summaryrefslogtreecommitdiffstats
path: root/cddl
diff options
context:
space:
mode:
authorsjg <sjg@FreeBSD.org>2014-04-27 08:13:43 +0000
committersjg <sjg@FreeBSD.org>2014-04-27 08:13:43 +0000
commit0c7e03a54c8e7ddc9c3fe710f83d9ca53173692e (patch)
treeb92e741b68057a24e381faa9809f32030d65574c /cddl
parentc244fcbcaa61dc2a15995e7dbdf3ae8107bc2111 (diff)
parent69c3e6933b6946c49fe99b19986f018d71621980 (diff)
downloadFreeBSD-src-0c7e03a54c8e7ddc9c3fe710f83d9ca53173692e.zip
FreeBSD-src-0c7e03a54c8e7ddc9c3fe710f83d9ca53173692e.tar.gz
Merge head
Diffstat (limited to 'cddl')
-rw-r--r--cddl/Makefile6
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d8
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh97
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh2
-rw-r--r--cddl/contrib/opensolaris/cmd/lockstat/lockstat.11178
-rw-r--r--cddl/contrib/opensolaris/cmd/lockstat/sym.c11
-rw-r--r--cddl/contrib/opensolaris/cmd/plockstat/plockstat.c3
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.826
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.c478
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb_il.c14
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs.8260
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c22
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h3
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_main.c426
-rw-r--r--cddl/contrib/opensolaris/cmd/zhack/zhack.c86
-rw-r--r--cddl/contrib/opensolaris/cmd/zinject/zinject.c1
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool-features.7157
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool.879
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_main.c165
-rw-r--r--cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.16
-rw-r--r--cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c121
-rw-r--r--cddl/contrib/opensolaris/cmd/ztest/ztest.c16
-rw-r--r--cddl/contrib/opensolaris/common/ctf/ctf_create.c2
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/drti.c88
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c22
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c4
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h5
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c126
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c12
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c27
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c5
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c10
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c138
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c2
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c1
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h13
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c193
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h4
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c26
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c62
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c67
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c58
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c11
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c114
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h32
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/kernel.c60
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h55
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/taskq.c101
-rw-r--r--cddl/contrib/opensolaris/lib/pyzfs/common/allow.py2
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c156
-rw-r--r--cddl/lib/Makefile7
-rw-r--r--cddl/lib/libctf/Makefile3
-rw-r--r--cddl/lib/libdtrace/Makefile2
-rw-r--r--cddl/lib/libdtrace/psinfo.d3
-rw-r--r--cddl/lib/libnvpair/Makefile9
-rw-r--r--cddl/lib/libzpool/Makefile2
-rw-r--r--cddl/lib/tests/Makefile10
-rw-r--r--cddl/sbin/Makefile6
-rw-r--r--cddl/sbin/tests/Makefile10
-rw-r--r--cddl/tests/Makefile10
-rw-r--r--cddl/usr.bin/Makefile5
-rw-r--r--cddl/usr.bin/sgsmsg/Makefile2
-rw-r--r--cddl/usr.bin/tests/Makefile10
-rw-r--r--cddl/usr.bin/zinject/Makefile3
-rw-r--r--cddl/usr.bin/zlook/Makefile2
-rw-r--r--cddl/usr.bin/ztest/Makefile2
-rw-r--r--cddl/usr.sbin/Makefile5
-rw-r--r--cddl/usr.sbin/lockstat/Makefile1
-rw-r--r--cddl/usr.sbin/tests/Makefile10
-rw-r--r--cddl/usr.sbin/zhack/Makefile2
79 files changed, 3126 insertions, 1563 deletions
diff --git a/cddl/Makefile b/cddl/Makefile
index 801d9cf..2a9b6f8 100644
--- a/cddl/Makefile
+++ b/cddl/Makefile
@@ -1,5 +1,11 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
SUBDIR= lib sbin usr.bin usr.sbin
+.if ${MK_TESTS} != "no"
+SUBDIR+=tests
+.endif
+
.include <bsd.subdir.mk>
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d
index 396a808..ca8ad44 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize1.d
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* ASSERTION:
* Checks that setting "bufresize" to "auto" will cause buffer
@@ -34,14 +32,8 @@
* SECTION: Buffers and Buffering/Buffer Resizing Policy;
* Options and Tunables/bufsize;
* Options and Tunables/bufresize
- *
- * NOTES:
- * We use the undocumented "preallocate" option to make sure dtrace(1M)
- * has enough space in its heap to allocate a buffer as large as the
- * kernel's trace buffer.
*/
-#pragma D option preallocate=100t
#pragma D option bufresize=auto
#pragma D option bufsize=100t
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d
index 50b814b..ddb97c8 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/buffering/tst.resize2.d
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* ASSERTION:
* Checks that setting "bufresize" to "auto" will cause buffer
@@ -34,14 +32,8 @@
* SECTION: Buffers and Buffering/Buffer Resizing Policy;
* Options and Tunables/aggsize;
* Options and Tunables/bufresize
- *
- * NOTES:
- * We use the undocumented "preallocate" option to make sure dtrace(1M)
- * has enough space in its heap to allocate a buffer as large as the
- * kernel's trace buffer.
*/
-#pragma D option preallocate=100t
#pragma D option bufresize=auto
#pragma D option aggsize=100t
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh
new file mode 100644
index 0000000..22c267d
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/misc/tst.dofmax.ksh
@@ -0,0 +1,97 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+let j=8
+
+enable()
+{
+ prog=/var/tmp/dtest.$$.d
+ err=/var/tmp/dtest.$$.err
+
+ nawk -v nprobes=$1 'BEGIN { \
+ for (i = 0; i < nprobes - 1; i++) { \
+ printf("dtrace:::BEGIN,\n"); \
+ } \
+ \
+ printf("dtrace:::BEGIN { exit(0); }\n"); \
+ }' /dev/null > $prog
+
+ dtrace -qs $prog > /dev/null 2> $err
+
+ if [[ "$?" -eq 0 ]]; then
+ return 0
+ else
+ if ! grep "DIF program exceeds maximum program size" $err \
+ 1> /dev/null 2>&1 ; then
+ echo "failed to enable $prog: `cat $err`"
+ exit 1
+ fi
+
+ return 1
+ fi
+}
+
+#
+# First, establish an upper bound
+#
+let upper=1
+
+while enable $upper ; do
+ let lower=upper
+ let upper=upper+upper
+ echo success at $lower, raised to $upper
+done
+
+#
+# Now search for the highest value that can be enabled
+#
+while [[ "$lower" -lt "$upper" ]]; do
+ let guess=$(((lower + upper) / 2))
+ echo "lower is $lower; upper is $upper; guess is $guess\c"
+
+ if enable $guess ; then
+ if [[ $((upper - lower)) -le 2 ]]; then
+ let upper=guess
+ fi
+
+ echo " (success)"
+ let lower=guess
+ else
+ echo " (failure)"
+ let upper=guess
+ fi
+done
+
+let expected=10000
+
+if [[ "$lower" -lt "$expected" ]]; then
+ echo "expected support for enablings of at least $expected probes; \c"
+ echo "found $lower"
+ exit 1
+fi
+
+echo "maximum supported enabled probes found to be $lower"
+exit 0
+
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d
index 8d4bb81..10dc61d 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d
@@ -44,7 +44,7 @@ BEGIN
printf("\n");
- printf("%%a = %a\n", &`kmem_alloc);
+ printf("%%a = %a\n", &`malloc);
printf("%%c = %c\n", i);
printf("%%d = %d\n", i);
printf("%%hd = %hd\n", (short)i);
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out
index 55c1222..1d27405 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out
@@ -1,5 +1,5 @@
-%a = genunix`kmem_alloc
+%a = kernel`malloc
%c = a
%d = 97
%hd = 97
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d
index a740413..67d7749 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d
@@ -36,6 +36,6 @@
BEGIN
{
- printf("sysname = %s", `utsname.sysname);
+ printf("sysname = %s", `ostype);
exit(0);
}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out
index ba31981..82d597b 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out
@@ -1 +1 @@
-sysname = SunOS
+sysname = FreeBSD
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d
index 32bc682..c2cf77d 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d
@@ -38,6 +38,6 @@
BEGIN
{
- printf("symbol = %a", &`kmem_alloc);
+ printf("symbol = %a", &`malloc);
exit(0);
}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out
index 5ed9d8e..7f645e1 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out
@@ -1 +1 @@
-symbol = kernel`kmem_alloc
+symbol = kernel`malloc
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh
index 69c0f84..d2afbed 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ufunc.ksh
@@ -64,7 +64,7 @@ child=$!
# ksh doing work. (This actually goes one step further and assumes that we
# catch some non-static function in ksh.)
#
-script | tee /dev/fd/2 | grep 'ksh`[a-zA-Z_]' > /dev/null
+script | tee /dev/fd/2 | egrep 'ksh(93)?`[a-zA-Z_]' > /dev/null
status=$?
kill $child
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh
index 6ca823f..8be34ec 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh
@@ -62,7 +62,7 @@ child=$!
#
# The only thing we can be sure of here is that ksh is doing some work.
#
-script | tee /dev/fd/2 | grep -w ksh > /dev/null
+script | tee /dev/fd/2 | egrep -w 'ksh(93)?' > /dev/null
status=$?
kill $child
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh
index b1a3ab9..8842d2b 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh
@@ -63,7 +63,7 @@ child=$!
# This test is essentially the same as that in the ufunc test; see that
# test for the rationale.
#
-script | tee /dev/fd/2 | grep 'ksh`[a-zA-Z_]' > /dev/null
+script | tee /dev/fd/2 | egrep 'ksh(93)?`[a-zA-Z_]' > /dev/null
status=$?
kill $child
diff --git a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1 b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1
index f3fc8e6..b634d45 100644
--- a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1
+++ b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1
@@ -2,7 +2,7 @@
.\" CDDL HEADER START
.\"
.\" The contents of this file are subject to the terms of the
-.\" Common Development and Distribution License (the "License").
+.\" Common Development and Distribution License (the "License").
.\" You may not use this file except in compliance with the License.
.\"
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
@@ -18,858 +18,382 @@
.\"
.\" CDDL HEADER END
.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved.
-.TH lockstat 1M "28 Feb 2008" "SunOS 5.11" "System Administration Commands"
-.SH NAME
-lockstat \- report kernel lock and profiling statistics
-.SH SYNOPSIS
-.LP
-.nf
-\fBlockstat\fR [\fB-ACEHI\fR] [\fB-e\fR \fIevent_list\fR] [\fB-i\fR \fIrate\fR]
- [\fB-b\fR | \fB-t\fR | \fB-h\fR | \fB-s\fR \fIdepth\fR] [\fB-n\fR \fInrecords\fR]
- [\fB-l\fR \fIlock\fR [, \fIsize\fR]] [\fB-d\fR \fIduration\fR]
- [\fB-f\fR \fIfunction\fR [, \fIsize\fR]] [\fB-T\fR] [\fB-ckgwWRpP\fR] [\fB-D\fR \fIcount\fR]
- [\fB-o\fR \fIfilename\fR] [\fB-x\fR \fIopt\fR [=val]] \fIcommand\fR [\fIargs\fR]
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-The \fBlockstat\fR utility gathers and displays kernel locking and profiling statistics. \fBlockstat\fR allows you to specify which events to watch (for example, spin on adaptive mutex, block on read access to rwlock due to waiting writers, and so forth) how much
-data to gather for each event, and how to display the data. By default, \fBlockstat\fR monitors all lock contention events, gathers frequency and timing data about those events, and displays the data in decreasing frequency order, so that the most common events appear first.
-.sp
-.LP
-\fBlockstat\fR gathers data until the specified command completes. For example, to gather statistics for a fixed-time interval, use \fBsleep\fR(1) as
-the command, as follows:
-.sp
-.LP
-\fBexample#\fR \fBlockstat\fR \fBsleep\fR \fB5\fR
-.sp
-.LP
-When the \fB-I\fR option is specified, \fBlockstat\fR establishes a per-processor high-level periodic interrupt source to gather profiling data. The interrupt handler simply generates a \fBlockstat\fR event whose caller is the interrupted PC (program counter).
-The profiling event is just like any other \fBlockstat\fR event, so all of the normal \fBlockstat\fR options are applicable.
-.sp
-.LP
-\fBlockstat\fR relies on DTrace to modify the running kernel's text to intercept events of interest. This imposes a small but measurable overhead on all system activity, so access to \fBlockstat\fR is restricted to super-user by default. The system administrator
-can permit other users to use \fBlockstat\fR by granting them additional DTrace privileges. Refer to the \fISolaris Dynamic Tracing Guide\fR for more information about DTrace security features.
-.SH OPTIONS
-.sp
-.LP
-The following options are supported:
-.SS "Event Selection"
-.sp
-.LP
-If no event selection options are specified, the default is \fB-C\fR.
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-A\fR\fR
-.ad
-.sp .6
-.RS 4n
-Watch all lock events. \fB-A\fR is equivalent to \fB-CH\fR.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-C\fR\fR
-.ad
-.sp .6
-.RS 4n
-Watch contention events.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-E\fR\fR
-.ad
-.sp .6
-.RS 4n
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 24, 2013
+.Dt LOCKSTAT 1
+.Os
+.Sh NAME
+.Nm lockstat
+.Nd report kernel lock and profiling statistics
+.Sh SYNOPSIS
+.Nm
+.Op Fl ACEHI
+.Op Fl e Ar event-list
+.Op Fl i Ar rate
+.Op Fl b | t | h | s Ar depth
+.Op Fl n Ar num-records
+.Op Fl l Ar lock Oo Ns , Ns Ar size Oc
+.Op Fl d Ar duration
+.Op Fl f Ar function Oo Ns , Ns Ar size Oc
+.Op Fl T
+.Op Fl ckgwWRpP
+.Op Fl D Ar count
+.Op Fl o filename
+.Op Fl x Ar opt Oo Ns = Ns Ar val Oc
+.Ar command
+.Op Oo Ar args Oc
+.Sh DESCRIPTION
+The
+.Nm
+utility gathers and displays kernel locking and profiling statistics.
+.Nm
+allows you to specify which events to watch (for example, spin on adaptive
+mutex, block on read access to rwlock due to waiting writers, and so forth), how
+much data to gather for each event, and how to display the data.
+By default,
+.Nm
+monitors all lock contention events, gathers frequency and timing data about
+those events, and displays the data in decreasing frequency order, so that the
+most common events appear first.
+.Pp
+.Nm
+gathers data until the specified command completes.
+For example, to gather statistics for a fixed-time interval, use
+.Xr sleep 1
+as the command, as follows:
+.Pp
+.Dl # lockstat sleep 5
+.Pp
+When the
+.Fl I
+option is specified,
+.Nm lockstat
+establishes a per-processor high-level periodic interrupt source to gather
+profiling data.
+The interrupt handler simply generates a
+.Nm
+event whose caller is the interrupted PC (program counter).
+The profiling event is just like any other
+.Nm lockstat
+event, so all of the normal
+.Nm lockstat
+options are applicable.
+.Pp
+.Nm
+relies on DTrace to modify the running kernel's text to intercept events of
+interest.
+This imposes a small but measurable overhead on all system activity, so access
+to
+.Nm
+is restricted to super-user by default.
+.Sh OPTIONS
+The following options are supported:
+.Ss Event Selection
+If no event selection options are specified, the default is
+.Fl C .
+.Bl -tag -width indent
+.It Fl A
+Watch all lock events.
+.Fl A
+is equivalent to
+.Fl CH .
+.It Fl C
+Watch contention events.
+.It Fl E
Watch error events.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-e\fR \fIevent_list\fR\fR
-.ad
-.sp .6
-.RS 4n
-Only watch the specified events. \fIevent\fR \fIlist\fR is a comma-separated list of events or ranges of events such as 1,4-7,35. Run \fBlockstat\fR with no arguments to get a brief description of all events.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-H\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl e Ar event-list
+Only watch the specified events.
+.Ar event-list
+is a comma-separated list of events or ranges of events such as 1,4-7,35.
+Run
+.Nm
+with no arguments to get a brief description of all events.
+.It Fl H
Watch hold events.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-I\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl I
Watch profiling interrupt events.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-i\fR \fIrate\fR\fR
-.ad
-.sp .6
-.RS 4n
-Interrupt rate (per second) for \fB-I\fR. The default is 97 Hz, so that profiling doesn't run in lockstep with the clock interrupt (which runs at 100 Hz).
-.RE
-
-.SS "Data Gathering"
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-x\fR \fIarg\fR[=\fIval\fR]\fR
-.ad
-.sp .6
-.RS 4n
-Enable or modify a DTrace runtime option or D compiler option. The list of options is found in the \fI\fR. Boolean options are enabled by specifying their name. Options with values are set by separating the option name and
-value with an equals sign (=).
-.RE
-
-.SS "Data Gathering (Mutually Exclusive)"
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-b\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl i Ar rate
+Interrupt rate (per second) for
+.Fl I .
+The default is 97 Hz, so that profiling doesn't run in lockstep with the clock
+interrupt (which runs at 100 Hz).
+.El
+.Ss Data Gathering
+.Bl -tag -width indent
+.It Fl x Ar arg Oo Ns = Ns Ar val Oc
+Enable or modify a
+.Xr dtrace 1
+runtime option or D compiler option.
+Boolean options are enabled by specifying their name.
+Options with values are set by separating the option name and value with an
+equals sign.
+.El
+.Ss "Data Gathering (Mutually Exclusive)"
+.Bl -tag -width indent
+.It Fl b
Basic statistics: lock, caller, number of events.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-h\fR\fR
-.ad
-.sp .6
-.RS 4n
-Histogram: Timing plus time-distribution histograms.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-s\fR \fIdepth\fR\fR
-.ad
-.sp .6
-.RS 4n
-Stack trace: Histogram plus stack traces up to \fIdepth\fR frames deep.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-t\fR\fR
-.ad
-.sp .6
-.RS 4n
-Timing: Basic plus timing for all events [default].
-.RE
-
-.SS "Data Filtering"
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-d\fR \fIduration\fR\fR
-.ad
-.sp .6
-.RS 4n
-Only watch events longer than \fIduration\fR.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-f\fR \fIfunc[,size]\fR\fR
-.ad
-.sp .6
-.RS 4n
-Only watch events generated by \fIfunc\fR, which can be specified as a symbolic name or hex address. \fIsize\fR defaults to the \fBELF\fR symbol size if available, or \fB1\fR if not.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-l\fR \fIlock[,size]\fR\fR
-.ad
-.sp .6
-.RS 4n
-Only watch \fIlock\fR, which can be specified as a symbolic name or hex address. \fBsize\fR defaults to the \fBELF\fR symbol size or \fB1\fR if the symbol size is not available.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-n\fR \fInrecords\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl h
+Histogram: timing plus time-distribution histograms.
+.It Fl s Ar depth
+Stack trace: histogram plus stack traces up to
+.Ar depth
+frames deep.
+.It Fl t
+Timing: Basic plus timing for all events (default).
+.El
+.Ss "Data Filtering"
+.Bl -tag -width indent
+.It Fl d Ar duration
+Only watch events longer than
+.Ar duration .
+.It Fl f Ar func Ns Oo Ns , Ns Ar size Oc Ns
+Only watch events generated by
+.Ar func ,
+which can be specified as a symbolic name or hex address.
+.Ar size
+defaults to the ELF symbol size if available, or 1 if not.
+.It Fl l Ar lock Ns Oo Ns , Ns Ar size Oc Ns
+Only watch
+.Ar lock ,
+which can be specified as a symbolic name or hex address.
+.Ar size
+defaults to the ELF symbol size or 1 if the symbol size is not available.
+.It Fl n Ar num-records
Maximum number of data records.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-T\fR\fR
-.ad
-.sp .6
-.RS 4n
-Trace (rather than sample) events [off by default].
-.RE
-
-.SS "Data Reporting"
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-c\fR\fR
-.ad
-.sp .6
-.RS 4n
-Coalesce lock data for lock arrays (for example, \fBpse_mutex[]\fR).
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-D\fR \fIcount\fR\fR
-.ad
-.sp .6
-.RS 4n
-Only display the top \fIcount\fR events of each type.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-g\fR\fR
-.ad
-.sp .6
-.RS 4n
-Show total events generated by function. For example, if \fBfoo()\fR calls \fBbar()\fR in a loop, the work done by \fBbar()\fR counts as work generated by \fBfoo()\fR (along with any work done by \fBfoo()\fR itself).
-The \fB-g\fR option works by counting the total number of stack frames in which each function appears. This implies two things: (1) the data reported by \fB-g\fR can be misleading if the stack traces are not deep enough, and (2) functions that are called recursively might show
-greater than 100% activity. In light of issue (1), the default data gathering mode when using \fB-g\fR is \fB-s\fR \fB50\fR.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-k\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl T
+Trace (rather than sample) events.
+This is off by default.
+.El
+.Ss Data Reporting
+.Bl -tag -width indent
+.It Fl c
+Coalesce lock data for lock arrays.
+.It Fl D Ar count
+Only display the top
+.Ar count
+events of each type.
+.It Fl g
+Show total events generated by function.
+For example, if
+.Fn foo
+calls
+.Fn bar
+in a loop, the work done by
+.Fn bar
+counts as work generated by
+.Fn foo
+(along with any work done by
+.Fn foo
+itself).
+The
+.Fl g
+option works by counting the total number of stack frames in which each function
+appears.
+This implies two things: (1) the data reported by
+.Fl g
+can be misleading if the stack traces are not deep enough, and (2) functions
+that are called recursively might show greater than 100% activity.
+In light of issue (1), the default data gathering mode when using
+.Fl g
+is
+.Fl s 50 .
+.It Fl k
Coalesce PCs within functions.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB\fR\fB-o\fR \fIfilename\fR\fR
-.ad
-.sp .6
-.RS 4n
-Direct output to \fIfilename\fR.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-P\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl o Ar filename
+Direct output to
+.Ar filename .
+.It Fl P
Sort data by (\fIcount * time\fR) product.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-p\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl p
Parsable output format.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-R\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl R
Display rates (events per second) rather than counts.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-W\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl W
Whichever: distinguish events only by caller, not by lock.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fB-w\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Fl w
Wherever: distinguish events only by lock, not by caller.
-.RE
-
-.SH DISPLAY FORMATS
-.sp
-.LP
+.El
+.Sh DISPLAY FORMATS
The following headers appear over various columns of data.
-.sp
-.ne 2
-.mk
-.na
-\fB\fBCount\fR or \fBops/s\fR\fR
-.ad
-.sp .6
-.RS 4n
-Number of times this event occurred, or the rate (times per second) if \fB-R\fR was specified.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBindv\fR\fR
-.ad
-.sp .6
-.RS 4n
+.Bl -tag -width indent
+.It Count or ops/s
+Number of times this event occurred, or the rate (times per second) if
+.Fl R
+was specified.
+.It indv
Percentage of all events represented by this individual event.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBgenr\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It genr
Percentage of all events generated by this function.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBcuml\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It cuml
Cumulative percentage; a running total of the individuals.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBrcnt\fR\fR
-.ad
-.sp .6
-.RS 4n
-Average reference count. This will always be \fB1\fR for exclusive locks (mutexes, spin locks, rwlocks held as writer) but can be greater than \fB1\fR for shared locks (rwlocks held as reader).
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBnsec\fR\fR
-.ad
-.sp .6
-.RS 4n
-Average duration of the events in nanoseconds, as appropriate for the event. For the profiling event, duration means interrupt latency.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBLock\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It rcnt
+Average reference count.
+This will always be 1 for exclusive locks (mutexes,
+spin locks, rwlocks held as writer) but can be greater than 1 for shared locks
+(rwlocks held as reader).
+.It nsec
+Average duration of the events in nanoseconds, as appropriate for the event.
+For the profiling event, duration means interrupt latency.
+.It Lock
Address of the lock; displayed symbolically if possible.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBCPU+PIL\fR\fR
-.ad
-.sp .6
-.RS 4n
-\fBCPU\fR plus processor interrupt level (\fBPIL\fR). For example, if \fBCPU\fR 4 is interrupted while at \fBPIL\fR 6, this will be reported as \fBcpu[4]+6\fR.
-.RE
-
-.sp
-.ne 2
-.mk
-.na
-\fB\fBCaller\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It CPU+PIL
+CPU plus processor interrupt level (PIL).
+For example, if CPU 4 is interrupted while at PIL 6, this will be reported as
+cpu[4]+6.
+.It Caller
Address of the caller; displayed symbolically if possible.
-.RE
-
-.SH EXAMPLES
-.LP
-\fBExample 1 \fRMeasuring Kernel Lock Contention
-.sp
-.in +2
-.nf
-example# \fBlockstat sleep 5\fR
-Adaptive mutex spin: 2210 events in 5.055 seconds (437 events/sec)
-.fi
-.in -2
-.sp
-
-.sp
-.in +2
-.nf
-Count indv cuml rcnt nsec Lock Caller
-------------------------------------------------------------------------
- 269 12% 12% 1.00 2160 service_queue background+0xdc
- 249 11% 23% 1.00 86 service_queue qenable_locked+0x64
- 228 10% 34% 1.00 131 service_queue background+0x15c
- 68 3% 37% 1.00 79 0x30000024070 untimeout+0x1c
- 59 3% 40% 1.00 384 0x300066fa8e0 background+0xb0
- 43 2% 41% 1.00 30 rqcred_lock svc_getreq+0x3c
- 42 2% 43% 1.00 341 0x30006834eb8 background+0xb0
- 41 2% 45% 1.00 135 0x30000021058 untimeout+0x1c
- 40 2% 47% 1.00 39 rqcred_lock svc_getreq+0x260
- 37 2% 49% 1.00 2372 0x300068e83d0 hmestart+0x1c4
- 36 2% 50% 1.00 77 0x30000021058 timeout_common+0x4
- 36 2% 52% 1.00 354 0x300066fa120 background+0xb0
- 32 1% 53% 1.00 97 0x30000024070 timeout_common+0x4
- 31 1% 55% 1.00 2923 0x300069883d0 hmestart+0x1c4
- 29 1% 56% 1.00 366 0x300066fb290 background+0xb0
- 28 1% 57% 1.00 117 0x3000001e040 untimeout+0x1c
- 25 1% 59% 1.00 93 0x3000001e040 timeout_common+0x4
- 22 1% 60% 1.00 25 0x30005161110 sync_stream_buf+0xdc
- 21 1% 60% 1.00 291 0x30006834eb8 putq+0xa4
- 19 1% 61% 1.00 43 0x3000515dcb0 mdf_alloc+0xc
- 18 1% 62% 1.00 456 0x30006834eb8 qenable+0x8
- 18 1% 63% 1.00 61 service_queue queuerun+0x168
- 17 1% 64% 1.00 268 0x30005418ee8 vmem_free+0x3c
-[...]
-
-R/W reader blocked by writer: 76 events in 5.055 seconds (15 events/sec)
+.El
+.Sh EXAMPLES
+.Bl -tag -width 0n
+.It Example 1 Measuring Kernel Lock Contention
+.Pp
+.Li # lockstat sleep 5
+.Bd -literal
+Adaptive mutex spin: 41411 events in 5.011 seconds (8263 events/sec)
-Count indv cuml rcnt nsec Lock Caller
-------------------------------------------------------------------------
- 23 30% 30% 1.00 22590137 0x300098ba358 ufs_dirlook+0xd0
- 17 22% 53% 1.00 5820995 0x3000ad815e8 find_bp+0x10
- 13 17% 70% 1.00 2639918 0x300098ba360 ufs_iget+0x198
- 4 5% 75% 1.00 3193015 0x300098ba360 ufs_getattr+0x54
- 3 4% 79% 1.00 7953418 0x3000ad817c0 find_bp+0x10
- 3 4% 83% 1.00 935211 0x3000ad815e8 find_read_lof+0x14
- 2 3% 86% 1.00 16357310 0x300073a4720 find_bp+0x10
- 2 3% 88% 1.00 2072433 0x300073a4720 find_read_lof+0x14
- 2 3% 91% 1.00 1606153 0x300073a4370 find_bp+0x10
- 1 1% 92% 1.00 2656909 0x300107e7400 ufs_iget+0x198
-[...]
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 2 \fRMeasuring Hold Times
-.sp
-.in +2
-.nf
-example# \fBlockstat -H -D 10 sleep 1\fR
-Adaptive mutex spin: 513 events
-.fi
-.in -2
-.sp
-
-.sp
-.in +2
-.nf
-Count indv cuml rcnt nsec Lock Caller
--------------------------------------------------------------------------
- 480 5% 5% 1.00 1136 0x300007718e8 putnext+0x40
- 286 3% 9% 1.00 666 0x3000077b430 getf+0xd8
- 271 3% 12% 1.00 537 0x3000077b430 msgio32+0x2fc
- 270 3% 15% 1.00 3670 0x300007718e8 strgetmsg+0x3d4
- 270 3% 18% 1.00 1016 0x300007c38b0 getq_noenab+0x200
- 264 3% 20% 1.00 1649 0x300007718e8 strgetmsg+0xa70
- 216 2% 23% 1.00 6251 tcp_mi_lock tcp_snmp_get+0xfc
- 206 2% 25% 1.00 602 thread_free_lock clock+0x250
- 138 2% 27% 1.00 485 0x300007c3998 putnext+0xb8
- 138 2% 28% 1.00 3706 0x300007718e8 strrput+0x5b8
--------------------------------------------------------------------------
+Count indv cuml rcnt nsec Lock Caller
+-------------------------------------------------------------------------------
+13750 33% 33% 0.00 72 vm_page_queue_free_mtx vm_page_free_toq+0x12e
+13648 33% 66% 0.00 66 vm_page_queue_free_mtx vm_page_alloc+0x138
+ 4023 10% 76% 0.00 51 vm_dom+0x80 vm_page_dequeue+0x68
+ 2672 6% 82% 0.00 186 vm_dom+0x80 vm_page_enqueue+0x63
+ 618 1% 84% 0.00 31 0xfffff8000cd83a88 qsyncvp+0x37
+ 506 1% 85% 0.00 164 0xfffff8000cb3f098 vputx+0x5a
+ 477 1% 86% 0.00 69 0xfffff8000c7eb180 uma_dbg_getslab+0x5b
+ 288 1% 87% 0.00 77 0xfffff8000cd8b000 vn_finished_write+0x29
+ 263 1% 88% 0.00 103 0xfffff8000cbad448 vinactive+0xdc
+ 259 1% 88% 0.00 53 0xfffff8000cd8b000 vfs_ref+0x24
+ 237 1% 89% 0.00 20 0xfffff8000cbad448 vfs_hash_get+0xcc
+ 233 1% 89% 0.00 22 0xfffff8000bfd9480 uma_dbg_getslab+0x5b
+ 223 1% 90% 0.00 20 0xfffff8000cb3f098 cache_lookup+0x561
+ 193 0% 90% 0.00 16 0xfffff8000cb40ba8 vref+0x27
+ 175 0% 91% 0.00 34 0xfffff8000cbad448 vputx+0x5a
+ 169 0% 91% 0.00 51 0xfffff8000cd8b000 vfs_unbusy+0x27
+ 164 0% 92% 0.00 31 0xfffff8000cb40ba8 vputx+0x5a
[...]
-.fi
-.in -2
-.sp
-.LP
-\fBExample 3 \fRMeasuring Hold Times for Stack Traces Containing a Specific Function
-.sp
-.in +2
-.nf
-example# \fBlockstat -H -f tcp_rput_data -s 50 -D 10 sleep 1\fR
-Adaptive mutex spin: 11 events in 1.023 seconds (11
-events/sec)
-.fi
-.in -2
-.sp
+Adaptive mutex block: 10 events in 5.011 seconds (2 events/sec)
-.sp
-.in +2
-.nf
--------------------------------------------------------------------------
Count indv cuml rcnt nsec Lock Caller
- 9 82% 82% 1.00 2540 0x30000031380 tcp_rput_data+0x2b90
-
- nsec ------ Time Distribution ------ count Stack
- 256 |@@@@@@@@@@@@@@@@ 5 tcp_rput_data+0x2b90
- 512 |@@@@@@ 2 putnext+0x78
- 1024 |@@@ 1 ip_rput+0xec4
- 2048 | 0 _c_putnext+0x148
- 4096 | 0 hmeread+0x31c
- 8192 | 0 hmeintr+0x36c
- 16384 |@@@ 1
-sbus_intr_wrapper+0x30
+-------------------------------------------------------------------------------
+ 3 30% 30% 0.00 17592 vm_page_queue_free_mtx vm_page_alloc+0x138
+ 2 20% 50% 0.00 20528 vm_dom+0x80 vm_page_enqueue+0x63
+ 2 20% 70% 0.00 55502 0xfffff8000cb40ba8 vputx+0x5a
+ 1 10% 80% 0.00 12007 vm_page_queue_free_mtx vm_page_free_toq+0x12e
+ 1 10% 90% 0.00 9125 0xfffff8000cbad448 vfs_hash_get+0xcc
+ 1 10% 100% 0.00 7864 0xfffff8000cd83a88 qsyncvp+0x37
+-------------------------------------------------------------------------------
[...]
+.Ed
+.It Example 2 Measuring Hold Times
+.Pp
+.Li # lockstat -H -D 10 sleep 1
+.Bd -literal
+Adaptive mutex hold: 109589 events in 1.039 seconds (105526 events/sec)
Count indv cuml rcnt nsec Lock Caller
- 1 9% 91% 1.00 1036 0x30000055380 freemsg+0x44
-
- nsec ------ Time Distribution ------ count Stack
- 1024 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1 freemsg+0x44
- tcp_rput_data+0x2fd0
- putnext+0x78
- ip_rput+0xec4
- _c_putnext+0x148
- hmeread+0x31c
- hmeintr+0x36c
-
-sbus_intr_wrapper+0x30
--------------------------------------------------------------------------
-[...]
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 4 \fRBasic Kernel Profiling
-.sp
-.LP
-For basic profiling, we don't care whether the profiling interrupt sampled \fBfoo()\fR\fB+0x4c\fR or \fBfoo()\fR\fB+0x78\fR; we care only that it sampled somewhere in \fBfoo()\fR, so we use \fB-k\fR. The \fBCPU\fR and \fBPIL\fR aren't relevant to basic profiling because we are measuring the system as a whole, not a particular \fBCPU\fR or interrupt level, so we use \fB-W\fR.
-
-.sp
-.in +2
-.nf
-example# \fBlockstat -kIW -D 20 ./polltest\fR
-Profiling interrupt: 82 events in 0.424 seconds (194
-events/sec)
-.fi
-.in -2
-.sp
-
-.sp
-.in +2
-.nf
-Count indv cuml rcnt nsec Hottest CPU+PIL Caller
------------------------------------------------------------------------
- 8 10% 10% 1.00 698 cpu[1] utl0
- 6 7% 17% 1.00 299 cpu[0] read
- 5 6% 23% 1.00 124 cpu[1] getf
- 4 5% 28% 1.00 327 cpu[0] fifo_read
- 4 5% 33% 1.00 112 cpu[1] poll
- 4 5% 38% 1.00 212 cpu[1] uiomove
- 4 5% 43% 1.00 361 cpu[1] mutex_tryenter
- 3 4% 46% 1.00 682 cpu[0] write
- 3 4% 50% 1.00 89 cpu[0] pcache_poll
- 3 4% 54% 1.00 118 cpu[1] set_active_fd
- 3 4% 57% 1.00 105 cpu[0] syscall_trap32
- 3 4% 61% 1.00 640 cpu[1] (usermode)
- 2 2% 63% 1.00 127 cpu[1] fifo_poll
- 2 2% 66% 1.00 300 cpu[1] fifo_write
- 2 2% 68% 1.00 669 cpu[0] releasef
- 2 2% 71% 1.00 112 cpu[1] bt_getlowbit
- 2 2% 73% 1.00 247 cpu[1] splx
- 2 2% 76% 1.00 503 cpu[0] mutex_enter
- 2 2% 78% 1.00 467 cpu[0]+10 disp_lock_enter
- 2 2% 80% 1.00 139 cpu[1] default_copyin
------------------------------------------------------------------------
-[...]
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 5 \fRGenerated-load Profiling
-.sp
-.LP
-In the example above, 5% of the samples were in \fBpoll()\fR. This tells us how much time was spent inside \fBpoll()\fR itself, but tells us nothing about how much work was \fBgenerated\fR by \fBpoll()\fR; that is, how much time we spent
-in functions called by \fBpoll()\fR. To determine that, we use the \fB-g\fR option. The example below shows that although \fBpolltest\fR spends only 5% of its time in \fBpoll()\fR itself, \fBpoll()\fR-induced work accounts for 34% of
-the load.
-
-.sp
-.LP
-Note that the functions that generate the profiling interrupt (\fBlockstat_intr()\fR, \fBcyclic_fire()\fR, and so forth) appear in every stack trace, and therefore are considered to have generated 100% of the load. This illustrates an important point: the generated
-load percentages do \fBnot\fR add up to 100% because they are not independent. If 72% of all stack traces contain both \fBfoo()\fR and \fBbar()\fR, then both \fBfoo()\fR and \fBbar()\fR are 72% load generators.
-
-.sp
-.in +2
-.nf
-example# \fBlockstat -kgIW -D 20 ./polltest\fR
-Profiling interrupt: 80 events in 0.412 seconds (194 events/sec)
-.fi
-.in -2
-.sp
-
-.sp
-.in +2
-.nf
-Count genr cuml rcnt nsec Hottest CPU+PIL Caller
--------------------------------------------------------------------------
- 80 100% ---- 1.00 310 cpu[1] lockstat_intr
- 80 100% ---- 1.00 310 cpu[1] cyclic_fire
- 80 100% ---- 1.00 310 cpu[1] cbe_level14
- 80 100% ---- 1.00 310 cpu[1] current_thread
- 27 34% ---- 1.00 176 cpu[1] poll
- 20 25% ---- 1.00 221 cpu[0] write
- 19 24% ---- 1.00 249 cpu[1] read
- 17 21% ---- 1.00 232 cpu[0] write32
- 17 21% ---- 1.00 207 cpu[1] pcache_poll
- 14 18% ---- 1.00 319 cpu[0] fifo_write
- 13 16% ---- 1.00 214 cpu[1] read32
- 10 12% ---- 1.00 208 cpu[1] fifo_read
- 10 12% ---- 1.00 787 cpu[1] utl0
- 9 11% ---- 1.00 178 cpu[0] pcacheset_resolve
- 9 11% ---- 1.00 262 cpu[0] uiomove
- 7 9% ---- 1.00 506 cpu[1] (usermode)
- 5 6% ---- 1.00 195 cpu[1] fifo_poll
- 5 6% ---- 1.00 136 cpu[1] syscall_trap32
- 4 5% ---- 1.00 139 cpu[0] releasef
- 3 4% ---- 1.00 277 cpu[1] polllock
--------------------------------------------------------------------------
-[...]
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 6 \fRGathering Lock Contention and Profiling Data for a Specific Module
-.sp
-.LP
-In this example we use the \fB-f\fR option not to specify a single function, but rather to specify the entire text space of the \fBsbus\fR module. We gather both lock contention and profiling statistics so that contention can be correlated with overall load on the
-module.
-
-.sp
-.in +2
-.nf
-example# \fBmodinfo | grep sbus\fR
-24 102a8b6f b8b4 59 1 sbus (SBus (sysio) nexus driver)
-.fi
-.in -2
-.sp
-
-.sp
-.in +2
-.nf
-example# \fBlockstat -kICE -f 0x102a8b6f,0xb8b4 sleep 10\fR
-Adaptive mutex spin: 39 events in 10.042 seconds (4 events/sec)
-.fi
-.in -2
-.sp
-
-.sp
-.in +2
-.nf
-Count indv cuml rcnt nsec Lock Caller
--------------------------------------------------------------------------
- 15 38% 38% 1.00 206 0x30005160528 sync_stream_buf
- 7 18% 56% 1.00 14 0x30005160d18 sync_stream_buf
- 6 15% 72% 1.00 27 0x300060c3118 sync_stream_buf
- 5 13% 85% 1.00 24 0x300060c3510 sync_stream_buf
- 2 5% 90% 1.00 29 0x300060c2d20 sync_stream_buf
- 2 5% 95% 1.00 24 0x30005161cf8 sync_stream_buf
- 1 3% 97% 1.00 21 0x30005161110 sync_stream_buf
- 1 3% 100% 1.00 23 0x30005160130 sync_stream_buf
+-------------------------------------------------------------------------------
+ 8998 8% 8% 0.00 617 0xfffff8000c7eb180 uma_dbg_getslab+0xd4
+ 5901 5% 14% 0.00 917 vm_page_queue_free_mtx vm_object_terminate+0x16a
+ 5040 5% 18% 0.00 902 vm_dom+0x80 vm_page_free_toq+0x88
+ 4884 4% 23% 0.00 1056 vm_page_queue_free_mtx vm_page_alloc+0x44e
+ 4664 4% 27% 0.00 759 vm_dom+0x80 vm_fault_hold+0x1a13
+ 4011 4% 31% 0.00 888 vm_dom vm_page_advise+0x11b
+ 4010 4% 34% 0.00 957 vm_dom+0x80 _vm_page_deactivate+0x5c
+ 3743 3% 38% 0.00 582 0xfffff8000cf04838 pmap_is_prefaultable+0x158
+ 2254 2% 40% 0.00 952 vm_dom vm_page_free_toq+0x88
+ 1639 1% 41% 0.00 591 0xfffff800d60065b8 trap_pfault+0x1f7
+-------------------------------------------------------------------------------
[...]
-Adaptive mutex block: 9 events in 10.042 seconds (1 events/sec)
+R/W writer hold: 64314 events in 1.039 seconds (61929 events/sec)
-Count indv cuml rcnt nsec Lock Caller
--------------------------------------------------------------------------
- 4 44% 44% 1.00 156539 0x30005160528 sync_stream_buf
- 2 22% 67% 1.00 763516 0x30005160d18 sync_stream_buf
- 1 11% 78% 1.00 462130 0x300060c3510 sync_stream_buf
- 1 11% 89% 1.00 288749 0x30005161110 sync_stream_buf
- 1 11% 100% 1.00 1015374 0x30005160130 sync_stream_buf
-[...]
-
-Profiling interrupt: 229 events in 10.042 seconds (23 events/sec)
-
-Count indv cuml rcnt nsec Hottest CPU+PIL Caller
-
--------------------------------------------------------------------------
- 89 39% 39% 1.00 426 cpu[0]+6 sync_stream_buf
- 64 28% 67% 1.00 398 cpu[0]+6 sbus_intr_wrapper
- 23 10% 77% 1.00 324 cpu[0]+6 iommu_dvma_kaddr_load
- 21 9% 86% 1.00 512 cpu[0]+6 iommu_tlb_flush
- 14 6% 92% 1.00 342 cpu[0]+6 iommu_dvma_unload
- 13 6% 98% 1.00 306 cpu[1] iommu_dvma_sync
- 5 2% 100% 1.00 389 cpu[1] iommu_dma_bindhdl
--------------------------------------------------------------------------
-[...]
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 7 \fRDetermining the Average PIL (processor interrupt level) for a CPU
-.sp
-.in +2
-.nf
-example# \fBlockstat -Iw -l cpu[3] ./testprog\fR
-
-Profiling interrupt: 14791 events in 152.463 seconds (97 events/sec)
-
-Count indv cuml rcnt nsec CPU+PIL Hottest Caller
-
------------------------------------------------------------------------
-13641 92% 92% 1.00 253 cpu[3] (usermode)
- 579 4% 96% 1.00 325 cpu[3]+6 ip_ocsum+0xe8
- 375 3% 99% 1.00 411 cpu[3]+10 splx
- 154 1% 100% 1.00 527 cpu[3]+4 fas_intr_svc+0x80
- 41 0% 100% 1.00 293 cpu[3]+13 send_mondo+0x18
- 1 0% 100% 1.00 266 cpu[3]+12 zsa_rxint+0x400
------------------------------------------------------------------------
-[...]
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 8 \fRDetermining which Subsystem is Causing the System to be Busy
-.sp
-.in +2
-.nf
-example# \fBlockstat -s 10 -I sleep 20\fR
-
-Profiling interrupt: 4863 events in 47.375 seconds (103 events/sec)
-
-Count indv cuml rcnt nsec CPU+PIL Caller
-
------------------------------------------------------------------------
-1929 40% 40% 0.00 3215 cpu[0] usec_delay+0x78
- nsec ------ Time Distribution ------ count Stack
- 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1872 ata_wait+0x90
- 8192 | 27 acersb_get_intr_status+0x34
-16384 | 29 ata_set_feature+0x124
-32768 | 1 ata_disk_start+0x15c
- ata_hba_start+0xbc
- ghd_waitq_process_and \e
- _mutex_hold+0x70
- ghd_waitq_process_and \e
- _mutex_exit+0x4
- ghd_transport+0x12c
- ata_disk_tran_start+0x108
------------------------------------------------------------------------
+Count indv cuml rcnt nsec Lock Caller
+-------------------------------------------------------------------------------
+ 7421 12% 12% 0.00 2994 pvh_global_lock pmap_page_is_mapped+0xb6
+ 4668 7% 19% 0.00 3313 pvh_global_lock pmap_enter+0x9ae
+ 1639 3% 21% 0.00 733 0xfffff80168d10200 vm_object_deallocate+0x683
+ 1639 3% 24% 0.00 3061 0xfffff80168d10200 unlock_and_deallocate+0x2b
+ 1639 3% 26% 0.00 2966 0xfffff80168d10200 vm_fault_hold+0x16ee
+ 1567 2% 29% 0.00 733 0xfffff80168d10200 vm_fault_hold+0x19bc
+ 821 1% 30% 0.00 786 0xfffff801eb0cc000 vm_object_madvise+0x32d
+ 649 1% 31% 0.00 4918 0xfffff80191105300 vm_fault_hold+0x16ee
+ 648 1% 32% 0.00 8112 0xfffff80191105300 unlock_and_deallocate+0x2b
+ 647 1% 33% 0.00 1261 0xfffff80191105300 vm_object_deallocate+0x683
+-------------------------------------------------------------------------------
+.Ed
+.It Example 3 Measuring Hold Times for Stack Traces Containing a Specific Function
+.Pp
+.Li # lockstat -H -f tcp_input -s 50 -D 10 sleep 1
+.Bd -literal
+Adaptive mutex hold: 68 events in 1.026 seconds (66 events/sec)
+
+-------------------------------------------------------------------------------
+Count indv cuml rcnt nsec Lock Caller
+ 32 47% 47% 0.00 1631 0xfffff800686f50d8 tcp_do_segment+0x284b
+
+ nsec ------ Time Distribution ------ count Stack
+ 1024 |@@@@@@@@@@ 11 tcp_input+0xf54
+ 2048 |@@@@@@@@@@@@@ 14 ip_input+0xc8
+ 4096 |@@@@@ 6 swi_net+0x192
+ 8192 | 1 intr_event_execute_handlers+0x93
+ ithread_loop+0xa6
+ fork_exit+0x84
+ 0xffffffff808cf9ee
+-------------------------------------------------------------------------------
+Count indv cuml rcnt nsec Lock Caller
+ 29 43% 90% 0.00 4851 0xfffff800686f50d8 sowakeup+0xf8
+
+ nsec ------ Time Distribution ------ count Stack
+ 4096 |@@@@@@@@@@@@@@@ 15 tcp_do_segment+0x2423
+ 8192 |@@@@@@@@@@@@ 12 tcp_input+0xf54
+ 16384 |@@ 2 ip_input+0xc8
+ swi_net+0x192
+ intr_event_execute_handlers+0x93
+ ithread_loop+0xa6
+ fork_exit+0x84
+ 0xffffffff808cf9ee
+-------------------------------------------------------------------------------
[...]
-.fi
-.in -2
-.sp
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(5) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-tab() box;
-cw(2.75i) |cw(2.75i)
-lw(2.75i) |lw(2.75i)
-.
-ATTRIBUTE TYPEATTRIBUTE VALUE
-_
-AvailabilitySUNWdtrc
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-\fBdtrace\fR(1M), \fBplockstat\fR(1M), \fBattributes\fR(5), \fBlockstat\fR(7D), \fBmutex\fR(9F), \fBrwlock\fR(9F)
-.sp
-.LP
-\fISolaris Dynamic Tracing Guide\fR
-.SH NOTES
-.sp
-.LP
-The profiling support provided by \fBlockstat\fR \fB-I\fR replaces the old (and undocumented) \fB/usr/bin/kgmon\fR and \fB/dev/profile\fR.
-.sp
-.LP
-Tail-call elimination can affect call sites. For example, if \fBfoo()\fR\fB+0x50\fR calls \fBbar()\fR and the last thing \fBbar()\fR does is call \fBmutex_exit()\fR, the compiler can arrange for \fBbar()\fR to
-branch to \fBmutex_exit()\fRwith a return address of \fBfoo()\fR\fB+0x58\fR. Thus, the \fBmutex_exit()\fR in \fBbar()\fR will appear as though it occurred at \fBfoo()\fR\fB+0x58\fR.
-.sp
-.LP
-The \fBPC\fR in the stack frame in which an interrupt occurs can be bogus because, between function calls, the compiler is free to use the return address register for local storage.
-.sp
-.LP
-When using the \fB-I\fR and \fB-s\fR options together, the interrupted PC will usually not appear anywhere in the stack since the interrupt handler is entered asynchronously, not by a function call from that \fBPC\fR.
-.sp
-.LP
-The \fBlockstat\fR technology is provided on an as-is basis. The format and content of \fBlockstat\fR output reflect the current Solaris kernel implementation and are therefore subject to change in future releases.
+.Ed
+.El
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr ksyms 4 ,
+.Xr locking 9
+.Sh NOTES
+Tail-call elimination can affect call sites.
+For example, if
+.Fn foo Ns +0x50
+calls
+.Fn bar
+and the last thing
+.Fn bar
+does is call
+.Fn mtx_unlock ,
+the compiler can arrange for
+.Fn bar
+to branch to
+.Fn mtx_unlock
+with a return address of
+.Fn foo Ns +0x58.
+Thus, the
+.Fn mtx_unlock
+in
+.Fn bar
+will appear as though it occurred at
+.Fn foo Ns +0x58.
+.Pp
+The PC in the stack frame in which an interrupt occurs can be bogus because,
+between function calls, the compiler is free to use the return address register
+for local storage.
+.Pp
+When using the
+.Fl I
+and
+.Fl s
+options together, the interrupted PC will usually not appear anywhere in the
+stack since the interrupt handler is entered asynchronously, not by a function
+call from that PC.
diff --git a/cddl/contrib/opensolaris/cmd/lockstat/sym.c b/cddl/contrib/opensolaris/cmd/lockstat/sym.c
index 78b27d2..1aa77ad 100644
--- a/cddl/contrib/opensolaris/cmd/lockstat/sym.c
+++ b/cddl/contrib/opensolaris/cmd/lockstat/sym.c
@@ -179,8 +179,19 @@ symtab_init(void)
size_t sz;
#endif
+#if defined(__FreeBSD__)
+ if ((fd = open("/dev/ksyms", O_RDONLY)) == -1) {
+ if (errno == ENOENT && modfind("ksyms") == -1) {
+ kldload("ksyms");
+ fd = open("/dev/ksyms", O_RDONLY);
+ }
+ if (fd == -1)
+ return (-1);
+ }
+#else
if ((fd = open("/dev/ksyms", O_RDONLY)) == -1)
return (-1);
+#endif
#if defined(sun)
(void) elf_version(EV_CURRENT);
diff --git a/cddl/contrib/opensolaris/cmd/plockstat/plockstat.c b/cddl/contrib/opensolaris/cmd/plockstat/plockstat.c
index aa2c1f9..1288468 100644
--- a/cddl/contrib/opensolaris/cmd/plockstat/plockstat.c
+++ b/cddl/contrib/opensolaris/cmd/plockstat/plockstat.c
@@ -778,7 +778,8 @@ main(int argc, char **argv)
#endif
int err;
int opt_C = 0, opt_H = 0, opt_p = 0, opt_v = 0;
- char c, *p, *end;
+ int c;
+ char *p, *end;
struct sigaction act;
int done = 0;
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.8 b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
index e036b96..e59f370 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb.8
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
@@ -14,11 +14,12 @@
.\"
.\" Copyright 2012, Richard Lowe.
.\" Copyright (c) 2012, Marcelo Araujo <araujo@FreeBSD.org>.
+.\" Copyright (c) 2012 by Delphix. All rights reserved.
.\" All Rights Reserved.
.\"
.\" $FreeBSD$
.\"
-.Dd May 10, 2012
+.Dd March 20, 2014
.Dt ZDB 8
.Os
.Sh NAME
@@ -29,27 +30,35 @@
.Op Fl CumdibcsDvhLXFPA
.Op Fl e Op Fl p Ar path...
.Op Fl t Ar txg
+.Op Fl U Ar cache
+.Op Fl M Ar inflight I/Os
.Ar poolname
.Op Ar object ...
.Nm
.Op Fl divPA
.Op Fl e Op Fl p Ar path...
+.Op Fl U Ar cache
.Ar dataset
.Op Ar object ...
.Nm
.Fl m Op Fl LXFPA
.Op Fl t Ar txg
.Op Fl e Op Fl p Ar path...
+.Op Fl U Ar cache
.Ar poolname
.Nm
.Fl R Op Fl A
.Op Fl e Op Fl p Ar path...
+.Op Fl U Ar cache
+.Ar poolname
.Ar poolname
.Ar vdev Ns : Ns Ar offset Ns : Ns Ar size Ns Op Ns : Ns Ar flags
.Nm
.Fl S
.Op Fl AP
.Op Fl e Op Fl p Ar path...
+.Op Fl U Ar cache
+.Ar poolname
.Ar poolname
.Nm
.Fl l
@@ -118,6 +127,12 @@ compression ratio (compress), inflation due to the zfs copies property
If specified twice, display a histogram of deduplication statistics, showing
the allocated (physically present on disk) and referenced (logically
referenced in the pool) block counts and sizes by reference count.
+.Pp
+If specified a third time, display the statistics independently for each deduplication table.
+.Pp
+If specified a fourth time, dump the contents of the deduplication tables describing duplicate blocks.
+.Pp
+If specified a fifth time, also dump the contents of the deduplication tables describing unique blocks.
.It Fl h
Display pool history similar to
.Cm zpool history ,
@@ -205,6 +220,11 @@ flag specifies the path under which devices are to be searched.
.It Fl F
Attempt to make an unreadable pool readable by trying progressively older
transactions.
+.It Fl M Ar inflight I/Os
+Limit the number of outstanding checksum I/Os to the specified value.
+The default value is 200. This option affects the performance of the
+.Fl c
+option.
.It Fl P
Print numbers in an unscaled form more amenable to parsing, eg. 1000000 rather
than 1M.
@@ -218,9 +238,7 @@ options for a means to see the available uberblocks and their associated
transaction numbers.
.It Fl U Ar cachefile
Use a cache file other than
-.Pa /etc/zfs/zpool.cache .
-This option is only valid with
-.Fl C
+.Pa /boot/zfs/zpool.cache .
.It Fl v
Enable verbosity.
Specify multiple times for increased verbosity.
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
index c265c99..61e8071 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb.c
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
*/
#include <stdio.h>
@@ -89,6 +89,7 @@ extern void dump_intent_log(zilog_t *);
uint64_t *zopt_object = NULL;
int zopt_objects = 0;
libzfs_handle_t *g_zfs;
+uint64_t max_inflight = 200;
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
@@ -110,16 +111,17 @@ static void
usage(void)
{
(void) fprintf(stderr,
- "Usage: %s [-CumdibcsDvhLXFPA] [-t txg] [-e [-p path...]]"
- "poolname [object...]\n"
- " %s [-divPA] [-e -p path...] dataset [object...]\n"
- " %s -m [-LXFPA] [-t txg] [-e [-p path...]]"
- "poolname [vdev [metaslab...]]\n"
- " %s -R [-A] [-e [-p path...]] poolname "
- "vdev:offset:size[:flags]\n"
- " %s -S [-PA] [-e [-p path...]] poolname\n"
- " %s -l [-uA] device\n"
- " %s -C [-A] [-U config]\n\n",
+ "Usage: %s [-CumdibcsDvhLXFPA] [-t txg] [-e [-p path...]] "
+ "[-U config] [-M inflight I/Os] poolname [object...]\n"
+ " %s [-divPA] [-e -p path...] [-U config] dataset "
+ "[object...]\n"
+ " %s -m [-LXFPA] [-t txg] [-e [-p path...]] [-U config] "
+ "poolname [vdev [metaslab...]]\n"
+ " %s -R [-A] [-e [-p path...]] poolname "
+ "vdev:offset:size[:flags]\n"
+ " %s -S [-PA] [-e [-p path...]] [-U config] poolname\n"
+ " %s -l [-uA] device\n"
+ " %s -C [-A] [-U config]\n\n",
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname);
(void) fprintf(stderr, " Dataset name must include at least one "
@@ -164,6 +166,8 @@ usage(void)
(void) fprintf(stderr, " -P print numbers in parseable form\n");
(void) fprintf(stderr, " -t <txg> -- highest txg to use when "
"searching for uberblocks\n");
+ (void) fprintf(stderr, " -M <number of inflight I/Os> -- "
+ "specify the maximum number of checksumming I/Os [default is 200]");
(void) fprintf(stderr, "Specify an option more than once (e.g. -bb) "
"to make only that option verbose\n");
(void) fprintf(stderr, "Default is to dump everything non-verbosely\n");
@@ -242,7 +246,7 @@ const char histo_stars[] = "****************************************";
const int histo_width = sizeof (histo_stars) - 1;
static void
-dump_histogram(const uint64_t *histo, int size)
+dump_histogram(const uint64_t *histo, int size, int offset)
{
int i;
int minidx = size - 1;
@@ -263,7 +267,7 @@ dump_histogram(const uint64_t *histo, int size)
for (i = minidx; i <= maxidx; i++) {
(void) printf("\t\t\t%3u: %6llu %s\n",
- i, (u_longlong_t)histo[i],
+ i + offset, (u_longlong_t)histo[i],
&histo_stars[(max - histo[i]) * histo_width / max]);
}
}
@@ -316,19 +320,19 @@ dump_zap_stats(objset_t *os, uint64_t object)
(u_longlong_t)zs.zs_salt);
(void) printf("\t\tLeafs with 2^n pointers:\n");
- dump_histogram(zs.zs_leafs_with_2n_pointers, ZAP_HISTOGRAM_SIZE);
+ dump_histogram(zs.zs_leafs_with_2n_pointers, ZAP_HISTOGRAM_SIZE, 0);
(void) printf("\t\tBlocks with n*5 entries:\n");
- dump_histogram(zs.zs_blocks_with_n5_entries, ZAP_HISTOGRAM_SIZE);
+ dump_histogram(zs.zs_blocks_with_n5_entries, ZAP_HISTOGRAM_SIZE, 0);
(void) printf("\t\tBlocks n/10 full:\n");
- dump_histogram(zs.zs_blocks_n_tenths_full, ZAP_HISTOGRAM_SIZE);
+ dump_histogram(zs.zs_blocks_n_tenths_full, ZAP_HISTOGRAM_SIZE, 0);
(void) printf("\t\tEntries with n chunks:\n");
- dump_histogram(zs.zs_entries_using_n_chunks, ZAP_HISTOGRAM_SIZE);
+ dump_histogram(zs.zs_entries_using_n_chunks, ZAP_HISTOGRAM_SIZE, 0);
(void) printf("\t\tBuckets with n entries:\n");
- dump_histogram(zs.zs_buckets_with_n_entries, ZAP_HISTOGRAM_SIZE);
+ dump_histogram(zs.zs_buckets_with_n_entries, ZAP_HISTOGRAM_SIZE, 0);
}
/*ARGSUSED*/
@@ -517,26 +521,89 @@ dump_zpldir(objset_t *os, uint64_t object, void *data, size_t size)
zap_cursor_fini(&zc);
}
+int
+get_dtl_refcount(vdev_t *vd)
+{
+ int refcount = 0;
+
+ if (vd->vdev_ops->vdev_op_leaf) {
+ space_map_t *sm = vd->vdev_dtl_sm;
+
+ if (sm != NULL &&
+ sm->sm_dbuf->db_size == sizeof (space_map_phys_t))
+ return (1);
+ return (0);
+ }
+
+ for (int c = 0; c < vd->vdev_children; c++)
+ refcount += get_dtl_refcount(vd->vdev_child[c]);
+ return (refcount);
+}
+
+int
+get_metaslab_refcount(vdev_t *vd)
+{
+ int refcount = 0;
+
+ if (vd->vdev_top == vd) {
+ for (int m = 0; m < vd->vdev_ms_count; m++) {
+ space_map_t *sm = vd->vdev_ms[m]->ms_sm;
+
+ if (sm != NULL &&
+ sm->sm_dbuf->db_size == sizeof (space_map_phys_t))
+ refcount++;
+ }
+ }
+ for (int c = 0; c < vd->vdev_children; c++)
+ refcount += get_metaslab_refcount(vd->vdev_child[c]);
+
+ return (refcount);
+}
+
+static int
+verify_spacemap_refcounts(spa_t *spa)
+{
+ uint64_t expected_refcount = 0;
+ uint64_t actual_refcount;
+
+ (void) feature_get_refcount(spa,
+ &spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM],
+ &expected_refcount);
+ actual_refcount = get_dtl_refcount(spa->spa_root_vdev);
+ actual_refcount += get_metaslab_refcount(spa->spa_root_vdev);
+
+ if (expected_refcount != actual_refcount) {
+ (void) printf("space map refcount mismatch: expected %lld != "
+ "actual %lld\n",
+ (longlong_t)expected_refcount,
+ (longlong_t)actual_refcount);
+ return (2);
+ }
+ return (0);
+}
+
static void
-dump_spacemap(objset_t *os, space_map_obj_t *smo, space_map_t *sm)
+dump_spacemap(objset_t *os, space_map_t *sm)
{
uint64_t alloc, offset, entry;
- uint8_t mapshift = sm->sm_shift;
- uint64_t mapstart = sm->sm_start;
char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
"INVALID", "INVALID", "INVALID", "INVALID" };
- if (smo->smo_object == 0)
+ if (sm == NULL)
return;
/*
* Print out the freelist entries in both encoded and decoded form.
*/
alloc = 0;
- for (offset = 0; offset < smo->smo_objsize; offset += sizeof (entry)) {
- VERIFY3U(0, ==, dmu_read(os, smo->smo_object, offset,
+ for (offset = 0; offset < space_map_length(sm);
+ offset += sizeof (entry)) {
+ uint8_t mapshift = sm->sm_shift;
+
+ VERIFY0(dmu_read(os, space_map_object(sm), offset,
sizeof (entry), &entry, DMU_READ_PREFETCH));
if (SM_DEBUG_DECODE(entry)) {
+
(void) printf("\t [%6llu] %s: txg %llu, pass %llu\n",
(u_longlong_t)(offset / sizeof (entry)),
ddata[SM_DEBUG_ACTION_DECODE(entry)],
@@ -548,10 +615,10 @@ dump_spacemap(objset_t *os, space_map_obj_t *smo, space_map_t *sm)
(u_longlong_t)(offset / sizeof (entry)),
SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F',
(u_longlong_t)((SM_OFFSET_DECODE(entry) <<
- mapshift) + mapstart),
+ mapshift) + sm->sm_start),
(u_longlong_t)((SM_OFFSET_DECODE(entry) <<
- mapshift) + mapstart + (SM_RUN_DECODE(entry) <<
- mapshift)),
+ mapshift) + sm->sm_start +
+ (SM_RUN_DECODE(entry) << mapshift)),
(u_longlong_t)(SM_RUN_DECODE(entry) << mapshift));
if (SM_TYPE_DECODE(entry) == SM_ALLOC)
alloc += SM_RUN_DECODE(entry) << mapshift;
@@ -559,10 +626,10 @@ dump_spacemap(objset_t *os, space_map_obj_t *smo, space_map_t *sm)
alloc -= SM_RUN_DECODE(entry) << mapshift;
}
}
- if (alloc != smo->smo_alloc) {
+ if (alloc != space_map_allocated(sm)) {
(void) printf("space_map_object alloc (%llu) INCONSISTENT "
"with space map summary (%llu)\n",
- (u_longlong_t)smo->smo_alloc, (u_longlong_t)alloc);
+ (u_longlong_t)space_map_allocated(sm), (u_longlong_t)alloc);
}
}
@@ -570,15 +637,17 @@ static void
dump_metaslab_stats(metaslab_t *msp)
{
char maxbuf[32];
- space_map_t *sm = msp->ms_map;
- avl_tree_t *t = sm->sm_pp_root;
- int free_pct = sm->sm_space * 100 / sm->sm_size;
+ range_tree_t *rt = msp->ms_tree;
+ avl_tree_t *t = &msp->ms_size_tree;
+ int free_pct = range_tree_space(rt) * 100 / msp->ms_size;
- zdb_nicenum(space_map_maxsize(sm), maxbuf);
+ zdb_nicenum(metaslab_block_maxsize(msp), maxbuf);
(void) printf("\t %25s %10lu %7s %6s %4s %4d%%\n",
"segments", avl_numnodes(t), "maxsize", maxbuf,
"freepct", free_pct);
+ (void) printf("\tIn-memory histogram:\n");
+ dump_histogram(rt->rt_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
}
static void
@@ -586,33 +655,44 @@ dump_metaslab(metaslab_t *msp)
{
vdev_t *vd = msp->ms_group->mg_vd;
spa_t *spa = vd->vdev_spa;
- space_map_t *sm = msp->ms_map;
- space_map_obj_t *smo = &msp->ms_smo;
+ space_map_t *sm = msp->ms_sm;
char freebuf[32];
- zdb_nicenum(sm->sm_size - smo->smo_alloc, freebuf);
+ zdb_nicenum(msp->ms_size - space_map_allocated(sm), freebuf);
(void) printf(
"\tmetaslab %6llu offset %12llx spacemap %6llu free %5s\n",
- (u_longlong_t)(sm->sm_start / sm->sm_size),
- (u_longlong_t)sm->sm_start, (u_longlong_t)smo->smo_object, freebuf);
+ (u_longlong_t)msp->ms_id, (u_longlong_t)msp->ms_start,
+ (u_longlong_t)space_map_object(sm), freebuf);
- if (dump_opt['m'] > 1 && !dump_opt['L']) {
+ if (dump_opt['m'] > 2 && !dump_opt['L']) {
mutex_enter(&msp->ms_lock);
- space_map_load_wait(sm);
- if (!sm->sm_loaded)
- VERIFY(space_map_load(sm, zfs_metaslab_ops,
- SM_FREE, smo, spa->spa_meta_objset) == 0);
+ metaslab_load_wait(msp);
+ if (!msp->ms_loaded) {
+ VERIFY0(metaslab_load(msp));
+ range_tree_stat_verify(msp->ms_tree);
+ }
dump_metaslab_stats(msp);
- space_map_unload(sm);
+ metaslab_unload(msp);
mutex_exit(&msp->ms_lock);
}
- if (dump_opt['d'] > 5 || dump_opt['m'] > 2) {
- ASSERT(sm->sm_size == (1ULL << vd->vdev_ms_shift));
+ if (dump_opt['m'] > 1 && sm != NULL &&
+ spa_feature_is_active(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
+ /*
+ * The space map histogram represents free space in chunks
+ * of sm_shift (i.e. bucket 0 refers to 2^sm_shift).
+ */
+ (void) printf("\tOn-disk histogram:\n");
+ dump_histogram(sm->sm_phys->smp_histogram,
+ SPACE_MAP_HISTOGRAM_SIZE(sm), sm->sm_shift);
+ }
+
+ if (dump_opt['d'] > 5 || dump_opt['m'] > 3) {
+ ASSERT(msp->ms_size == (1ULL << vd->vdev_ms_shift));
mutex_enter(&msp->ms_lock);
- dump_spacemap(spa->spa_meta_objset, smo, sm);
+ dump_spacemap(spa->spa_meta_objset, msp->ms_sm);
mutex_exit(&msp->ms_lock);
}
}
@@ -684,7 +764,7 @@ dump_dde(const ddt_t *ddt, const ddt_entry_t *dde, uint64_t index)
if (ddp->ddp_phys_birth == 0)
continue;
ddt_bp_create(ddt->ddt_checksum, ddk, ddp, &blk);
- sprintf_blkptr(blkbuf, &blk);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), &blk);
(void) printf("index %llx refcnt %llu %s %s\n",
(u_longlong_t)index, (u_longlong_t)ddp->ddp_refcnt,
types[p], blkbuf);
@@ -801,9 +881,9 @@ dump_all_ddts(spa_t *spa)
}
static void
-dump_dtl_seg(space_map_t *sm, uint64_t start, uint64_t size)
+dump_dtl_seg(void *arg, uint64_t start, uint64_t size)
{
- char *prefix = (void *)sm;
+ char *prefix = arg;
(void) printf("%s [%llu,%llu) length %llu\n",
prefix,
@@ -833,28 +913,32 @@ dump_dtl(vdev_t *vd, int indent)
required ? "DTL-required" : "DTL-expendable");
for (int t = 0; t < DTL_TYPES; t++) {
- space_map_t *sm = &vd->vdev_dtl[t];
- if (sm->sm_space == 0)
+ range_tree_t *rt = vd->vdev_dtl[t];
+ if (range_tree_space(rt) == 0)
continue;
(void) snprintf(prefix, sizeof (prefix), "\t%*s%s",
indent + 2, "", name[t]);
- mutex_enter(sm->sm_lock);
- space_map_walk(sm, dump_dtl_seg, (void *)prefix);
- mutex_exit(sm->sm_lock);
+ mutex_enter(rt->rt_lock);
+ range_tree_walk(rt, dump_dtl_seg, prefix);
+ mutex_exit(rt->rt_lock);
if (dump_opt['d'] > 5 && vd->vdev_children == 0)
- dump_spacemap(spa->spa_meta_objset,
- &vd->vdev_dtl_smo, sm);
+ dump_spacemap(spa->spa_meta_objset, vd->vdev_dtl_sm);
}
for (int c = 0; c < vd->vdev_children; c++)
dump_dtl(vd->vdev_child[c], indent + 4);
}
+/* from spa_history.c: spa_history_create_obj() */
+#define HIS_BUF_LEN_DEF (128 << 10)
+#define HIS_BUF_LEN_MAX (1 << 30)
+
static void
dump_history(spa_t *spa)
{
nvlist_t **events = NULL;
- char buf[SPA_MAXBLOCKSIZE];
+ char *buf = NULL;
+ uint64_t bufsize = HIS_BUF_LEN_DEF;
uint64_t resid, len, off = 0;
uint_t num = 0;
int error;
@@ -863,8 +947,11 @@ dump_history(spa_t *spa)
char tbuf[30];
char internalstr[MAXPATHLEN];
+ if ((buf = malloc(bufsize)) == NULL)
+ (void) fprintf(stderr, "Unable to read history: "
+ "out of memory\n");
do {
- len = sizeof (buf);
+ len = bufsize;
if ((error = spa_history_get(spa, &off, &len, buf)) != 0) {
(void) fprintf(stderr, "Unable to read history: "
@@ -874,9 +961,26 @@ dump_history(spa_t *spa)
if (zpool_history_unpack(buf, len, &resid, &events, &num) != 0)
break;
-
off -= resid;
+
+ /*
+ * If the history block is too big, double the buffer
+ * size and try again.
+ */
+ if (resid == len) {
+ free(buf);
+ buf = NULL;
+
+ bufsize <<= 1;
+ if ((bufsize >= HIS_BUF_LEN_MAX) ||
+ ((buf = malloc(bufsize)) == NULL)) {
+ (void) fprintf(stderr, "Unable to read history: "
+ "out of memory\n");
+ return;
+ }
+ }
} while (len != 0);
+ free(buf);
(void) printf("\nHistory:\n");
for (int i = 0; i < num; i++) {
@@ -945,31 +1049,39 @@ blkid2offset(const dnode_phys_t *dnp, const blkptr_t *bp, const zbookmark_t *zb)
}
static void
-sprintf_blkptr_compact(char *blkbuf, const blkptr_t *bp)
+snprintf_blkptr_compact(char *blkbuf, size_t buflen, const blkptr_t *bp)
{
const dva_t *dva = bp->blk_dva;
int ndvas = dump_opt['d'] > 5 ? BP_GET_NDVAS(bp) : 1;
if (dump_opt['b'] >= 6) {
- sprintf_blkptr(blkbuf, bp);
+ snprintf_blkptr(blkbuf, buflen, bp);
return;
}
blkbuf[0] = '\0';
for (int i = 0; i < ndvas; i++)
- (void) sprintf(blkbuf + strlen(blkbuf), "%llu:%llx:%llx ",
+ (void) snprintf(blkbuf + strlen(blkbuf),
+ buflen - strlen(blkbuf), "%llu:%llx:%llx ",
(u_longlong_t)DVA_GET_VDEV(&dva[i]),
(u_longlong_t)DVA_GET_OFFSET(&dva[i]),
(u_longlong_t)DVA_GET_ASIZE(&dva[i]));
- (void) sprintf(blkbuf + strlen(blkbuf),
- "%llxL/%llxP F=%llu B=%llu/%llu",
- (u_longlong_t)BP_GET_LSIZE(bp),
- (u_longlong_t)BP_GET_PSIZE(bp),
- (u_longlong_t)bp->blk_fill,
- (u_longlong_t)bp->blk_birth,
- (u_longlong_t)BP_PHYSICAL_BIRTH(bp));
+ if (BP_IS_HOLE(bp)) {
+ (void) snprintf(blkbuf + strlen(blkbuf),
+ buflen - strlen(blkbuf), "B=%llu",
+ (u_longlong_t)bp->blk_birth);
+ } else {
+ (void) snprintf(blkbuf + strlen(blkbuf),
+ buflen - strlen(blkbuf),
+ "%llxL/%llxP F=%llu B=%llu/%llu",
+ (u_longlong_t)BP_GET_LSIZE(bp),
+ (u_longlong_t)BP_GET_PSIZE(bp),
+ (u_longlong_t)bp->blk_fill,
+ (u_longlong_t)bp->blk_birth,
+ (u_longlong_t)BP_PHYSICAL_BIRTH(bp));
+ }
}
static void
@@ -994,7 +1106,7 @@ print_indirect(blkptr_t *bp, const zbookmark_t *zb,
}
}
- sprintf_blkptr_compact(blkbuf, bp);
+ snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
(void) printf("%s\n", blkbuf);
}
@@ -1009,7 +1121,7 @@ visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
print_indirect(bp, zb, dnp);
- if (BP_GET_LEVEL(bp) > 0) {
+ if (BP_GET_LEVEL(bp) > 0 && !BP_IS_HOLE(bp)) {
uint32_t flags = ARC_WAIT;
int i;
blkptr_t *cbp;
@@ -1134,7 +1246,7 @@ dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
zdb_nicenum(ds->ds_compressed_bytes, compressed);
zdb_nicenum(ds->ds_uncompressed_bytes, uncompressed);
zdb_nicenum(ds->ds_unique_bytes, unique);
- sprintf_blkptr(blkbuf, &ds->ds_bp);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), &ds->ds_bp);
(void) printf("\t\tdir_obj = %llu\n",
(u_longlong_t)ds->ds_dir_obj);
@@ -1179,7 +1291,7 @@ dump_bptree_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
char blkbuf[BP_SPRINTF_LEN];
if (bp->blk_birth != 0) {
- sprintf_blkptr(blkbuf, bp);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
(void) printf("\t%s\n", blkbuf);
}
return (0);
@@ -1217,7 +1329,7 @@ dump_bpobj_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
char blkbuf[BP_SPRINTF_LEN];
ASSERT(bp->blk_birth != 0);
- sprintf_blkptr_compact(blkbuf, bp);
+ snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
(void) printf("\t%s\n", blkbuf);
return (0);
}
@@ -1716,8 +1828,9 @@ dump_dir(objset_t *os)
zdb_nicenum(refdbytes, numbuf);
if (verbosity >= 4) {
- (void) sprintf(blkbuf, ", rootbp ");
- (void) sprintf_blkptr(blkbuf + strlen(blkbuf), os->os_rootbp);
+ (void) snprintf(blkbuf, sizeof (blkbuf), ", rootbp ");
+ (void) snprintf_blkptr(blkbuf + strlen(blkbuf),
+ sizeof (blkbuf) - strlen(blkbuf), os->os_rootbp);
} else {
blkbuf[0] = '\0';
}
@@ -1747,7 +1860,7 @@ dump_dir(objset_t *os)
if (verbosity < 2)
return;
- if (os->os_rootbp->blk_birth == 0)
+ if (BP_IS_HOLE(os->os_rootbp))
return;
dump_object(os, 0, verbosity, &print_header);
@@ -1788,7 +1901,7 @@ dump_uberblock(uberblock_t *ub, const char *header, const char *footer)
(u_longlong_t)ub->ub_timestamp, asctime(localtime(&timestamp)));
if (dump_opt['u'] >= 3) {
char blkbuf[BP_SPRINTF_LEN];
- sprintf_blkptr(blkbuf, &ub->ub_rootbp);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), &ub->ub_rootbp);
(void) printf("\trootbp = %s\n", blkbuf);
}
(void) printf(footer ? footer : "");
@@ -2079,16 +2192,68 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
bp, NULL, NULL, ZIO_FLAG_CANFAIL)), ==, 0);
}
+/* ARGSUSED */
+static void
+zdb_blkptr_done(zio_t *zio)
+{
+ spa_t *spa = zio->io_spa;
+ blkptr_t *bp = zio->io_bp;
+ int ioerr = zio->io_error;
+ zdb_cb_t *zcb = zio->io_private;
+ zbookmark_t *zb = &zio->io_bookmark;
+
+ zio_data_buf_free(zio->io_data, zio->io_size);
+
+ mutex_enter(&spa->spa_scrub_lock);
+ spa->spa_scrub_inflight--;
+ cv_broadcast(&spa->spa_scrub_io_cv);
+
+ if (ioerr && !(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
+ char blkbuf[BP_SPRINTF_LEN];
+
+ zcb->zcb_haderrors = 1;
+ zcb->zcb_errors[ioerr]++;
+
+ if (dump_opt['b'] >= 2)
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ else
+ blkbuf[0] = '\0';
+
+ (void) printf("zdb_blkptr_cb: "
+ "Got error %d reading "
+ "<%llu, %llu, %lld, %llx> %s -- skipping\n",
+ ioerr,
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)zb->zb_object,
+ (u_longlong_t)zb->zb_level,
+ (u_longlong_t)zb->zb_blkid,
+ blkbuf);
+ }
+ mutex_exit(&spa->spa_scrub_lock);
+}
+
+/* ARGSUSED */
static int
zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
{
zdb_cb_t *zcb = arg;
- char blkbuf[BP_SPRINTF_LEN];
dmu_object_type_t type;
boolean_t is_metadata;
- if (bp == NULL)
+ if (dump_opt['b'] >= 5 && bp->blk_birth > 0) {
+ char blkbuf[BP_SPRINTF_LEN];
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+ (void) printf("objset %llu object %llu "
+ "level %lld offset 0x%llx %s\n",
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)zb->zb_object,
+ (longlong_t)zb->zb_level,
+ (u_longlong_t)blkid2offset(dnp, bp, zb),
+ blkbuf);
+ }
+
+ if (BP_IS_HOLE(bp))
return (0);
type = BP_GET_TYPE(bp);
@@ -2099,53 +2264,26 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
is_metadata = (BP_GET_LEVEL(bp) != 0 || DMU_OT_IS_METADATA(type));
if (dump_opt['c'] > 1 || (dump_opt['c'] && is_metadata)) {
- int ioerr;
size_t size = BP_GET_PSIZE(bp);
- void *data = malloc(size);
+ void *data = zio_data_buf_alloc(size);
int flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_SCRUB | ZIO_FLAG_RAW;
/* If it's an intent log block, failure is expected. */
if (zb->zb_level == ZB_ZIL_LEVEL)
flags |= ZIO_FLAG_SPECULATIVE;
- ioerr = zio_wait(zio_read(NULL, spa, bp, data, size,
- NULL, NULL, ZIO_PRIORITY_ASYNC_READ, flags, zb));
+ mutex_enter(&spa->spa_scrub_lock);
+ while (spa->spa_scrub_inflight > max_inflight)
+ cv_wait(&spa->spa_scrub_io_cv, &spa->spa_scrub_lock);
+ spa->spa_scrub_inflight++;
+ mutex_exit(&spa->spa_scrub_lock);
- free(data);
- if (ioerr && !(flags & ZIO_FLAG_SPECULATIVE)) {
- zcb->zcb_haderrors = 1;
- zcb->zcb_errors[ioerr]++;
-
- if (dump_opt['b'] >= 2)
- sprintf_blkptr(blkbuf, bp);
- else
- blkbuf[0] = '\0';
-
- (void) printf("zdb_blkptr_cb: "
- "Got error %d reading "
- "<%llu, %llu, %lld, %llx> %s -- skipping\n",
- ioerr,
- (u_longlong_t)zb->zb_objset,
- (u_longlong_t)zb->zb_object,
- (u_longlong_t)zb->zb_level,
- (u_longlong_t)zb->zb_blkid,
- blkbuf);
- }
+ zio_nowait(zio_read(NULL, spa, bp, data, size,
+ zdb_blkptr_done, zcb, ZIO_PRIORITY_ASYNC_READ, flags, zb));
}
zcb->zcb_readfails = 0;
- if (dump_opt['b'] >= 5) {
- sprintf_blkptr(blkbuf, bp);
- (void) printf("objset %llu object %llu "
- "level %lld offset 0x%llx %s\n",
- (u_longlong_t)zb->zb_objset,
- (u_longlong_t)zb->zb_object,
- (longlong_t)zb->zb_level,
- (u_longlong_t)blkid2offset(dnp, bp, zb),
- blkbuf);
- }
-
if (dump_opt['b'] < 5 && isatty(STDERR_FILENO) &&
gethrtime() > zcb->zcb_lastprint + NANOSEC) {
uint64_t now = gethrtime();
@@ -2172,39 +2310,17 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
}
static void
-zdb_leak(space_map_t *sm, uint64_t start, uint64_t size)
+zdb_leak(void *arg, uint64_t start, uint64_t size)
{
- vdev_t *vd = sm->sm_ppd;
+ vdev_t *vd = arg;
(void) printf("leaked space: vdev %llu, offset 0x%llx, size %llu\n",
(u_longlong_t)vd->vdev_id, (u_longlong_t)start, (u_longlong_t)size);
}
-/* ARGSUSED */
-static void
-zdb_space_map_load(space_map_t *sm)
-{
-}
-
-static void
-zdb_space_map_unload(space_map_t *sm)
-{
- space_map_vacate(sm, zdb_leak, sm);
-}
-
-/* ARGSUSED */
-static void
-zdb_space_map_claim(space_map_t *sm, uint64_t start, uint64_t size)
-{
-}
-
-static space_map_ops_t zdb_space_map_ops = {
- zdb_space_map_load,
- zdb_space_map_unload,
+static metaslab_ops_t zdb_metaslab_ops = {
NULL, /* alloc */
- zdb_space_map_claim,
- NULL, /* free */
- NULL /* maxsize */
+ NULL /* fragmented */
};
static void
@@ -2259,11 +2375,21 @@ zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
for (int m = 0; m < vd->vdev_ms_count; m++) {
metaslab_t *msp = vd->vdev_ms[m];
mutex_enter(&msp->ms_lock);
- space_map_unload(msp->ms_map);
- VERIFY(space_map_load(msp->ms_map,
- &zdb_space_map_ops, SM_ALLOC, &msp->ms_smo,
- spa->spa_meta_objset) == 0);
- msp->ms_map->sm_ppd = vd;
+ metaslab_unload(msp);
+
+ /*
+ * For leak detection, we overload the metaslab
+ * ms_tree to contain allocated segments
+ * instead of free segments. As a result,
+ * we can't use the normal metaslab_load/unload
+ * interfaces.
+ */
+ if (msp->ms_sm != NULL) {
+ msp->ms_ops = &zdb_metaslab_ops;
+ VERIFY0(space_map_load(msp->ms_sm,
+ msp->ms_tree, SM_ALLOC));
+ msp->ms_loaded = B_TRUE;
+ }
mutex_exit(&msp->ms_lock);
}
}
@@ -2286,7 +2412,20 @@ zdb_leak_fini(spa_t *spa)
for (int m = 0; m < vd->vdev_ms_count; m++) {
metaslab_t *msp = vd->vdev_ms[m];
mutex_enter(&msp->ms_lock);
- space_map_unload(msp->ms_map);
+
+ /*
+ * The ms_tree has been overloaded to
+ * contain allocated segments. Now that we
+ * finished traversing all blocks, any
+ * block that remains in the ms_tree
+ * represents an allocated block that we
+ * did not claim during the traversal.
+ * Claimed blocks would have been removed
+ * from the ms_tree.
+ */
+ range_tree_vacate(msp->ms_tree, zdb_leak, vd);
+ msp->ms_loaded = B_FALSE;
+
mutex_exit(&msp->ms_lock);
}
}
@@ -2301,7 +2440,7 @@ count_block_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
if (dump_opt['b'] >= 5) {
char blkbuf[BP_SPRINTF_LEN];
- sprintf_blkptr(blkbuf, bp);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
(void) printf("[%s] %s\n",
"deferred free", blkbuf);
}
@@ -2344,8 +2483,7 @@ dump_block_stats(spa_t *spa)
(void) bpobj_iterate_nofree(&spa->spa_dsl_pool->dp_free_bpobj,
count_block_cb, &zcb, NULL);
}
- if (spa_feature_is_active(spa,
- &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
+ if (spa_feature_is_active(spa, SPA_FEATURE_ASYNC_DESTROY)) {
VERIFY3U(0, ==, bptree_iterate(spa->spa_meta_objset,
spa->spa_dsl_pool->dp_bptree_obj, B_FALSE, count_block_cb,
&zcb, NULL));
@@ -2358,6 +2496,18 @@ dump_block_stats(spa_t *spa)
zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
zcb.zcb_haderrors |= traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
+ /*
+ * If we've traversed the data blocks then we need to wait for those
+ * I/Os to complete. We leverage "The Godfather" zio to wait on
+ * all async I/Os to complete.
+ */
+ if (dump_opt['c']) {
+ (void) zio_wait(spa->spa_async_zio_root);
+ spa->spa_async_zio_root = zio_root(spa, NULL, NULL,
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+ ZIO_FLAG_GODFATHER);
+ }
+
if (zcb.zcb_haderrors) {
(void) printf("\nError counts:\n\n");
(void) printf("\t%5s %s\n", "errno", "count");
@@ -2489,7 +2639,7 @@ dump_block_stats(spa_t *spa)
"(in 512-byte sectors): "
"number of blocks\n");
dump_histogram(zb->zb_psize_histogram,
- PSIZE_HISTO_SIZE);
+ PSIZE_HISTO_SIZE, 0);
}
}
}
@@ -2524,7 +2674,7 @@ zdb_ddt_add_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
avl_index_t where;
zdb_ddt_entry_t *zdde, zdde_search;
- if (bp == NULL)
+ if (BP_IS_HOLE(bp))
return (0);
if (dump_opt['S'] > 1 && zb->zb_level == ZB_ROOT_LEVEL) {
@@ -2591,7 +2741,8 @@ dump_simulated_ddt(spa_t *spa)
dds.dds_ref_psize = zdde->zdde_ref_psize;
dds.dds_ref_dsize = zdde->zdde_ref_dsize;
- ddt_stat_add(&ddh_total.ddh_stat[highbit(refcnt) - 1], &dds, 0);
+ ddt_stat_add(&ddh_total.ddh_stat[highbit64(refcnt) - 1],
+ &dds, 0);
umem_free(zdde, sizeof (*zdde));
}
@@ -2646,7 +2797,7 @@ dump_zpool(spa_t *spa)
}
if (spa_feature_is_active(spa,
- &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
+ SPA_FEATURE_ASYNC_DESTROY)) {
dump_bptree(spa->spa_meta_objset,
spa->spa_dsl_pool->dp_bptree_obj,
"Pool dataset frees");
@@ -2659,6 +2810,9 @@ dump_zpool(spa_t *spa)
if (dump_opt['b'] || dump_opt['c'])
rc = dump_block_stats(spa);
+ if (rc == 0)
+ rc = verify_spacemap_refcounts(spa);
+
if (dump_opt['s'])
show_pool_stats(spa);
@@ -2688,7 +2842,7 @@ zdb_print_blkptr(blkptr_t *bp, int flags)
if (flags & ZDB_FLAG_BSWAP)
byteswap_uint64_array((void *)bp, sizeof (blkptr_t));
- sprintf_blkptr(blkbuf, bp);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
(void) printf("%s\n", blkbuf);
}
@@ -2884,6 +3038,7 @@ zdb_read_block(char *thing, spa_t *spa)
free(dup);
return;
}
+ i += p - &flagstr[i + 1]; /* skip over the number */
}
}
@@ -3124,7 +3279,7 @@ main(int argc, char **argv)
dprintf_setup(&argc, argv);
- while ((c = getopt(argc, argv, "bcdhilmsuCDRSAFLXevp:t:U:P")) != -1) {
+ while ((c = getopt(argc, argv, "bcdhilmM:suCDRSAFLXevp:t:U:P")) != -1) {
switch (c) {
case 'b':
case 'c':
@@ -3153,6 +3308,15 @@ main(int argc, char **argv)
case 'v':
verbose++;
break;
+ case 'M':
+ max_inflight = strtoull(optarg, NULL, 0);
+ if (max_inflight == 0) {
+ (void) fprintf(stderr, "maximum number "
+ "of inflight I/Os must be greater "
+ "than 0\n");
+ usage();
+ }
+ break;
case 'p':
if (searchdirs == NULL) {
searchdirs = umem_alloc(sizeof (char *),
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c b/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
index a0ed985..17f7ad3 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
@@ -24,6 +24,10 @@
*/
/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+/*
* Print intent log header and statistics.
*/
@@ -47,7 +51,7 @@ print_log_bp(const blkptr_t *bp, const char *prefix)
{
char blkbuf[BP_SPRINTF_LEN];
- sprintf_blkptr(blkbuf, bp);
+ snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
(void) printf("%s%s\n", prefix, blkbuf);
}
@@ -132,6 +136,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
(void) printf("%shas blkptr, %s\n", prefix,
+ !BP_IS_HOLE(bp) &&
bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
"will claim" : "won't claim");
print_log_bp(bp, prefix);
@@ -139,8 +144,6 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
if (BP_IS_HOLE(bp)) {
(void) printf("\t\t\tLSIZE 0x%llx\n",
(u_longlong_t)BP_GET_LSIZE(bp));
- }
- if (bp->blk_birth == 0) {
bzero(buf, sizeof (buf));
(void) printf("%s<hole>\n", prefix);
return;
@@ -313,7 +316,8 @@ print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
if (verbose >= 5) {
(void) strcpy(blkbuf, ", ");
- sprintf_blkptr(blkbuf + strlen(blkbuf), bp);
+ snprintf_blkptr(blkbuf + strlen(blkbuf),
+ sizeof (blkbuf) - strlen(blkbuf), bp);
} else {
blkbuf[0] = '\0';
}
@@ -361,7 +365,7 @@ dump_intent_log(zilog_t *zilog)
int verbose = MAX(dump_opt['d'], dump_opt['i']);
int i;
- if (zh->zh_log.blk_birth == 0 || verbose < 1)
+ if (BP_IS_HOLE(&zh->zh_log) || verbose < 1)
return;
(void) printf("\n ZIL header: claim_txg %llu, "
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
index 9daec71..9eb3082 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
@@ -18,17 +18,19 @@
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" Copyright (c) 2010, Sun Microsystems, Inc. All Rights Reserved.
-.\" Copyright (c) 2012 by Delphix. All rights reserved.
+.\" Copyright (c) 2013 by Delphix. All rights reserved.
.\" Copyright (c) 2011, Pawel Jakub Dawidek <pjd@FreeBSD.org>
.\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org>
.\" Copyright (c) 2012, Bryan Drewery <bdrewery@FreeBSD.org>
.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
.\" Copyright (c) 2013 Nexenta Systems, Inc. All Rights Reserved.
-.\" Copyright (c) 2013, Joyent, Inc. All rights reserved.
+.\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
+.\" Copyright (c) 2013, Steven Hartland <smh@FreeBSD.org>
+.\" Copyright (c) 2014, Xin LI <delphij@FreeBSD.org>
.\"
.\" $FreeBSD$
.\"
-.Dd September 20, 2013
+.Dd April 23, 2014
.Dt ZFS 8
.Os
.Sh NAME
@@ -56,12 +58,17 @@
.Cm destroy
.Op Fl dnpRrv
.Sm off
-.Ar snapshot
-.Op % Ns Ar snapname
+.Ar filesystem Ns | Ns volume
+.Ns @snap
+.Op % Ns Ar snap
+.Op , Ns Ar snap Op % Ns Ar snap
.Op , Ns ...
.Sm on
.Nm
-.Cm snapshot
+.Cm destroy
+.Ar filesystem Ns | Ns Ar volume Ns # Ns Ar bookmark
+.Nm
+.Cm snapshot Ns | Ns Cm snap
.Op Fl r
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
.Ar filesystem@snapname Ns | Ns Ar volume@snapname
@@ -101,7 +108,7 @@
.Nm
.Cm list
.Op Fl r Ns | Ns Fl d Ar depth
-.Op Fl H
+.Op Fl Hp
.Op Fl o Ar property Ns Oo , Ns property Ns Oc Ns ...
.Op Fl t Ar type Ns Oo , Ns type Ns Oc Ns ...
.Oo Fl s Ar property Oc Ns ...
@@ -157,7 +164,7 @@
.Op Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
.Fl a | Ar filesystem
.Nm
-.Cm unmount
+.Cm unmount Ns | Ns Cm umount
.Op Fl f
.Fl a | Ar filesystem Ns | Ns Ar mountpoint
.Nm
@@ -167,16 +174,24 @@
.Cm unshare
.Fl a | Ar filesystem Ns | Ns Ar mountpoint
.Nm
+.Cm bookmark
+.Ar snapshot
+.Ar bookmark
+.Nm
.Cm send
.Op Fl DnPpRv
.Op Fl i Ar snapshot | Fl I Ar snapshot
.Ar snapshot
.Nm
-.Cm receive
+.Cm send
+.Op Fl i Ar snapshot Ns | Ns bookmark
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Nm
+.Cm receive Ns | Ns Cm recv
.Op Fl vnFu
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
.Nm
-.Cm receive
+.Cm receive Ns | Ns Cm recv
.Op Fl vnFu
.Op Fl d | e
.Ar filesystem
@@ -527,6 +542,13 @@ if the snapshot has been marked for deferred destroy by using the
.Qq Nm Cm destroy -d
command. Otherwise, the property is
.Cm off .
+.It Sy filesystem_count
+The total number of filesystems and volumes that exist under this location in the
+dataset tree.
+This value is only available when a
+.Sy filesystem_limit
+has
+been set somewhere in the tree under which the dataset resides.
.It Sy logicalreferenced
The amount of space that is
.Qq logically
@@ -585,6 +607,12 @@ The compression ratio achieved for the
space of this dataset, expressed as a multiplier. See also the
.Sy compressratio
property.
+.It Sy snapshot_count
+The total number of snapshots that exist under this location in the dataset tree.
+This value is only available when a
+.Sy snapshot_limit
+has been set somewhere
+in the tree under which the dataset resides.
.It Sy type
The type of dataset:
.Sy filesystem , volume , No or Sy snapshot .
@@ -1005,6 +1033,23 @@ The
.Sy mlslabel
property is currently not supported on
.Fx .
+.It Sy filesystem_limit Ns = Ns Ar count | Cm none
+Limits the number of filesystems and volumes that can exist under this point in
+the dataset tree.
+The limit is not enforced if the user is allowed to change
+the limit.
+Setting a
+.Sy filesystem_limit
+on a descendent of a filesystem that
+already has a
+.Sy filesystem_limit
+does not override the ancestor's
+.Sy filesystem_limit ,
+but rather imposes an additional limit.
+This feature must be enabled to be used
+.Po see
+.Xr zpool-features 7
+.Pc .
.It Sy mountpoint Ns = Ns Ar path | Cm none | legacy
Controls the mount point used for this file system. See the
.Qq Sx Mount Points
@@ -1046,6 +1091,27 @@ the ancestor's quota, but rather imposes an additional limit.
Quotas cannot be set on volumes, as the
.Sy volsize
property acts as an implicit quota.
+.It Sy snapshot_limit Ns = Ns Ar count | Cm none
+Limits the number of snapshots that can be created on a dataset and its
+descendents.
+Setting a
+.Sy snapshot_limit
+on a descendent of a dataset that already
+has a
+.Sy snapshot_limit
+does not override the ancestor's
+.Sy snapshot_limit ,
+but
+rather imposes an additional limit.
+The limit is not enforced if the user is
+allowed to change the limit.
+For example, this means that recursive snapshots
+taken from the global zone are counted against each delegated dataset within
+a jail.
+This feature must be enabled to be used
+.Po see
+.Xr zpool-features 7
+.Pc .
.It Sy userquota@ Ns Ar user Ns = Ns Ar size | Cm none
Limits the amount of space consumed by the specified user.
Similar to the
@@ -1291,6 +1357,38 @@ Consequently, writes to a sparse volume can fail with
when the pool is low on space. For a sparse volume, changes to
.Sy volsize
are not reflected in the reservation.
+.It Sy volmode Ns = Ns Cm default | geom | dev | none
+This property specifies how volumes should be exposed to the OS.
+Setting it to
+.Sy geom
+exposes volumes as
+.Xr geom 4
+providers, providing maximal functionality.
+Setting it to
+.Sy dev
+exposes volumes only as cdev device in devfs.
+Such volumes can be accessed only as raw disk device files, i.e. they
+can not be partitioned, mounted, participate in RAIDs, etc, but they
+are faster, and in some use scenarios with untrusted consumer, such as
+NAS or VM storage, can be more safe.
+Volumes with property set to
+.Sy none
+are not exposed outside ZFS, but can be snapshoted, cloned, replicated, etc,
+that can be suitable for backup purposes.
+Value
+.Sy default
+means that volumes exposition is controlled by system-wide sysctl/tunable
+.Va vfs.zfs.vol.mode ,
+where
+.Sy geom ,
+.Sy dev
+and
+.Sy none
+are encoded as 1, 2 and 3 respectively.
+The default values is
+.Sy geom .
+This property can be changed any time, but so far it is processed only
+during volume creation and pool import.
.It Sy vscan Ns = Ns Cm off | on
The
.Sy vscan
@@ -1320,10 +1418,21 @@ features being supported, the new file system will have the default values for
these properties.
.Bl -tag -width 4n
.It Sy casesensitivity Ns = Ns Cm sensitive | insensitive | mixed
+Indicates whether the file name matching algorithm used by the file system
+should be case-sensitive, case-insensitive, or allow a combination of both
+styles of matching. The default value for the
+.Sy casesensitivity
+property is
+.Cm sensitive .
+Traditionally, UNIX and POSIX file systems have case-sensitive file names.
+.Pp
The
+.Cm mixed
+value for the
.Sy casesensitivity
-property is currently not supported on
-.Fx .
+property indicates that the
+file system can support requests for both case-sensitive and case-insensitive
+matching behavior.
.It Sy normalization Ns = Ns Cm none | formC | formD | formKC | formKD
Indicates whether the file system should perform a
.Sy unicode
@@ -1653,7 +1762,14 @@ options, as they can destroy large portions of a pool and cause unexpected
behavior for mounted file systems in use.
.It Xo
.Nm
-.Cm snapshot
+.Cm destroy
+.Ar filesystem Ns | Ns Ar volume Ns # Ns Ar bookmark
+.Xc
+.Pp
+The given bookmark is destroyed.
+.It Xo
+.Nm
+.Cm snapshot Ns | Ns Cm snap
.Op Fl r
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
.Ar filesystem@snapname Ns | Ns volume@snapname
@@ -1685,14 +1801,24 @@ Roll back the given dataset to a previous snapshot. When a dataset is rolled
back, all data that has changed since the snapshot is discarded, and the
dataset reverts to the state at the time of the snapshot. By default, the
command refuses to roll back to a snapshot other than the most recent one. In
-order to do so, all intermediate snapshots must be destroyed by specifying the
+order to do so, all intermediate snapshots and bookmarks must be destroyed
+by specifying the
.Fl r
option.
+.Pp
+The
+.Fl rR
+options do not recursively destroy the child snapshots of a
+recursive snapshot.
+Only direct snapshots of the specified filesystem
+are destroyed by either of these options.
+To completely roll back a
+recursive snapshot, you must rollback the individual child snapshots.
.Bl -tag -width indent
.It Fl r
-Recursively destroy any snapshots more recent than the one specified.
+Destroy any snapshots and bookmarks more recent than the one specified.
.It Fl R
-Recursively destroy any more recent snapshots, as well as any clones of those
+Destroy any more recent snapshots and bookmarks, as well as any clones of those
snapshots.
.It Fl f
Used with the
@@ -1806,7 +1932,7 @@ only dataset that can be renamed recursively.
.Nm
.Cm list
.Op Fl r Ns | Ns Fl d Ar depth
-.Op Fl H
+.Op Fl Hp
.Op Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
.Op Fl t Ar type Ns Oo , Ns Ar type Oc Ns ...
.Oo Fl s Ar property Oc Ns ...
@@ -1837,6 +1963,8 @@ will display only the dataset and its direct children.
.It Fl H
Used for scripting mode. Do not print headers and separate fields by a single
tab instead of arbitrary white space.
+.It Fl p
+Display numbers in parsable (exact) values.
.It Fl o Ar property Ns Oo , Ns Ar property Oc Ns ...
A comma-separated list of properties to display. The property must be:
.Bl -bullet -offset 2n
@@ -1865,7 +1993,7 @@ syntax.
A comma-separated list of types to display, where
.Ar type
is one of
-.Sy filesystem , snapshot , volume , No or Sy all .
+.Sy filesystem , snapshot , snap , volume , bookmark , No or Sy all .
For example, specifying
.Fl t Cm snapshot
displays only snapshots.
@@ -1962,7 +2090,7 @@ sections.
The special value
.Cm all
can be used to display all properties that apply to the given dataset's type
-(filesystem, volume, or snapshot).
+(filesystem, volume, snapshot, or bookmark).
.Bl -tag -width indent
.It Fl r
Recursively display properties for any children.
@@ -1977,7 +2105,7 @@ Display output in a form more easily parsed by scripts. Any headers are
omitted, and fields are explicitly separated by a single tab instead of an
arbitrary amount of space.
.It Fl p
-Display numbers in parseable (exact) values.
+Display numbers in parsable (exact) values.
.It Fl o Cm all | Ar field Ns Oo , Ns Ar field Oc Ns ...
A comma-separated list of columns to display. Supported values are
.Sy name,property,value,received,source .
@@ -2194,7 +2322,7 @@ Mount the specified filesystem.
.El
.It Xo
.Nm
-.Cm unmount
+.Cm unmount Ns | Ns Cm umount
.Op Fl f
.Fl a | Ar filesystem Ns | Ns Ar mountpoint
.Xc
@@ -2280,6 +2408,26 @@ file system shared on the system.
.El
.It Xo
.Nm
+.Cm bookmark
+.Ar snapshot
+.Ar bookmark
+.Xc
+.Pp
+Creates a bookmark of the given snapshot.
+Bookmarks mark the point in time
+when the snapshot was created, and can be used as the incremental source for
+a
+.Qq Nm Cm send
+command.
+.Pp
+This feature must be enabled to be used.
+See
+.Xr zpool-features 7
+for details on ZFS feature flags and the
+.Sy bookmark
+feature.
+.It Xo
+.Nm
.Cm send
.Op Fl DnPpRv
.Op Fl i Ar snapshot | Fl I Ar snapshot
@@ -2298,17 +2446,15 @@ a file or to a different system (for example, using
By default, a full stream is generated.
.Bl -tag -width indent
.It Fl i Ar snapshot
-Generate an incremental stream from the
-.Fl i Ar snapshot
-to the last
-.Ar snapshot .
-The incremental source (the
-.Fl i Ar snapshot )
-can be specified as the last component of the snapshot name (for example, the
-part after the
-.Sy @ ) ,
-and it is assumed to be from the same file system as the last
-.Ar snapshot .
+Generate an incremental stream from the first
+.Ar snapshot Pq the incremental source
+to the second
+.Ar snapshot Pq the incremental target .
+The incremental source can be specified as the last component of the
+snapshot name
+.Pq the Em @ No character and following
+and
+it is assumed to be from the same file system as the incremental target.
.Pp
If the destination is a clone, the source may be the origin snapshot, which
must be fully specified (for example,
@@ -2316,15 +2462,16 @@ must be fully specified (for example,
not just
.Cm @origin ) .
.It Fl I Ar snapshot
-Generate a stream package that sends all intermediary snapshots from the
-.Fl I Ar snapshot
-to the last
+Generate a stream package that sends all intermediary snapshots from the first
+.Ar snapshot
+to the second
.Ar snapshot .
For example,
.Ic -I @a fs@d
is similar to
.Ic -i @a fs@b; -i @b fs@c; -i @c fs@d .
-The incremental source snapshot may be specified as with the
+The incremental
+source may be specified as with the
.Fl i
option.
.It Fl R
@@ -2377,13 +2524,42 @@ on future versions of
.Tn ZFS .
.It Xo
.Nm
-.Cm receive
+.Cm send
+.Op Fl i Ar snapshot Ns | Ns Ar bookmark
+.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
+.Xc
+.Pp
+Generate a send stream, which may be of a filesystem, and may be
+incremental from a bookmark.
+If the destination is a filesystem or volume,
+the pool must be read-only, or the filesystem must not be mounted.
+When the
+stream generated from a filesystem or volume is received, the default snapshot
+name will be
+.Pq --head-- .
+.Bl -tag -width indent
+.It Fl i Ar snapshot Ns | Ns bookmark
+Generate an incremental send stream.
+The incremental source must be an earlier
+snapshot in the destination's history.
+It will commonly be an earlier
+snapshot in the destination's filesystem, in which case it can be
+specified as the last component of the name
+.Pq the Em # No or Em @ No character and following .
+.Pp
+If the incremental target is a clone, the incremental source can
+be the origin snapshot, or an earlier snapshot in the origin's filesystem,
+or the origin's origin, etc.
+.El
+.It Xo
+.Nm
+.Cm receive Ns | Ns Cm recv
.Op Fl vnFu
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
.Xc
.It Xo
.Nm
-.Cm receive
+.Cm receive Ns | Ns Cm recv
.Op Fl vnFu
.Op Fl d | e
.Ar filesystem
@@ -2474,7 +2650,7 @@ option to verify the name the receive operation would use.
Force a rollback of the file system to the most recent snapshot before
performing the receive operation. If receiving an incremental replication
stream (for example, one generated by
-.Qq Nm Cm send Fl R Fi iI ) ,
+.Qq Nm Cm send Fl R Bro Fl i | Fl I Brc ) ,
destroy snapshots and file systems that do not exist on the sending side.
.El
.It Xo
@@ -2613,6 +2789,7 @@ protocol
.It dedup Ta property
.It devices Ta property
.It exec Ta property
+.It filesystem_limit Ta property
.It logbias Ta property
.It jailed Ta property
.It mlslabel Ta property
@@ -2631,6 +2808,7 @@ protocol
.It sharenfs Ta property
.It sharesmb Ta property
.It snapdir Ta property
+.It snapshot_limit Ta property
.It sync Ta property
.It utf8only Ta property
.It version Ta property
@@ -2819,7 +2997,7 @@ option of
.It \&P Ta event port (not supported on Fx )
.El
.It Fl H
-Give more parseable tab-separated output, without header lines and without
+Give more parsable tab-separated output, without header lines and without
arrows.
.It Fl t
Display the path's inode change time as the first column of output.
@@ -2977,10 +3155,12 @@ pool/home/bob compression on local
pool/home/bob atime on default
pool/home/bob devices on default
pool/home/bob exec on default
+pool/home/bob filesystem_limit none default
pool/home/bob setuid on default
pool/home/bob readonly off default
pool/home/bob jailed off default
pool/home/bob snapdir hidden default
+pool/home/bob snapshot_limit none default
pool/home/bob aclmode discard default
pool/home/bob aclinherit restricted default
pool/home/bob canmount on default
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c
index 62cd9d0..626d69c 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.c
@@ -18,10 +18,13 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
*/
#include <libintl.h>
@@ -70,7 +73,7 @@ uu_avl_pool_t *avl_pool;
* Include snaps if they were requested or if this a zfs list where types
* were not specified and the "listsnapshots" property is set on this pool.
*/
-static int
+static boolean_t
zfs_include_snapshots(zfs_handle_t *zhp, callback_data_t *cb)
{
zpool_handle_t *zph;
@@ -90,8 +93,9 @@ static int
zfs_callback(zfs_handle_t *zhp, void *data)
{
callback_data_t *cb = data;
- int dontclose = 0;
- int include_snaps = zfs_include_snapshots(zhp, cb);
+ boolean_t dontclose = B_FALSE;
+ boolean_t include_snaps = zfs_include_snapshots(zhp, cb);
+ boolean_t include_bmarks = (cb->cb_types & ZFS_TYPE_BOOKMARK);
if ((zfs_get_type(zhp) & cb->cb_types) ||
((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) {
@@ -109,14 +113,15 @@ zfs_callback(zfs_handle_t *zhp, void *data)
cb->cb_props_table);
if (zfs_expand_proplist(zhp, cb->cb_proplist,
- (cb->cb_flags & ZFS_ITER_RECVD_PROPS))
+ (cb->cb_flags & ZFS_ITER_RECVD_PROPS),
+ (cb->cb_flags & ZFS_ITER_LITERAL_PROPS))
!= 0) {
free(node);
return (-1);
}
}
uu_avl_insert(cb->cb_avl, node, idx);
- dontclose = 1;
+ dontclose = B_TRUE;
} else {
free(node);
}
@@ -131,11 +136,14 @@ zfs_callback(zfs_handle_t *zhp, void *data)
cb->cb_depth++;
if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
(void) zfs_iter_filesystems(zhp, zfs_callback, data);
- if ((zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) && include_snaps) {
+ if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
+ ZFS_TYPE_BOOKMARK)) == 0) && include_snaps)
(void) zfs_iter_snapshots(zhp,
(cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
data);
- }
+ if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
+ ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks)
+ (void) zfs_iter_bookmarks(zhp, zfs_callback, data);
cb->cb_depth--;
}
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h
index a287374..f4f0e5b 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_iter.h
@@ -18,9 +18,11 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef ZFS_ITER_H
@@ -44,6 +46,7 @@ typedef struct zfs_sort_column {
#define ZFS_ITER_DEPTH_LIMIT (1 << 3)
#define ZFS_ITER_RECVD_PROPS (1 << 4)
#define ZFS_ITER_SIMPLE (1 << 5)
+#define ZFS_ITER_LITERAL_PROPS (1 << 6)
int zfs_for_each(int, char **, int options, zfs_type_t,
zfs_sort_column_t *, zprop_list_t **, int, zfs_iter_f, void *);
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
index a2d4973..4c5f8d44 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
@@ -21,14 +21,14 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include <assert.h>
@@ -107,6 +107,7 @@ static int zfs_do_release(int argc, char **argv);
static int zfs_do_diff(int argc, char **argv);
static int zfs_do_jail(int argc, char **argv);
static int zfs_do_unjail(int argc, char **argv);
+static int zfs_do_bookmark(int argc, char **argv);
/*
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
@@ -155,6 +156,7 @@ typedef enum {
HELP_HOLDS,
HELP_RELEASE,
HELP_DIFF,
+ HELP_BOOKMARK,
} zfs_help_t;
typedef struct zfs_command {
@@ -181,6 +183,7 @@ static zfs_command_t command_table[] = {
{ "clone", zfs_do_clone, HELP_CLONE },
{ "promote", zfs_do_promote, HELP_PROMOTE },
{ "rename", zfs_do_rename, HELP_RENAME },
+ { "bookmark", zfs_do_bookmark, HELP_BOOKMARK },
{ NULL },
{ "list", zfs_do_list, HELP_LIST },
{ NULL },
@@ -231,11 +234,12 @@ get_usage(zfs_help_t idx)
case HELP_DESTROY:
return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
"\tdestroy [-dnpRrv] "
- "<snapshot>[%<snapname>][,...]\n"));
+ "<filesystem|volume>@<snap>[%<snap>][,...]\n"
+ "\tdestroy <filesystem|volume>#<bookmark>\n"));
case HELP_GET:
return (gettext("\tget [-rHp] [-d max] "
- "[-o \"all\" | field[,...]] [-t type[,...]] "
- "[-s source[,...]]\n"
+ "[-o \"all\" | field[,...]]\n"
+ "\t [-t type[,...]] [-s source[,...]]\n"
"\t <\"all\" | property[,...]> "
"[filesystem|volume|snapshot] ...\n"));
case HELP_INHERIT:
@@ -249,9 +253,8 @@ get_usage(zfs_help_t idx)
case HELP_UNJAIL:
return (gettext("\tunjail <jailid|jailname> <filesystem>\n"));
case HELP_LIST:
- return (gettext("\tlist [-rH][-d max] "
- "[-o property[,...]] [-t type[,...]] [-s property] ...\n"
- "\t [-S property] ... "
+ return (gettext("\tlist [-Hp] [-r|-d max] [-o property[,...]] "
+ "[-s property]...\n\t [-S property]... [-t type[,...]] "
"[filesystem|volume|snapshot] ...\n"));
case HELP_MOUNT:
return (gettext("\tmount\n"
@@ -259,31 +262,32 @@ get_usage(zfs_help_t idx)
case HELP_PROMOTE:
return (gettext("\tpromote <clone-filesystem>\n"));
case HELP_RECEIVE:
- return (gettext("\treceive [-vnFu] <filesystem|volume|"
+ return (gettext("\treceive|recv [-vnFu] <filesystem|volume|"
"snapshot>\n"
- "\treceive [-vnFu] [-d | -e] <filesystem>\n"));
+ "\treceive|recv [-vnFu] [-d | -e] <filesystem>\n"));
case HELP_RENAME:
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
"<filesystem|volume|snapshot>\n"
- "\trename [-f] -p <filesystem|volume> "
- "<filesystem|volume>\n"
+ "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
"\trename -r <snapshot> <snapshot>\n"
"\trename -u [-p] <filesystem> <filesystem>"));
case HELP_ROLLBACK:
return (gettext("\trollback [-rRf] <snapshot>\n"));
case HELP_SEND:
- return (gettext("\tsend [-DnPpRv] "
- "[-i snapshot | -I snapshot] <snapshot>\n"));
+ return (gettext("\tsend [-DnPpRv] [-[iI] snapshot] "
+ "<snapshot>\n"
+ "\tsend [-i snapshot|bookmark] "
+ "<filesystem|volume|snapshot>\n"));
case HELP_SET:
return (gettext("\tset <property=value> "
"<filesystem|volume|snapshot> ...\n"));
case HELP_SHARE:
return (gettext("\tshare <-a | filesystem>\n"));
case HELP_SNAPSHOT:
- return (gettext("\tsnapshot [-r] [-o property=value] ... "
- "<filesystem@snapname|volume@snapname> ...\n"));
+ return (gettext("\tsnapshot|snap [-r] [-o property=value] ... "
+ "<filesystem|volume>@<snap> ...\n"));
case HELP_UNMOUNT:
- return (gettext("\tunmount [-f] "
+ return (gettext("\tunmount|umount [-f] "
"<-a | filesystem|mountpoint>\n"));
case HELP_UNSHARE:
return (gettext("\tunshare "
@@ -310,12 +314,14 @@ get_usage(zfs_help_t idx)
"<filesystem|volume>\n"));
case HELP_USERSPACE:
return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
- "[-s field] ...\n\t[-S field] ... "
- "[-t type[,...]] <filesystem|snapshot>\n"));
+ "[-s field] ...\n"
+ "\t [-S field] ... [-t type[,...]] "
+ "<filesystem|snapshot>\n"));
case HELP_GROUPSPACE:
return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
- "[-s field] ...\n\t[-S field] ... "
- "[-t type[,...]] <filesystem|snapshot>\n"));
+ "[-s field] ...\n"
+ "\t [-S field] ... [-t type[,...]] "
+ "<filesystem|snapshot>\n"));
case HELP_HOLD:
return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
case HELP_HOLDS:
@@ -325,6 +331,8 @@ get_usage(zfs_help_t idx)
case HELP_DIFF:
return (gettext("\tdiff [-FHt] <snapshot> "
"[snapshot|filesystem]\n"));
+ case HELP_BOOKMARK:
+ return (gettext("\tbookmark <snapshot> <bookmark>\n"));
}
abort();
@@ -487,9 +495,8 @@ usage(boolean_t requested)
}
static int
-parseprop(nvlist_t *props)
+parseprop(nvlist_t *props, char *propname)
{
- char *propname = optarg;
char *propval, *strval;
if ((propval = strchr(propname, '=')) == NULL) {
@@ -518,7 +525,7 @@ parse_depth(char *opt, int *flags)
depth = (int)strtol(opt, &tmp, 0);
if (*tmp) {
(void) fprintf(stderr,
- gettext("%s is not an integer\n"), optarg);
+ gettext("%s is not an integer\n"), opt);
usage(B_FALSE);
}
if (depth < 0) {
@@ -609,7 +616,7 @@ zfs_do_clone(int argc, char **argv)
while ((c = getopt(argc, argv, "o:p")) != -1) {
switch (c) {
case 'o':
- if (parseprop(props))
+ if (parseprop(props, optarg))
return (1);
break;
case 'p':
@@ -759,7 +766,7 @@ zfs_do_create(int argc, char **argv)
nomem();
break;
case 'o':
- if (parseprop(props))
+ if (parseprop(props, optarg))
goto error;
break;
case 's':
@@ -927,6 +934,7 @@ typedef struct destroy_cbdata {
char *cb_prevsnap;
int64_t cb_snapused;
char *cb_snapspec;
+ char *cb_bookmark;
} destroy_cbdata_t;
/*
@@ -1196,7 +1204,7 @@ zfs_do_destroy(int argc, char **argv)
int err = 0;
int c;
zfs_handle_t *zhp = NULL;
- char *at;
+ char *at, *pound;
zfs_type_t type = ZFS_TYPE_DATASET;
/* check options */
@@ -1248,6 +1256,7 @@ zfs_do_destroy(int argc, char **argv)
}
at = strchr(argv[0], '@');
+ pound = strchr(argv[0], '#');
if (at != NULL) {
/* Build the list of snaps to destroy in cb_nvl. */
@@ -1309,6 +1318,46 @@ zfs_do_destroy(int argc, char **argv)
if (err != 0)
rv = 1;
+ } else if (pound != NULL) {
+ int err;
+ nvlist_t *nvl;
+
+ if (cb.cb_dryrun) {
+ (void) fprintf(stderr,
+ "dryrun is not supported with bookmark\n");
+ return (-1);
+ }
+
+ if (cb.cb_defer_destroy) {
+ (void) fprintf(stderr,
+ "defer destroy is not supported with bookmark\n");
+ return (-1);
+ }
+
+ if (cb.cb_recurse) {
+ (void) fprintf(stderr,
+ "recursive is not supported with bookmark\n");
+ return (-1);
+ }
+
+ if (!zfs_bookmark_exists(argv[0])) {
+ (void) fprintf(stderr, gettext("bookmark '%s' "
+ "does not exist.\n"), argv[0]);
+ return (1);
+ }
+
+ nvl = fnvlist_alloc();
+ fnvlist_add_boolean(nvl, argv[0]);
+
+ err = lzc_destroy_bookmarks(nvl, NULL);
+ if (err != 0) {
+ (void) zfs_standard_error(g_zfs, err,
+ "cannot destroy bookmark");
+ }
+
+ nvlist_free(cb.cb_nvl);
+
+ return (err);
} else {
/* Open the given dataset */
if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
@@ -1671,7 +1720,8 @@ zfs_do_get(int argc, char **argv)
flags &= ~ZFS_ITER_PROP_LISTSNAPS;
while (*optarg != '\0') {
static char *type_subopts[] = { "filesystem",
- "volume", "snapshot", "all", NULL };
+ "volume", "snapshot", "bookmark",
+ "all", NULL };
switch (getsubopt(&optarg, type_subopts,
&value)) {
@@ -1685,7 +1735,11 @@ zfs_do_get(int argc, char **argv)
types |= ZFS_TYPE_SNAPSHOT;
break;
case 3:
- types = ZFS_TYPE_DATASET;
+ types |= ZFS_TYPE_BOOKMARK;
+ break;
+ case 4:
+ types = ZFS_TYPE_DATASET |
+ ZFS_TYPE_BOOKMARK;
break;
default:
@@ -2011,7 +2065,7 @@ zfs_do_upgrade(int argc, char **argv)
boolean_t showversions = B_FALSE;
int ret = 0;
upgrade_cbdata_t cb = { 0 };
- char c;
+ int c;
int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
/* check options */
@@ -2124,7 +2178,7 @@ zfs_do_upgrade(int argc, char **argv)
* -i Translate SID to POSIX ID.
* -n Print numeric ID instead of user/group name.
* -o Control which fields to display.
- * -p Use exact (parseable) numeric output.
+ * -p Use exact (parsable) numeric output.
* -s Specify sort columns, descending order.
* -S Specify sort columns, ascending order.
* -t Control which object types to display.
@@ -2158,7 +2212,7 @@ static int us_type_bits[] = {
USTYPE_SMB_USR,
USTYPE_ALL
};
-static char *us_type_names[] = { "posixgroup", "posxiuser", "smbgroup",
+static char *us_type_names[] = { "posixgroup", "posixuser", "smbgroup",
"smbuser", "all" };
typedef struct us_node {
@@ -2811,24 +2865,25 @@ zfs_do_userspace(int argc, char **argv)
}
/*
- * list [-r][-d max] [-H] [-o property[,property]...] [-t type[,type]...]
- * [-s property [-s property]...] [-S property [-S property]...]
- * <dataset> ...
+ * list [-Hp][-r|-d max] [-o property[,...]] [-s property] ... [-S property] ...
+ * [-t type[,...]] [filesystem|volume|snapshot] ...
*
- * -r Recurse over all children
+ * -H Scripted mode; elide headers and separate columns by tabs.
+ * -p Display values in parsable (literal) format.
+ * -r Recurse over all children.
* -d Limit recursion by depth.
- * -H Scripted mode; elide headers and separate columns by tabs
* -o Control which fields to display.
- * -t Control which object types to display.
* -s Specify sort columns, descending order.
* -S Specify sort columns, ascending order.
+ * -t Control which object types to display.
*
- * When given no arguments, lists all filesystems in the system.
+ * When given no arguments, list all filesystems in the system.
* Otherwise, list the specified datasets, optionally recursing down them if
* '-r' is specified.
*/
typedef struct list_cbdata {
boolean_t cb_first;
+ boolean_t cb_literal;
boolean_t cb_scripted;
zprop_list_t *cb_proplist;
} list_cbdata_t;
@@ -2837,8 +2892,9 @@ typedef struct list_cbdata {
* Given a list of columns to display, output appropriate headers for each one.
*/
static void
-print_header(zprop_list_t *pl)
+print_header(list_cbdata_t *cb)
{
+ zprop_list_t *pl = cb->cb_proplist;
char headerbuf[ZFS_MAXPROPLEN];
const char *header;
int i;
@@ -2879,19 +2935,19 @@ print_header(zprop_list_t *pl)
* to the described layout.
*/
static void
-print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted)
+print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
{
+ zprop_list_t *pl = cb->cb_proplist;
boolean_t first = B_TRUE;
char property[ZFS_MAXPROPLEN];
nvlist_t *userprops = zfs_get_user_props(zhp);
nvlist_t *propval;
char *propstr;
boolean_t right_justify;
- int width;
for (; pl != NULL; pl = pl->pl_next) {
if (!first) {
- if (scripted)
+ if (cb->cb_scripted)
(void) printf("\t");
else
(void) printf(" ");
@@ -2906,22 +2962,22 @@ print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted)
right_justify = zfs_prop_align_right(pl->pl_prop);
} else if (pl->pl_prop != ZPROP_INVAL) {
if (zfs_prop_get(zhp, pl->pl_prop, property,
- sizeof (property), NULL, NULL, 0, B_FALSE) != 0)
+ sizeof (property), NULL, NULL, 0,
+ cb->cb_literal) != 0)
propstr = "-";
else
propstr = property;
-
right_justify = zfs_prop_align_right(pl->pl_prop);
} else if (zfs_prop_userquota(pl->pl_user_prop)) {
if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
- property, sizeof (property), B_FALSE) != 0)
+ property, sizeof (property), cb->cb_literal) != 0)
propstr = "-";
else
propstr = property;
right_justify = B_TRUE;
} else if (zfs_prop_written(pl->pl_user_prop)) {
if (zfs_prop_get_written(zhp, pl->pl_user_prop,
- property, sizeof (property), B_FALSE) != 0)
+ property, sizeof (property), cb->cb_literal) != 0)
propstr = "-";
else
propstr = property;
@@ -2936,19 +2992,17 @@ print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted)
right_justify = B_FALSE;
}
- width = pl->pl_width;
-
/*
* If this is being called in scripted mode, or if this is the
* last column and it is left-justified, don't include a width
* format specifier.
*/
- if (scripted || (pl->pl_next == NULL && !right_justify))
+ if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
(void) printf("%s", propstr);
else if (right_justify)
- (void) printf("%*s", width, propstr);
+ (void) printf("%*s", pl->pl_width, propstr);
else
- (void) printf("%-*s", width, propstr);
+ (void) printf("%-*s", pl->pl_width, propstr);
}
(void) printf("\n");
@@ -2964,11 +3018,11 @@ list_callback(zfs_handle_t *zhp, void *data)
if (cbp->cb_first) {
if (!cbp->cb_scripted)
- print_header(cbp->cb_proplist);
+ print_header(cbp);
cbp->cb_first = B_FALSE;
}
- print_dataset(zhp, cbp->cb_proplist, cbp->cb_scripted);
+ print_dataset(zhp, cbp);
return (0);
}
@@ -2977,7 +3031,6 @@ static int
zfs_do_list(int argc, char **argv)
{
int c;
- boolean_t scripted = B_FALSE;
static char default_fields[] =
"name,used,available,referenced,mountpoint";
int types = ZFS_TYPE_DATASET;
@@ -2991,11 +3044,15 @@ zfs_do_list(int argc, char **argv)
int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
/* check options */
- while ((c = getopt(argc, argv, ":d:o:rt:Hs:S:")) != -1) {
+ while ((c = getopt(argc, argv, "HS:d:o:prs:t:")) != -1) {
switch (c) {
case 'o':
fields = optarg;
break;
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ flags |= ZFS_ITER_LITERAL_PROPS;
+ break;
case 'd':
limit = parse_depth(optarg, &flags);
break;
@@ -3003,7 +3060,7 @@ zfs_do_list(int argc, char **argv)
flags |= ZFS_ITER_RECURSE;
break;
case 'H':
- scripted = B_TRUE;
+ cb.cb_scripted = B_TRUE;
break;
case 's':
if (zfs_add_sort_column(&sortcol, optarg,
@@ -3027,7 +3084,8 @@ zfs_do_list(int argc, char **argv)
flags &= ~ZFS_ITER_PROP_LISTSNAPS;
while (*optarg != '\0') {
static char *type_subopts[] = { "filesystem",
- "volume", "snapshot", "all", NULL };
+ "volume", "snapshot", "snap", "bookmark",
+ "all", NULL };
switch (getsubopt(&optarg, type_subopts,
&value)) {
@@ -3038,12 +3096,16 @@ zfs_do_list(int argc, char **argv)
types |= ZFS_TYPE_VOLUME;
break;
case 2:
+ case 3:
types |= ZFS_TYPE_SNAPSHOT;
break;
- case 3:
- types = ZFS_TYPE_DATASET;
+ case 4:
+ types |= ZFS_TYPE_BOOKMARK;
+ break;
+ case 5:
+ types = ZFS_TYPE_DATASET |
+ ZFS_TYPE_BOOKMARK;
break;
-
default:
(void) fprintf(stderr,
gettext("invalid type '%s'\n"),
@@ -3092,7 +3154,6 @@ zfs_do_list(int argc, char **argv)
!= 0)
usage(B_FALSE);
- cb.cb_scripted = scripted;
cb.cb_first = B_TRUE;
ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
@@ -3284,9 +3345,29 @@ typedef struct rollback_cbdata {
char *cb_target;
int cb_error;
boolean_t cb_recurse;
- boolean_t cb_dependent;
} rollback_cbdata_t;
+static int
+rollback_check_dependent(zfs_handle_t *zhp, void *data)
+{
+ rollback_cbdata_t *cbp = data;
+
+ if (cbp->cb_first && cbp->cb_recurse) {
+ (void) fprintf(stderr, gettext("cannot rollback to "
+ "'%s': clones of previous snapshots exist\n"),
+ cbp->cb_target);
+ (void) fprintf(stderr, gettext("use '-R' to "
+ "force deletion of the following clones and "
+ "dependents:\n"));
+ cbp->cb_first = 0;
+ cbp->cb_error = 1;
+ }
+
+ (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+
+ zfs_close(zhp);
+ return (0);
+}
/*
* Report any snapshots more recent than the one specified. Used when '-r' is
* not specified. We reuse this same callback for the snapshot dependents - if
@@ -3303,52 +3384,30 @@ rollback_check(zfs_handle_t *zhp, void *data)
return (0);
}
- if (!cbp->cb_dependent) {
- if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 &&
- zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
- zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
- cbp->cb_create) {
-
- if (cbp->cb_first && !cbp->cb_recurse) {
- (void) fprintf(stderr, gettext("cannot "
- "rollback to '%s': more recent snapshots "
- "exist\n"),
- cbp->cb_target);
- (void) fprintf(stderr, gettext("use '-r' to "
- "force deletion of the following "
- "snapshots:\n"));
- cbp->cb_first = 0;
- cbp->cb_error = 1;
- }
-
- if (cbp->cb_recurse) {
- cbp->cb_dependent = B_TRUE;
- if (zfs_iter_dependents(zhp, B_TRUE,
- rollback_check, cbp) != 0) {
- zfs_close(zhp);
- return (-1);
- }
- cbp->cb_dependent = B_FALSE;
- } else {
- (void) fprintf(stderr, "%s\n",
- zfs_get_name(zhp));
- }
- }
- } else {
- if (cbp->cb_first && cbp->cb_recurse) {
- (void) fprintf(stderr, gettext("cannot rollback to "
- "'%s': clones of previous snapshots exist\n"),
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
+ if (cbp->cb_first && !cbp->cb_recurse) {
+ (void) fprintf(stderr, gettext("cannot "
+ "rollback to '%s': more recent snapshots "
+ "or bookmarks exist\n"),
cbp->cb_target);
- (void) fprintf(stderr, gettext("use '-R' to "
- "force deletion of the following clones and "
- "dependents:\n"));
+ (void) fprintf(stderr, gettext("use '-r' to "
+ "force deletion of the following "
+ "snapshots and bookmarks:\n"));
cbp->cb_first = 0;
cbp->cb_error = 1;
}
- (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+ if (cbp->cb_recurse) {
+ if (zfs_iter_dependents(zhp, B_TRUE,
+ rollback_check_dependent, cbp) != 0) {
+ zfs_close(zhp);
+ return (-1);
+ }
+ } else {
+ (void) fprintf(stderr, "%s\n",
+ zfs_get_name(zhp));
+ }
}
-
zfs_close(zhp);
return (0);
}
@@ -3418,7 +3477,9 @@ zfs_do_rollback(int argc, char **argv)
cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
cb.cb_first = B_TRUE;
cb.cb_error = 0;
- if ((ret = zfs_iter_children(zhp, rollback_check, &cb)) != 0)
+ if ((ret = zfs_iter_snapshots(zhp, B_FALSE, rollback_check, &cb)) != 0)
+ goto out;
+ if ((ret = zfs_iter_bookmarks(zhp, rollback_check, &cb)) != 0)
goto out;
if ((ret = cb.cb_error) != 0)
@@ -3560,7 +3621,7 @@ static int
zfs_do_snapshot(int argc, char **argv)
{
int ret = 0;
- char c;
+ int c;
nvlist_t *props;
snap_cbdata_t sd = { 0 };
boolean_t multiple_snaps = B_FALSE;
@@ -3574,7 +3635,7 @@ zfs_do_snapshot(int argc, char **argv)
while ((c = getopt(argc, argv, "ro:")) != -1) {
switch (c) {
case 'o':
- if (parseprop(props))
+ if (parseprop(props, optarg))
return (1);
break;
case 'r':
@@ -3713,12 +3774,45 @@ zfs_do_send(int argc, char **argv)
return (1);
}
- cp = strchr(argv[0], '@');
- if (cp == NULL) {
- (void) fprintf(stderr,
- gettext("argument must be a snapshot\n"));
- usage(B_FALSE);
+ /*
+ * Special case sending a filesystem, or from a bookmark.
+ */
+ if (strchr(argv[0], '@') == NULL ||
+ (fromname && strchr(fromname, '#') != NULL)) {
+ char frombuf[ZFS_MAXNAMELEN];
+
+ if (flags.replicate || flags.doall || flags.props ||
+ flags.dedup || flags.dryrun || flags.verbose ||
+ flags.progress) {
+ (void) fprintf(stderr,
+ gettext("Error: "
+ "Unsupported flag with filesystem or bookmark.\n"));
+ return (1);
+ }
+
+ zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET);
+ if (zhp == NULL)
+ return (1);
+
+ if (fromname != NULL &&
+ (fromname[0] == '#' || fromname[0] == '@')) {
+ /*
+ * Incremental source name begins with # or @.
+ * Default to same fs as target.
+ */
+ (void) strncpy(frombuf, argv[0], sizeof (frombuf));
+ cp = strchr(frombuf, '@');
+ if (cp != NULL)
+ *cp = '\0';
+ (void) strlcat(frombuf, fromname, sizeof (frombuf));
+ fromname = frombuf;
+ }
+ err = zfs_send_one(zhp, fromname, STDOUT_FILENO);
+ zfs_close(zhp);
+ return (err != 0);
}
+
+ cp = strchr(argv[0], '@');
*cp = '\0';
toname = cp + 1;
zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
@@ -3874,6 +3968,7 @@ zfs_do_receive(int argc, char **argv)
#define ZFS_DELEG_PERM_HOLD "hold"
#define ZFS_DELEG_PERM_RELEASE "release"
#define ZFS_DELEG_PERM_DIFF "diff"
+#define ZFS_DELEG_PERM_BOOKMARK "bookmark"
#define ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE
@@ -3893,6 +3988,7 @@ static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
{ ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND },
{ ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
{ ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
+ { ZFS_DELEG_PERM_BOOKMARK, ZFS_DELEG_NOTE_BOOKMARK },
{ ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
{ ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
@@ -6664,6 +6760,108 @@ zfs_do_diff(int argc, char **argv)
return (err != 0);
}
+/*
+ * zfs bookmark <fs@snap> <fs#bmark>
+ *
+ * Creates a bookmark with the given name from the given snapshot.
+ */
+static int
+zfs_do_bookmark(int argc, char **argv)
+{
+ char snapname[ZFS_MAXNAMELEN];
+ zfs_handle_t *zhp;
+ nvlist_t *nvl;
+ int ret = 0;
+ int c;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "")) != -1) {
+ switch (c) {
+ case '?':
+ (void) fprintf(stderr,
+ gettext("invalid option '%c'\n"), optopt);
+ goto usage;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing snapshot argument\n"));
+ goto usage;
+ }
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing bookmark argument\n"));
+ goto usage;
+ }
+
+ if (strchr(argv[1], '#') == NULL) {
+ (void) fprintf(stderr,
+ gettext("invalid bookmark name '%s' -- "
+ "must contain a '#'\n"), argv[1]);
+ goto usage;
+ }
+
+ if (argv[0][0] == '@') {
+ /*
+ * Snapshot name begins with @.
+ * Default to same fs as bookmark.
+ */
+ (void) strncpy(snapname, argv[1], sizeof (snapname));
+ *strchr(snapname, '#') = '\0';
+ (void) strlcat(snapname, argv[0], sizeof (snapname));
+ } else {
+ (void) strncpy(snapname, argv[0], sizeof (snapname));
+ }
+ zhp = zfs_open(g_zfs, snapname, ZFS_TYPE_SNAPSHOT);
+ if (zhp == NULL)
+ goto usage;
+ zfs_close(zhp);
+
+
+ nvl = fnvlist_alloc();
+ fnvlist_add_string(nvl, argv[1], snapname);
+ ret = lzc_bookmark(nvl, NULL);
+ fnvlist_free(nvl);
+
+ if (ret != 0) {
+ const char *err_msg;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN,
+ "cannot create bookmark '%s'"), argv[1]);
+
+ switch (ret) {
+ case EXDEV:
+ err_msg = "bookmark is in a different pool";
+ break;
+ case EEXIST:
+ err_msg = "bookmark exists";
+ break;
+ case EINVAL:
+ err_msg = "invalid argument";
+ break;
+ case ENOTSUP:
+ err_msg = "bookmark feature not enabled";
+ break;
+ default:
+ err_msg = "unknown error";
+ break;
+ }
+ (void) fprintf(stderr, "%s: %s\n", errbuf,
+ dgettext(TEXT_DOMAIN, err_msg));
+ }
+
+ return (ret);
+
+usage:
+ usage(B_FALSE);
+ return (-1);
+}
+
int
main(int argc, char **argv)
{
@@ -6726,6 +6924,12 @@ main(int argc, char **argv)
cmdname = "receive";
/*
+ * The 'snap' command is an alias for 'snapshot'
+ */
+ if (strcmp(cmdname, "snap") == 0)
+ cmdname = "snapshot";
+
+ /*
* Special case '-?'
*/
if (strcmp(cmdname, "-?") == 0)
diff --git a/cddl/contrib/opensolaris/cmd/zhack/zhack.c b/cddl/contrib/opensolaris/cmd/zhack/zhack.c
index 1eb8713..ace8c32 100644
--- a/cddl/contrib/opensolaris/cmd/zhack/zhack.c
+++ b/cddl/contrib/opensolaris/cmd/zhack/zhack.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
*/
@@ -85,10 +85,15 @@ usage(void)
static void
-fatal(const char *fmt, ...)
+fatal(spa_t *spa, void *tag, const char *fmt, ...)
{
va_list ap;
+ if (spa != NULL) {
+ spa_close(spa, tag);
+ (void) spa_export(g_pool, NULL, B_TRUE, B_FALSE);
+ }
+
va_start(ap, fmt);
(void) fprintf(stderr, "%s: ", cmdname);
(void) vfprintf(stderr, fmt, ap);
@@ -159,13 +164,14 @@ import_pool(const char *target, boolean_t readonly)
g_importargs.can_be_active = B_TRUE;
if (zpool_search_import(g_zfs, &g_importargs) != NULL ||
spa_open(target, &spa, FTAG) == 0) {
- fatal("cannot import '%s': pool is active; run "
- "\"zpool export %s\" first\n",
- g_pool, g_pool);
+ fatal(spa, FTAG, "cannot import '%s': pool is "
+ "active; run " "\"zpool export %s\" "
+ "first\n", g_pool, g_pool);
}
}
- fatal("cannot import '%s': no such pool available\n", g_pool);
+ fatal(NULL, FTAG, "cannot import '%s': no such pool "
+ "available\n", g_pool);
}
elem = nvlist_next_nvpair(pools, NULL);
@@ -186,7 +192,8 @@ import_pool(const char *target, boolean_t readonly)
error = 0;
if (error)
- fatal("can't import '%s': %s", name, strerror(error));
+ fatal(NULL, FTAG, "can't import '%s': %s", name,
+ strerror(error));
}
static void
@@ -201,10 +208,11 @@ zhack_spa_open(const char *target, boolean_t readonly, void *tag, spa_t **spa)
zfeature_checks_disable = B_FALSE;
if (err != 0)
- fatal("cannot open '%s': %s", target, strerror(err));
+ fatal(*spa, FTAG, "cannot open '%s': %s", target,
+ strerror(err));
if (spa_version(*spa) < SPA_VERSION_FEATURES) {
- fatal("'%s' has version %d, features not enabled", target,
- (int)spa_version(*spa));
+ fatal(*spa, FTAG, "'%s' has version %d, features not enabled",
+ target, (int)spa_version(*spa));
}
}
@@ -269,18 +277,22 @@ zhack_do_feature_stat(int argc, char **argv)
dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
+ if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
+ dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg");
+ }
dump_mos(spa);
spa_close(spa, FTAG);
}
static void
-feature_enable_sync(void *arg, dmu_tx_t *tx)
+zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
- spa_feature_enable(spa, feature, tx);
+ feature_enable_sync(spa, feature, tx);
+
spa_history_log_internal(spa, "zhack enable feature", tx,
"name=%s can_readonly=%u",
feature->fi_guid, feature->fi_can_readonly);
@@ -294,7 +306,7 @@ zhack_do_feature_enable(int argc, char **argv)
spa_t *spa;
objset_t *mos;
zfeature_info_t feature;
- zfeature_info_t *nodeps[] = { NULL };
+ spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
/*
* Features are not added to the pool's label until their refcounts
@@ -304,7 +316,9 @@ zhack_do_feature_enable(int argc, char **argv)
feature.fi_uname = "zhack";
feature.fi_mos = B_FALSE;
feature.fi_can_readonly = B_FALSE;
+ feature.fi_activate_on_enable = B_FALSE;
feature.fi_depends = nodeps;
+ feature.fi_feature = SPA_FEATURE_NONE;
optind = 1;
while ((c = getopt(argc, argv, "rmd:")) != -1) {
@@ -336,18 +350,19 @@ zhack_do_feature_enable(int argc, char **argv)
feature.fi_guid = argv[1];
if (!zfeature_is_valid_guid(feature.fi_guid))
- fatal("invalid feature guid: %s", feature.fi_guid);
+ fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset;
- if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
- fatal("'%s' is a real feature, will not enable");
+ if (zfeature_is_supported(feature.fi_guid))
+ fatal(spa, FTAG, "'%s' is a real feature, will not enable");
if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
- fatal("feature already enabled: %s", feature.fi_guid);
+ fatal(spa, FTAG, "feature already enabled: %s",
+ feature.fi_guid);
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
- feature_enable_sync, &feature, 5));
+ zhack_feature_enable_sync, &feature, 5));
spa_close(spa, FTAG);
@@ -359,8 +374,10 @@ feature_incr_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
+ uint64_t refcount;
- spa_feature_incr(spa, feature, tx);
+ VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+ feature_sync(spa, feature, refcount + 1, tx);
spa_history_log_internal(spa, "zhack feature incr", tx,
"name=%s", feature->fi_guid);
}
@@ -370,8 +387,10 @@ feature_decr_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
+ uint64_t refcount;
- spa_feature_decr(spa, feature, tx);
+ VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+ feature_sync(spa, feature, refcount - 1, tx);
spa_history_log_internal(spa, "zhack feature decr", tx,
"name=%s", feature->fi_guid);
}
@@ -385,7 +404,7 @@ zhack_do_feature_ref(int argc, char **argv)
spa_t *spa;
objset_t *mos;
zfeature_info_t feature;
- zfeature_info_t *nodeps[] = { NULL };
+ spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
/*
* fi_desc does not matter here because it was written to disk
@@ -397,6 +416,7 @@ zhack_do_feature_ref(int argc, char **argv)
feature.fi_mos = B_FALSE;
feature.fi_desc = NULL;
feature.fi_depends = nodeps;
+ feature.fi_feature = SPA_FEATURE_NONE;
optind = 1;
while ((c = getopt(argc, argv, "md")) != -1) {
@@ -423,13 +443,15 @@ zhack_do_feature_ref(int argc, char **argv)
feature.fi_guid = argv[1];
if (!zfeature_is_valid_guid(feature.fi_guid))
- fatal("invalid feature guid: %s", feature.fi_guid);
+ fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset;
- if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
- fatal("'%s' is a real feature, will not change refcount");
+ if (zfeature_is_supported(feature.fi_guid)) {
+ fatal(spa, FTAG,
+ "'%s' is a real feature, will not change refcount");
+ }
if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
feature.fi_guid)) {
@@ -438,11 +460,17 @@ zhack_do_feature_ref(int argc, char **argv)
feature.fi_guid)) {
feature.fi_can_readonly = B_TRUE;
} else {
- fatal("feature is not enabled: %s", feature.fi_guid);
+ fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
}
- if (decr && !spa_feature_is_active(spa, &feature))
- fatal("feature refcount already 0: %s", feature.fi_guid);
+ if (decr) {
+ uint64_t count;
+ if (feature_get_refcount_from_disk(spa, &feature,
+ &count) == 0 && count != 0) {
+ fatal(spa, FTAG, "feature refcount already 0: %s",
+ feature.fi_guid);
+ }
+ }
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
decr ? feature_decr_sync : feature_incr_sync, &feature, 5));
@@ -530,8 +558,8 @@ main(int argc, char **argv)
usage();
}
- if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_TRUE) != 0) {
- fatal("pool export failed; "
+ if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) {
+ fatal(NULL, FTAG, "pool export failed; "
"changes may not be committed to disk\n");
}
diff --git a/cddl/contrib/opensolaris/cmd/zinject/zinject.c b/cddl/contrib/opensolaris/cmd/zinject/zinject.c
index 994d687..ddcdb1f 100644
--- a/cddl/contrib/opensolaris/cmd/zinject/zinject.c
+++ b/cddl/contrib/opensolaris/cmd/zinject/zinject.c
@@ -148,6 +148,7 @@
#include <sys/mount.h>
#include <libzfs.h>
+#include <libzfs_compat.h>
#undef verify /* both libzfs.h and zfs_context.h want to define this */
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7 b/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
index d018acc..5560de9 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
@@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 20, 2013
+.Dd April 23, 2014
.Dt ZPOOL-FEATURES 7
.Os
.Sh NAME
@@ -187,6 +187,23 @@ This feature is
.Sy active
while there are any filesystems, volumes, or snapshots which were created
after enabling this feature.
+.It Sy filesystem_limits
+.Bl -column "READ\-ONLY COMPATIBLE" "com.joyent:filesystem_limits"
+.It GUID Ta com.joyent:filesystem_limits
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+This feature enables filesystem and snapshot limits.
+These limits can be used
+to control how many filesystems and/or snapshots can be created at the point in
+the tree on which the limits are set.
+.Pp
+This feature is
+.Sy active
+once either of the limit properties has been
+set on a dataset.
+Once activated the feature is never deactivated.
.It Sy lz4_compress
.Bl -column "READ\-ONLY COMPATIBLE" "org.illumos:lz4_compress"
.It GUID Ta org.illumos:lz4_compress
@@ -222,12 +239,16 @@ command. Please note that doing so will
immediately activate the
.Sy lz4_compress
feature on the underlying
-pool (even before any data is written). Since this feature is not
-read-only compatible, this operation will render the pool unimportable
-on systems without support for the
+pool
+.Pq even before any data is written ,
+and the feature will not be
+deactivated.
+Since this feature is not read-only compatible, this
+operation will render the pool unimportable on systems without support
+for the
.Sy lz4_compress
-feature. At the
-moment, this operation cannot be reversed. Booting off of
+feature.
+Booting off of
.Sy lz4
-compressed root pools is supported.
.It Sy multi_vdev_crash_dump
@@ -251,6 +272,130 @@ configuration.
.\" .Xr dumpon 8
.\" command to configure a
.\" dump device on a pool comprised of multiple vdevs.
+.It Sy spacemap_histogram
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:spacemap_histogram"
+.It GUID Ta com.delphix:spacemap_histogram
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This features allows ZFS to maintain more information about how free space
+is organized within the pool. If this feature is
+.Sy enabled ,
+ZFS will
+set this feature to
+.Sy active
+when a new space map object is created or
+an existing space map is upgraded to the new format.
+Once the feature is
+.Sy active ,
+it will remain in that state until the pool is destroyed.
+.It Sy extensible_dataset
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:extensible_dataset"
+.It GUID Ta com.delphix:extensible_dataset
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature allows more flexible use of internal ZFS data structures,
+and exists for other features to depend on.
+.Pp
+This feature will be
+.Sy active
+when the first dependent feature uses it,
+and will be returned to the
+.Sy enabled
+state when all datasets that use
+this feature are destroyed.
+.It Sy bookmarks
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:bookmarks"
+.It GUID Ta com.delphix:bookmarks
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta extensible_dataset
+.El
+.Pp
+This feature enables use of the
+.Nm zfs
+.Cm bookmark
+subcommand.
+.Pp
+This feature is
+.Sy active
+while any bookmarks exist in the pool.
+All bookmarks in the pool can be listed by running
+.Nm zfs
+.Cm list
+.Fl t No bookmark Fl r Ar poolname .
+.It Sy enabled_txg
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:enabled_txg"
+.It GUID Ta com.delphix:enabled_txg
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+Once this feature is enabled ZFS records the transaction group number
+in which new features are enabled. This has no user-visible impact,
+but other features may depend on this feature.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
+.It Sy hole_birth
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:hole_birth"
+.It GUID Ta com.delphix:hole_birth
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta enabled_txg
+.El
+.Pp
+This feature improves performance of incremental sends
+.Pq Dq zfs send -i
+and receives for objects with many holes.
+The most common case of
+hole-filled objects is zvols.
+.Pp
+An incremental send stream from snapshot
+.Sy A
+to snapshot
+.Sy B
+contains information about every block that changed between
+.Sy A
+and
+.Sy B .
+Blocks which did not change between those snapshots can be
+identified and omitted from the stream using a piece of metadata called
+the 'block birth time', but birth times are not recorded for holes
+.Pq blocks filled only with zeroes .
+Since holes created after
+.Sy A
+cannot be
+distinguished from holes created before
+.Sy A ,
+information about every
+hole in the entire filesystem or zvol is included in the send stream.
+.Pp
+For workloads where holes are rare this is not a problem.
+However, when
+incrementally replicating filesystems or zvols with many holes
+.Pq for example a zvol formatted with another filesystem
+a lot of time will
+be spent sending and receiving unnecessary information about holes that
+already exist on the receiving side.
+.Pp
+Once the
+.Sy hole_birth
+feature has been enabled the block birth times
+of all new holes will be recorded.
+Incremental sends between snapshots
+created after this feature is enabled will use this new metadata to avoid
+sending information about holes that already exist on the receiving side.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
.El
.Sh SEE ALSO
.Xr zpool 8
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
index 715439b..1061e45 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool.8
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
@@ -1,5 +1,6 @@
'\" te
.\" Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>.
+.\" Copyright (c) 2013-2014, Xin Li <delphij@FreeBSD.org>.
.\" All Rights Reserved.
.\"
.\" The contents of this file are subject to the terms of the
@@ -25,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 14, 2013
+.Dd March 28, 2014
.Dt ZPOOL 8
.Os
.Sh NAME
@@ -70,6 +71,8 @@
.Ar pool ...
.Nm
.Cm get
+.Op Fl Hp
+.Op Fl o Ar field Ns Op , Ns Ar ...
.Ar all | property Ns Op , Ns Ar ...
.Ar pool ...
.Nm
@@ -120,7 +123,7 @@
.Ar device
.Nm
.Cm list
-.Op Fl H
+.Op Fl Hpv
.Op Fl o Ar property Ns Op , Ns Ar ...
.Op Fl T Cm d Ns | Ns Cm u
.Op Ar pool
@@ -141,6 +144,9 @@
.Cm remove
.Ar pool device ...
.Nm
+.Cm reopen
+.Ar pool
+.Nm
.Cm replace
.Op Fl f
.Ar pool device
@@ -621,6 +627,9 @@ Datasets of this pool can only be mounted read-only
.It
To write to a read-only pool, a export and import of the pool is required.
.El
+.Pp
+This property can also be referred to by its shortened column name,
+.Sy rdonly .
.El
.Pp
The following properties can be set at creation time and import time, and later
@@ -679,7 +688,9 @@ property.
Threshold for the number of block ditto copies. If the reference count for a
deduplicated block increases above this number, a new ditto copy of this block
is automatically stored. Default setting is
-.Cm 0 .
+.Cm 0
+which causes no ditto copies to be created for deduplicated blocks.
+The miniumum legal nonzero setting is 100.
.It Sy delegation Ns = Ns Cm on No | Cm off
Controls whether a non-privileged user is granted access based on the dataset
permissions defined on the dataset. See
@@ -1010,6 +1021,8 @@ is currently being used. This may lead to potential data corruption.
.It Xo
.Nm
.Cm get
+.Op Fl Hp
+.Op Fl o Ar field Ns Op , Ns Ar ...
.Ar all | property Ns Op , Ns Ar ...
.Ar pool ...
.Xc
@@ -1028,6 +1041,19 @@ the following fields:
See the
.Qq Sx Properties
section for more information on the available pool properties.
+.Pp
+.It Fl H
+Scripted mode. Do not display headers, and separate fields by a single tab
+instead of arbitrary space.
+.It Fl p
+Display numbers in parsable (exact) values.
+.It Fl o Ar field
+A comma-separated list of columns to display.
+.Sy name Ns , Ns
+.Sy property Ns , Ns
+.Sy value Ns , Ns
+.Sy source
+is the default value.
.It Xo
.Nm
.Cm history
@@ -1149,9 +1175,10 @@ option is also required.
.It Fl f
Forces import, even if the pool appears to be potentially active.
.It Fl m
-Enables import with missing log devices.
+Allows a pool to import when there is a missing log device. Recent transactions
+can be lost because the log device will be discarded.
.It Fl N
-Do not mount any filesystems from the imported pool.
+Import the pool without mounting any file systems.
.It Fl R Ar root
Sets the
.Qq Sy cachefile
@@ -1242,9 +1269,10 @@ option is also required.
.It Fl f
Forces import, even if the pool appears to be potentially active.
.It Fl m
-Enables import with missing log devices.
+Allows a pool to import when there is a missing log device. Recent transactions
+can be lost because the log device will be discarded.
.It Fl N
-Do not mount any filesystems from the imported pool.
+Import the pool without mounting any file systems.
.It Fl R Ar root
Equivalent to
.Qq Fl o Cm cachefile=none,altroot= Ns Pa root
@@ -1319,13 +1347,13 @@ The
.Ar device
must not be part of an active pool configuration.
.Bl -tag -width indent
-.It Fl v
+.It Fl f
Treat exported or foreign devices as inactive.
.El
.It Xo
.Nm
.Cm list
-.Op Fl Hv
+.Op Fl Hpv
.Op Fl o Ar property Ns Op , Ns Ar ...
.Op Fl T Cm d Ns | Ns Cm u
.Op Ar pool
@@ -1333,8 +1361,9 @@ Treat exported or foreign devices as inactive.
.Op Ar inverval Op Ar count
.Xc
.Pp
-Lists the given pools along with a health status and space usage. When given no
-arguments, all pools in the system are listed.
+Lists the given pools along with a health status and space usage. If no
+.Ar pools
+are specified, all pools in the system are listed.
.Pp
When given an interval, the output is printed every
.Ar interval
@@ -1346,9 +1375,22 @@ is specified, the command exits after
.Ar count
reports are printed.
.Bl -tag -width indent
+.It Fl T Cm d Ns | Ns Cm u
+Print a timestamp.
+.Pp
+Use modifier
+.Cm d
+for standard date format. See
+.Xr date 1 .
+Use modifier
+.Cm u
+for unixtime
+.Pq equals Qq Ic date +%s .
.It Fl H
Scripted mode. Do not display headers, and separate fields by a single tab
instead of arbitrary space.
+.It Fl p
+Display numbers in parsable (exact) values.
.It Fl v
Show more detailed information.
.It Fl o Ar property Ns Op , Ns Ar ...
@@ -1431,6 +1473,13 @@ command. Non-redundant and
devices cannot be removed from a pool.
.It Xo
.Nm
+.Cm reopen
+.Ar pool
+.Xc
+.Pp
+Reopen all the vdevs associated with the pool.
+.It Xo
+.Nm
.Cm replace
.Op Fl f
.Ar pool device
@@ -1667,7 +1716,7 @@ Once this is done, the pool will no longer be accessible on systems that do
not support feature flags.
See
.Xr zpool-features 7
-for details on compatability with system sthat support feature flags, but do
+for details on compatibility with systems that support feature flags, but do
not support all features enabled on the pool.
.Bl -tag -width indent
.It Fl a
@@ -1946,3 +1995,9 @@ The
.Xr mdoc 7
implementation of this manual page was initially written by
.An Martin Matuska Aq mm@FreeBSD.org .
+.Sh CAVEATS
+The
+.Cm spare
+feature requires a utility to detect zpool degradation and initiate
+disk replacement within the zpool.
+FreeBSD does not provide such a utility at this time.
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
index 0dcf11b..bec5e70 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
@@ -236,7 +236,7 @@ get_usage(zpool_help_t idx) {
case HELP_LABELCLEAR:
return (gettext("\tlabelclear [-f] <vdev>\n"));
case HELP_LIST:
- return (gettext("\tlist [-Hv] [-o property[,...]] "
+ return (gettext("\tlist [-Hpv] [-o property[,...]] "
"[-T d|u] [pool] ... [interval [count]]\n"));
case HELP_OFFLINE:
return (gettext("\toffline [-t] <pool> <device> ...\n"));
@@ -248,7 +248,7 @@ get_usage(zpool_help_t idx) {
case HELP_REMOVE:
return (gettext("\tremove <pool> <device> ...\n"));
case HELP_REOPEN:
- return (""); /* Undocumented command */
+ return (gettext("\treopen <pool>\n"));
case HELP_SCRUB:
return (gettext("\tscrub [-s] <pool> ...\n"));
case HELP_STATUS:
@@ -258,8 +258,8 @@ get_usage(zpool_help_t idx) {
return (gettext("\tupgrade [-v]\n"
"\tupgrade [-V version] <-a | pool ...>\n"));
case HELP_GET:
- return (gettext("\tget <\"all\" | property[,...]> "
- "<pool> ...\n"));
+ return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
+ "<\"all\" | property[,...]> <pool> ...\n"));
case HELP_SET:
return (gettext("\tset <property=value> <pool> \n"));
case HELP_SPLIT:
@@ -1004,7 +1004,7 @@ zpool_do_create(int argc, char **argv)
* Hand off to libzfs.
*/
if (enable_all_pool_feat) {
- int i;
+ spa_feature_t i;
for (i = 0; i < SPA_FEATURES; i++) {
char propname[MAXPATHLEN];
zfeature_info_t *feat = &spa_feature_table[i];
@@ -1702,6 +1702,12 @@ show_import(nvlist_t *config)
"resilvered.\n"));
break;
+ case ZPOOL_STATUS_NON_NATIVE_ASHIFT:
+ (void) printf(gettext("status: One or more devices were "
+ "configured to use a non-native block size.\n"
+ "\tExpect reduced performance.\n"));
+ break;
+
default:
/*
* No other status can be seen when importing pools.
@@ -1963,7 +1969,7 @@ zpool_do_import(int argc, char **argv)
char *endptr;
/* check options */
- while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
+ while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:T:VX")) != -1) {
switch (c) {
case 'a':
do_all = B_TRUE;
@@ -2759,6 +2765,7 @@ typedef struct list_cbdata {
int cb_namewidth;
boolean_t cb_scripted;
zprop_list_t *cb_proplist;
+ boolean_t cb_literal;
} list_cbdata_t;
/*
@@ -2854,7 +2861,7 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
propstr = "-";
else if (zpool_get_prop(zhp, pl->pl_prop, property,
- sizeof (property), NULL) != 0)
+ sizeof (property), NULL, cb->cb_literal) != 0)
propstr = "-";
else
propstr = property;
@@ -3005,12 +3012,13 @@ list_callback(zpool_handle_t *zhp, void *data)
}
/*
- * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
+ * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
*
* -H Scripted mode. Don't display headers, and separate properties
* by a single tab.
* -o List of properties to display. Defaults to
* "name,size,allocated,free,capacity,health,altroot"
+ * -p Diplay values in parsable (exact) format.
* -T Display a timestamp in date(1) or Unix format
*
* List all pools in the system, whether or not they're healthy. Output space
@@ -3031,7 +3039,7 @@ zpool_do_list(int argc, char **argv)
boolean_t first = B_TRUE;
/* check options */
- while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
+ while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) {
switch (c) {
case 'H':
cb.cb_scripted = B_TRUE;
@@ -3039,6 +3047,9 @@ zpool_do_list(int argc, char **argv)
case 'o':
props = optarg;
break;
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ break;
case 'T':
get_timestamp_arg(*optarg);
break;
@@ -3714,22 +3725,37 @@ zpool_do_reguid(int argc, char **argv)
* zpool reopen <pool>
*
* Reopen the pool so that the kernel can update the sizes of all vdevs.
- *
- * NOTE: This command is currently undocumented. If the command is ever
- * exposed then the appropriate usage() messages will need to be made.
*/
int
zpool_do_reopen(int argc, char **argv)
{
+ int c;
int ret = 0;
zpool_handle_t *zhp;
char *pool;
+ /* check options */
+ while ((c = getopt(argc, argv, "")) != -1) {
+ switch (c) {
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
argc--;
argv++;
- if (argc != 1)
- return (2);
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
pool = argv[0];
if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
@@ -5178,7 +5204,7 @@ get_callback(zpool_handle_t *zhp, void *data)
}
} else {
if (zpool_get_prop(zhp, pl->pl_prop, value,
- sizeof (value), &srctype) != 0)
+ sizeof (value), &srctype, cbp->cb_literal) != 0)
continue;
zprop_print_one_property(zpool_get_name(zhp), cbp,
@@ -5189,20 +5215,32 @@ get_callback(zpool_handle_t *zhp, void *data)
return (0);
}
+/*
+ * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
+ *
+ * -H Scripted mode. Don't display headers, and separate properties
+ * by a single tab.
+ * -o List of columns to display. Defaults to
+ * "name,property,value,source".
+ * -p Diplay values in parsable (exact) format.
+ *
+ * Get properties of pools in the system. Output space statistics
+ * for each one as well as other attributes.
+ */
int
zpool_do_get(int argc, char **argv)
{
zprop_get_cbdata_t cb = { 0 };
zprop_list_t fake_name = { 0 };
int ret;
-
- if (argc < 2) {
- (void) fprintf(stderr, gettext("missing property "
- "argument\n"));
- usage(B_FALSE);
- }
+ int c, i;
+ char *value;
cb.cb_first = B_TRUE;
+
+ /*
+ * Set up default columns and sources.
+ */
cb.cb_sources = ZPROP_SRC_ALL;
cb.cb_columns[0] = GET_COL_NAME;
cb.cb_columns[1] = GET_COL_PROPERTY;
@@ -5210,10 +5248,89 @@ zpool_do_get(int argc, char **argv)
cb.cb_columns[3] = GET_COL_SOURCE;
cb.cb_type = ZFS_TYPE_POOL;
- if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
+ /* check options */
+ while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
+ switch (c) {
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ break;
+ case 'H':
+ cb.cb_scripted = B_TRUE;
+ break;
+ case 'o':
+ bzero(&cb.cb_columns, sizeof (cb.cb_columns));
+ i = 0;
+ while (*optarg != '\0') {
+ static char *col_subopts[] =
+ { "name", "property", "value", "source",
+ "all", NULL };
+
+ if (i == ZFS_GET_NCOLS) {
+ (void) fprintf(stderr, gettext("too "
+ "many fields given to -o "
+ "option\n"));
+ usage(B_FALSE);
+ }
+
+ switch (getsubopt(&optarg, col_subopts,
+ &value)) {
+ case 0:
+ cb.cb_columns[i++] = GET_COL_NAME;
+ break;
+ case 1:
+ cb.cb_columns[i++] = GET_COL_PROPERTY;
+ break;
+ case 2:
+ cb.cb_columns[i++] = GET_COL_VALUE;
+ break;
+ case 3:
+ cb.cb_columns[i++] = GET_COL_SOURCE;
+ break;
+ case 4:
+ if (i > 0) {
+ (void) fprintf(stderr,
+ gettext("\"all\" conflicts "
+ "with specific fields "
+ "given to -o option\n"));
+ usage(B_FALSE);
+ }
+ cb.cb_columns[0] = GET_COL_NAME;
+ cb.cb_columns[1] = GET_COL_PROPERTY;
+ cb.cb_columns[2] = GET_COL_VALUE;
+ cb.cb_columns[3] = GET_COL_SOURCE;
+ i = ZFS_GET_NCOLS;
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid column name "
+ "'%s'\n"), value);
+ usage(B_FALSE);
+ }
+ }
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing property "
+ "argument\n"));
+ usage(B_FALSE);
+ }
+
+ if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
ZFS_TYPE_POOL) != 0)
usage(B_FALSE);
+ argc--;
+ argv++;
+
if (cb.cb_proplist != NULL) {
fake_name.pl_prop = ZPOOL_PROP_NAME;
fake_name.pl_width = strlen(gettext("NAME"));
@@ -5221,7 +5338,7 @@ zpool_do_get(int argc, char **argv)
cb.cb_proplist = &fake_name;
}
- ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
+ ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
get_callback, &cb);
if (cb.cb_proplist == &fake_name)
diff --git a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.1 b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.1
index 6f8ca6e..7158075 100644
--- a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.1
+++ b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.1
@@ -18,10 +18,11 @@
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2013, Delphix. All Rights Reserved.
.\"
.\" $FreeBSD$
.\"
-.Dd November 26, 2011
+.Dd December 31, 2013
.Dt ZSTREAMDUMP 8
.Os
.Sh NAME
@@ -30,6 +31,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl C
+.Op Fl d
.Op Fl v
.Sh DESCRIPTION
The
@@ -43,6 +45,8 @@ The following options are supported:
.Bl -tag -width indent
.It Fl C
Suppress the validation of checksums.
+.It Fl d
+Dump contents of blocks modified, implies verbose.
.It Fl v
Verbose. Dump all headers, not only begin and end headers.
.El
diff --git a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
index df23cc1..f7a4091 100644
--- a/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
+++ b/cddl/contrib/opensolaris/cmd/zstreamdump/zstreamdump.c
@@ -24,6 +24,11 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <ctype.h>
#include <libnvpair.h>
#include <stdio.h>
#include <stdlib.h>
@@ -34,6 +39,16 @@
#include <sys/zfs_ioctl.h>
#include <zfs_fletcher.h>
+/*
+ * If dump mode is enabled, the number of bytes to print per line
+ */
+#define BYTES_PER_LINE 16
+/*
+ * If dump mode is enabled, the number of bytes to group together, separated
+ * by newlines or spaces
+ */
+#define DUMP_GROUPING 4
+
uint64_t drr_record_count[DRR_NUMTYPES];
uint64_t total_write_size = 0;
uint64_t total_stream_len = 0;
@@ -45,9 +60,11 @@ boolean_t do_cksum = B_TRUE;
static void
usage(void)
{
- (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] < file\n");
+ (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n");
(void) fprintf(stderr, "\t -v -- verbose\n");
(void) fprintf(stderr, "\t -C -- suppress checksum verification\n");
+ (void) fprintf(stderr, "\t -d -- dump contents of blocks modified, "
+ "implies verbose\n");
exit(1);
}
@@ -75,6 +92,70 @@ ssread(void *buf, size_t len, zio_cksum_t *cksum)
return (outlen);
}
+/*
+ * Print part of a block in ASCII characters
+ */
+static void
+print_ascii_block(char *subbuf, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ char char_print = isprint(subbuf[i]) ? subbuf[i] : '.';
+ if (i != 0 && i % DUMP_GROUPING == 0) {
+ (void) printf(" ");
+ }
+ (void) printf("%c", char_print);
+ }
+ (void) printf("\n");
+}
+
+/*
+ * print_block - Dump the contents of a modified block to STDOUT
+ *
+ * Assume that buf has capacity evenly divisible by BYTES_PER_LINE
+ */
+static void
+print_block(char *buf, int length)
+{
+ int i;
+ /*
+ * Start printing ASCII characters at a constant offset, after
+ * the hex prints. Leave 3 characters per byte on a line (2 digit
+ * hex number plus 1 space) plus spaces between characters and
+ * groupings
+ */
+ int ascii_start = BYTES_PER_LINE * 3 +
+ BYTES_PER_LINE / DUMP_GROUPING + 2;
+
+ for (i = 0; i < length; i += BYTES_PER_LINE) {
+ int j;
+ int this_line_length = MIN(BYTES_PER_LINE, length - i);
+ int print_offset = 0;
+
+ for (j = 0; j < this_line_length; j++) {
+ int buf_offset = i + j;
+
+ /*
+ * Separate every DUMP_GROUPING bytes by a space.
+ */
+ if (buf_offset % DUMP_GROUPING == 0) {
+ print_offset += printf(" ");
+ }
+
+ /*
+ * Print the two-digit hex value for this byte.
+ */
+ unsigned char hex_print = buf[buf_offset];
+ print_offset += printf("%02x ", hex_print);
+ }
+
+ (void) printf("%*s", ascii_start - print_offset, " ");
+
+ print_ascii_block(buf + i, this_line_length);
+ }
+}
+
int
main(int argc, char *argv[])
{
@@ -92,11 +173,17 @@ main(int argc, char *argv[])
char c;
boolean_t verbose = B_FALSE;
boolean_t first = B_TRUE;
+ /*
+ * dump flag controls whether the contents of any modified data blocks
+ * are printed to the console during processing of the stream. Warning:
+ * for large streams, this can obviously lead to massive prints.
+ */
+ boolean_t dump = B_FALSE;
int err;
zio_cksum_t zc = { 0 };
zio_cksum_t pcksum = { 0 };
- while ((c = getopt(argc, argv, ":vC")) != -1) {
+ while ((c = getopt(argc, argv, ":vCd")) != -1) {
switch (c) {
case 'C':
do_cksum = B_FALSE;
@@ -104,6 +191,10 @@ main(int argc, char *argv[])
case 'v':
verbose = B_TRUE;
break;
+ case 'd':
+ dump = B_TRUE;
+ verbose = B_TRUE;
+ break;
case ':':
(void) fprintf(stderr,
"missing argument for '%c' option\n", optopt);
@@ -128,6 +219,10 @@ main(int argc, char *argv[])
pcksum = zc;
while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) {
+ /*
+ * If this is the first DMU record being processed, check for
+ * the magic bytes and figure out the endian-ness based on them.
+ */
if (first) {
if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
do_byteswap = B_TRUE;
@@ -209,7 +304,7 @@ main(int argc, char *argv[])
nvlist_t *nv;
int sz = drr->drr_payloadlen;
- if (sz > 1<<20) {
+ if (sz > INITIAL_BUFLEN) {
free(buf);
buf = malloc(sz);
}
@@ -283,6 +378,10 @@ main(int argc, char *argv[])
if (drro->drr_bonuslen > 0) {
(void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen,
8), &zc);
+ if (dump) {
+ print_block(buf,
+ P2ROUNDUP(drro->drr_bonuslen, 8));
+ }
}
break;
@@ -312,6 +411,10 @@ main(int argc, char *argv[])
drrw->drr_key.ddk_prop =
BSWAP_64(drrw->drr_key.ddk_prop);
}
+ /*
+ * If this is verbose and/or dump output,
+ * print info on the modified block
+ */
if (verbose) {
(void) printf("WRITE object = %llu type = %u "
"checksum type = %u\n"
@@ -324,7 +427,16 @@ main(int argc, char *argv[])
(u_longlong_t)drrw->drr_length,
(u_longlong_t)drrw->drr_key.ddk_prop);
}
+ /*
+ * Read the contents of the block in from STDIN to buf
+ */
(void) ssread(buf, drrw->drr_length, &zc);
+ /*
+ * If in dump mode
+ */
+ if (dump) {
+ print_block(buf, drrw->drr_length);
+ }
total_write_size += drrw->drr_length;
break;
@@ -390,6 +502,9 @@ main(int argc, char *argv[])
drrs->drr_length);
}
(void) ssread(buf, drrs->drr_length, &zc);
+ if (dump) {
+ print_block(buf, drrs->drr_length);
+ }
break;
}
pcksum = zc;
diff --git a/cddl/contrib/opensolaris/cmd/ztest/ztest.c b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
index b6dcf09..6e028c3 100644
--- a/cddl/contrib/opensolaris/cmd/ztest/ztest.c
+++ b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
@@ -186,7 +186,7 @@ static const ztest_shared_opts_t ztest_opts_defaults = {
extern uint64_t metaslab_gang_bang;
extern uint64_t metaslab_df_alloc_threshold;
-extern uint64_t zfs_deadman_synctime;
+extern uint64_t zfs_deadman_synctime_ms;
static ztest_shared_opts_t *ztest_shared_opts;
static ztest_shared_opts_t ztest_opts;
@@ -5328,10 +5328,10 @@ ztest_deadman_thread(void *arg)
hrtime_t delta, total = 0;
for (;;) {
- delta = (zs->zs_thread_stop - zs->zs_thread_start) /
- NANOSEC + zfs_deadman_synctime;
+ delta = zs->zs_thread_stop - zs->zs_thread_start +
+ MSEC2NSEC(zfs_deadman_synctime_ms);
- (void) poll(NULL, 0, (int)(1000 * delta));
+ (void) poll(NULL, 0, (int)NSEC2MSEC(delta));
/*
* If the pool is suspended then fail immediately. Otherwise,
@@ -5339,15 +5339,15 @@ ztest_deadman_thread(void *arg)
* vdev_deadman() discovers that there hasn't been any recent
* I/Os then it will end up aborting the tests.
*/
- if (spa_suspended(spa)) {
+ if (spa_suspended(spa) || spa->spa_root_vdev == NULL) {
fatal(0, "aborting test after %llu seconds because "
"pool has transitioned to a suspended state.",
- zfs_deadman_synctime);
+ zfs_deadman_synctime_ms / 1000);
return (NULL);
}
vdev_deadman(spa->spa_root_vdev);
- total += zfs_deadman_synctime;
+ total += zfs_deadman_synctime_ms/1000;
(void) printf("ztest has been running for %lld seconds\n",
total);
}
@@ -6080,7 +6080,7 @@ main(int argc, char **argv)
(void) setvbuf(stdout, NULL, _IOLBF, 0);
dprintf_setup(&argc, argv);
- zfs_deadman_synctime = 300;
+ zfs_deadman_synctime_ms = 300000;
ztest_fd_rand = open("/dev/urandom", O_RDONLY);
ASSERT3S(ztest_fd_rand, >=, 0);
diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_create.c b/cddl/contrib/opensolaris/common/ctf/ctf_create.c
index 239d166..7364814 100644
--- a/cddl/contrib/opensolaris/common/ctf/ctf_create.c
+++ b/cddl/contrib/opensolaris/common/ctf/ctf_create.c
@@ -65,7 +65,7 @@ ctf_create(int *errp)
cts.cts_name = _CTF_SECTION;
cts.cts_type = SHT_PROGBITS;
cts.cts_flags = 0;
- cts.cts_data = &hdr;
+ cts.cts_data = (void *)&hdr;
cts.cts_size = sizeof (hdr);
cts.cts_entsize = 1;
cts.cts_offset = 0;
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
index 3b4a38c..bb02d8c 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2013 Voxer Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -144,7 +145,8 @@ dtrace_dof_init(void)
Lmid_t lmid;
#else
u_long lmid = 0;
- dof_sec_t *sec;
+ dof_sec_t *sec, *secstart, *dofstrtab, *dofprobes;
+ dof_provider_t *dofprovider;
size_t i;
#endif
int fd;
@@ -152,14 +154,15 @@ dtrace_dof_init(void)
#if !defined(sun)
Elf *e;
Elf_Scn *scn = NULL;
- Elf_Data *symtabdata = NULL, *dynsymdata = NULL;
+ Elf_Data *symtabdata = NULL, *dynsymdata = NULL, *dofdata = NULL;
+ dof_hdr_t *dof_next = NULL;
GElf_Shdr shdr;
int efd, nprobes;
char *s;
+ char *dofstrtabraw;
size_t shstridx, symtabidx = 0, dynsymidx = 0;
- unsigned char *dofstrtab = NULL;
unsigned char *buf;
- int fixedprobes = 0;
+ int fixedprobes;
#endif
if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
@@ -209,7 +212,8 @@ dtrace_dof_init(void)
} else if (shdr.sh_type == SHT_PROGBITS) {
s = elf_strptr(e, shstridx, shdr.sh_name);
if (s && strcmp(s, ".SUNW_dof") == 0) {
- dof = elf_getdata(scn, NULL)->d_buf;
+ dofdata = elf_getdata(scn, NULL);
+ dof = dofdata->d_buf;
}
}
}
@@ -219,6 +223,10 @@ dtrace_dof_init(void)
close(efd);
return;
}
+
+ while ((char *) dof < (char *) dofdata->d_buf + dofdata->d_size) {
+ fixedprobes = 0;
+ dof_next = (void *) ((char *) dof + dof->dofh_filesz);
#endif
if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
@@ -290,34 +298,49 @@ dtrace_dof_init(void)
* We are assuming the number of probes is less than the number of
* symbols (libc can have 4k symbols, for example).
*/
- sec = (dof_sec_t *)(dof + 1);
+ secstart = sec = (dof_sec_t *)(dof + 1);
buf = (char *)dof;
for (i = 0; i < dof->dofh_secnum; i++, sec++) {
- if (sec->dofs_type == DOF_SECT_STRTAB)
- dofstrtab = (unsigned char *)(buf + sec->dofs_offset);
- else if (sec->dofs_type == DOF_SECT_PROBES && dofstrtab)
+ if (sec->dofs_type != DOF_SECT_PROVIDER)
+ continue;
+
+ dofprovider = (void *) (buf + sec->dofs_offset);
+ dofstrtab = secstart + dofprovider->dofpv_strtab;
+ dofprobes = secstart + dofprovider->dofpv_probes;
+
+ if (dofstrtab->dofs_type != DOF_SECT_STRTAB) {
+ fprintf(stderr, "WARNING: expected STRTAB section, but got %d\n",
+ dofstrtab->dofs_type);
break;
-
- }
- nprobes = sec->dofs_size / sec->dofs_entsize;
- fixsymbol(e, symtabdata, symtabidx, nprobes, buf, sec, &fixedprobes,
- dofstrtab);
- if (fixedprobes != nprobes) {
- /*
- * If we haven't fixed all the probes using the
- * symtab section, look inside the dynsym
- * section.
- */
- fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, sec,
- &fixedprobes, dofstrtab);
- }
- if (fixedprobes != nprobes) {
- fprintf(stderr, "WARNING: number of probes "
- "fixed does not match the number of "
- "defined probes (%d != %d, "
- "respectively)\n", fixedprobes, nprobes);
- fprintf(stderr, "WARNING: some probes might "
- "not fire or your program might crash\n");
+ }
+ if (dofprobes->dofs_type != DOF_SECT_PROBES) {
+ fprintf(stderr, "WARNING: expected PROBES section, but got %d\n",
+ dofprobes->dofs_type);
+ break;
+ }
+
+ dprintf(1, "found provider %p\n", dofprovider);
+ dofstrtabraw = (char *)(buf + dofstrtab->dofs_offset);
+ nprobes = dofprobes->dofs_size / dofprobes->dofs_entsize;
+ fixsymbol(e, symtabdata, symtabidx, nprobes, buf, dofprobes, &fixedprobes,
+ dofstrtabraw);
+ if (fixedprobes != nprobes) {
+ /*
+ * If we haven't fixed all the probes using the
+ * symtab section, look inside the dynsym
+ * section.
+ */
+ fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, dofprobes,
+ &fixedprobes, dofstrtabraw);
+ }
+ if (fixedprobes != nprobes) {
+ fprintf(stderr, "WARNING: number of probes "
+ "fixed does not match the number of "
+ "defined probes (%d != %d, "
+ "respectively)\n", fixedprobes, nprobes);
+ fprintf(stderr, "WARNING: some probes might "
+ "not fire or your program might crash\n");
+ }
}
#endif
if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
@@ -330,7 +353,12 @@ dtrace_dof_init(void)
}
(void) close(fd);
+
#if !defined(sun)
+ /* End of while loop */
+ dof = dof_next;
+ }
+
elf_end(e);
(void) close(efd);
#endif
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
index 01ef0f9..5442683 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -486,7 +487,7 @@ dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
return (0);
}
-static void
+static int
dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
{
dtrace_hdl_t *dtp = ddo->ddo_hdl;
@@ -497,8 +498,12 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
size_t sz;
id_t i;
- if (pvp->pv_flags & DT_PROVIDER_IMPL)
- return; /* ignore providers that are exported by dtrace(7D) */
+ if (pvp->pv_flags & DT_PROVIDER_IMPL) {
+ /*
+ * ignore providers that are exported by dtrace(7D)
+ */
+ return (0);
+ }
nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax);
dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1));
@@ -525,6 +530,9 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
(void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo);
+ if (dt_buf_len(&ddo->ddo_probes) == 0)
+ return (dt_set_errno(dtp, EDT_NOPROBES));
+
dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES,
sizeof (uint64_t), 0, sizeof (dof_probe_t),
dt_buf_len(&ddo->ddo_probes));
@@ -579,6 +587,8 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t),
sizeof (dof_secidx_t) * (nxr + 1));
}
+
+ return (0);
}
static int
@@ -822,8 +832,10 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
*/
if (flags & DTRACE_D_PROBES) {
for (pvp = dt_list_next(&dtp->dt_provlist);
- pvp != NULL; pvp = dt_list_next(pvp))
- dof_add_provider(ddo, pvp);
+ pvp != NULL; pvp = dt_list_next(pvp)) {
+ if (dof_add_provider(ddo, pvp) != 0)
+ return (NULL);
+ }
}
/*
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c
index 66776be..d8dbbabb 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c
@@ -26,6 +26,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <string.h>
@@ -109,7 +110,8 @@ static const struct {
{ EDT_BADSTACKPC, "Invalid stack program counter size" },
{ EDT_BADAGGVAR, "Invalid aggregation variable identifier" },
{ EDT_OVERSION, "Client requested deprecated version of library" },
- { EDT_ENABLING_ERR, "Failed to enable probe" }
+ { EDT_ENABLING_ERR, "Failed to enable probe" },
+ { EDT_NOPROBES, "No probe sites found for declared provider" }
};
static const int _dt_nerr = sizeof (_dt_errlist) / sizeof (_dt_errlist[0]);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
index e4b1db5..2bae220 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
@@ -25,7 +25,7 @@
*/
/*
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
@@ -535,7 +535,8 @@ enum {
EDT_BADSTACKPC, /* invalid stack program counter size */
EDT_BADAGGVAR, /* invalid aggregation variable identifier */
EDT_OVERSION, /* client is requesting deprecated version */
- EDT_ENABLING_ERR /* failed to enable probe */
+ EDT_ENABLING_ERR, /* failed to enable probe */
+ EDT_NOPROBES /* no probes sites for declared provider */
};
/*
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index 2d0428a..f31c600 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -242,8 +242,14 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
/* XXX */
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#elif defined(__powerpc__)
-/* XXX */
-printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
+ /*
+ * Add 4 bytes to hit the low half of this 64-bit
+ * big-endian address.
+ */
+ rel->r_offset = s->dofs_offset +
+ dofr[j].dofr_offset + 4;
+ rel->r_info = ELF32_R_INFO(count + dep->de_global,
+ R_PPC_REL32);
#elif defined(__sparc)
/*
* Add 4 bytes to hit the low half of this 64-bit
@@ -423,7 +429,10 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
#elif defined(__mips__)
/* XXX */
#elif defined(__powerpc__)
-/* XXX */
+ rel->r_offset = s->dofs_offset +
+ dofr[j].dofr_offset;
+ rel->r_info = ELF64_R_INFO(count + dep->de_global,
+ R_PPC64_REL64);
#elif defined(__i386) || defined(__amd64)
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset;
@@ -824,12 +833,84 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
return (0);
}
#elif defined(__powerpc__)
+/* The sentinel is 'xor r3,r3,r3'. */
+#define DT_OP_XOR_R3 0x7c631a78
+
+#define DT_OP_NOP 0x60000000
+#define DT_OP_BLR 0x4e800020
+
+/* This captures all forms of branching to address. */
+#define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000)
+#define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01))
+
/* XXX */
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
uint32_t *off)
{
-printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
+ uint32_t *ip;
+
+ if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0)
+ return (-1);
+
+ /*LINTED*/
+ ip = (uint32_t *)(p + rela->r_offset);
+
+ /*
+ * We only know about some specific relocation types.
+ */
+ if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 &&
+ GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24)
+ return (-1);
+
+ /*
+ * We may have already processed this object file in an earlier linker
+ * invocation. Check to see if the present instruction sequence matches
+ * the one we would install below.
+ */
+ if (isenabled) {
+ if (ip[0] == DT_OP_XOR_R3) {
+ (*off) += sizeof (ip[0]);
+ return (0);
+ }
+ } else {
+ if (ip[0] == DT_OP_NOP) {
+ (*off) += sizeof (ip[0]);
+ return (0);
+ }
+ }
+
+ /*
+ * We only expect branch to address instructions.
+ */
+ if (!DT_IS_BRANCH(ip[0])) {
+ dt_dprintf("found %x instead of a branch instruction at %llx\n",
+ ip[0], (u_longlong_t)rela->r_offset);
+ return (-1);
+ }
+
+ if (isenabled) {
+ /*
+ * It would necessarily indicate incorrect usage if an is-
+ * enabled probe were tail-called so flag that as an error.
+ * It's also potentially (very) tricky to handle gracefully,
+ * but could be done if this were a desired use scenario.
+ */
+ if (!DT_IS_BL(ip[0])) {
+ dt_dprintf("tail call to is-enabled probe at %llx\n",
+ (u_longlong_t)rela->r_offset);
+ return (-1);
+ }
+
+ ip[0] = DT_OP_XOR_R3;
+ (*off) += sizeof (ip[0]);
+ } else {
+ if (DT_IS_BL(ip[0]))
+ ip[0] = DT_OP_NOP;
+ else
+ ip[0] = DT_OP_BLR;
+ }
+
return (0);
}
@@ -1539,10 +1620,17 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
* the executable file as the symbol is going to be
* change from UND to ABS.
*/
- rela.r_offset = 0;
- rela.r_info = 0;
- rela.r_addend = 0;
- (void) gelf_update_rela(data_rel, i, &rela);
+ if (shdr_rel.sh_type == SHT_RELA) {
+ rela.r_offset = 0;
+ rela.r_info = 0;
+ rela.r_addend = 0;
+ (void) gelf_update_rela(data_rel, i, &rela);
+ } else {
+ GElf_Rel rel;
+ rel.r_offset = 0;
+ rel.r_info = 0;
+ (void) gelf_update_rel(data_rel, i, &rel);
+ }
#endif
mod = 1;
@@ -1628,8 +1716,6 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
*/
return (0);
}
- /* XXX Should get a temp file name here. */
- snprintf(tfile, sizeof(tfile), "%s.tmp", file);
#endif
/*
@@ -1704,9 +1790,11 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
"failed to open %s: %s", file, strerror(errno)));
}
#else
- if ((fd = open(tfile, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1)
+ snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
+ if ((fd = mkstemp(tfile)) == -1)
return (dt_link_error(dtp, NULL, -1, NULL,
- "failed to open %s: %s", tfile, strerror(errno)));
+ "failed to create temporary file %s: %s",
+ tfile, strerror(errno)));
#endif
/*
@@ -1749,13 +1837,15 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
status = dump_elf32(dtp, dof, fd);
if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) {
-#else
- /* We don't write the ELF header, just the DOF section */
- if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) {
-#endif
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to write %s: %s", file, strerror(errno)));
}
+#else
+ /* We don't write the ELF header, just the DOF section */
+ if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz)
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to write %s: %s", tfile, strerror(errno)));
+#endif
if (!dtp->dt_lazyload) {
#if defined(sun)
@@ -1783,7 +1873,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
* Arches which default to 64-bit need to explicitly use
* the 32-bit library path.
*/
- int use_32 = !(dtp->dt_oflags & DTRACE_O_LP64);
+ int use_32 = (dtp->dt_oflags & DTRACE_O_ILP32);
#else
/*
* Arches which are 32-bit only just use the normal
@@ -1798,9 +1888,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
drti) + 1;
-#if !defined(sun)
len *= 2;
-#endif
cmd = alloca(len);
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file,
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
index 9c9b2a6..767114e 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
@@ -311,6 +311,10 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "void(@)" },
{ "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "uintptr_t *(void *, size_t)" },
+#if !defined(sun)
+{ "memstr", DT_IDENT_FUNC, 0, DIF_SUBR_MEMSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
+ &dt_idops_func, "string(void *, char, size_t)" },
+#endif
{ "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@)" },
{ "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN,
@@ -483,22 +487,16 @@ static const dt_ident_t _dtrace_globals[] = {
DT_VERS_1_0, &dt_idops_func, "void(...)" },
{ "typeref", DT_IDENT_FUNC, 0, DIF_SUBR_TYPEREF, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "uintptr_t *(void *, size_t, string, size_t)" },
-#if defined(sun)
{ "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
{ "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_type, "uint64_t" },
-#if defined(sun)
{ "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
{ "uid", DT_IDENT_SCALAR, 0, DIF_VAR_UID, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uid_t" },
-#if defined(sun)
{ "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
{ "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_regs, NULL },
{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -506,10 +504,8 @@ static const dt_ident_t _dtrace_globals[] = {
{ "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
DT_ATTR_STABCMN, DT_VERS_1_2,
&dt_idops_type, "uint32_t" },
-#if defined(sun)
{ "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
{ "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint64_t" },
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
index 020df2f..c20d250 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
@@ -906,30 +904,6 @@ dt_options_load(dtrace_hdl_t *dtp)
return (0);
}
-/*ARGSUSED*/
-static int
-dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
-{
- dtrace_optval_t size;
- void *p;
-
- if (arg == NULL || dt_optval_parse(arg, &size) != 0)
- return (dt_set_errno(dtp, EDT_BADOPTVAL));
-
- if (size > SIZE_MAX)
- size = SIZE_MAX;
-
- if ((p = dt_zalloc(dtp, size)) == NULL) {
- do {
- size /= 2;
- } while ((p = dt_zalloc(dtp, size)) == NULL);
- }
-
- dt_free(dtp, p);
-
- return (0);
-}
-
typedef struct dt_option {
const char *o_name;
int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
@@ -968,7 +942,6 @@ static const dt_option_t _dtrace_ctoptions[] = {
{ "linktype", dt_opt_linktype },
{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
{ "pgmax", dt_opt_pgmax },
- { "preallocate", dt_opt_preallocate },
{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
{ "setenv", dt_opt_setenv, 1 },
{ "stdc", dt_opt_stdc },
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
index 24682b2..e4cbd21 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
@@ -694,8 +694,13 @@ static const dt_pfconv_t _dtrace_conversions[] = {
{ "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr },
{ "T", "s", "int64_t", pfcheck_time, pfprint_time822 },
{ "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint },
+#if defined(sun)
{ "wc", "wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
{ "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
+#else
+{ "wc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
+{ "ws", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
+#endif
{ "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint },
{ "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint },
{ "Y", "s", "int64_t", pfcheck_time, pfprint_time },
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
index 87211a2..4429019 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
@@ -734,11 +734,6 @@ dt_zalloc(dtrace_hdl_t *dtp, size_t size)
{
void *data;
- if (size > 16 * 1024 * 1024) {
- (void) dt_set_errno(dtp, EDT_NOMEM);
- return (NULL);
- }
-
if ((data = malloc(size)) == NULL)
(void) dt_set_errno(dtp, EDT_NOMEM);
else
@@ -752,11 +747,6 @@ dt_alloc(dtrace_hdl_t *dtp, size_t size)
{
void *data;
- if (size > 16 * 1024 * 1024) {
- (void) dt_set_errno(dtp, EDT_NOMEM);
- return (NULL);
- }
-
if ((data = malloc(size)) == NULL)
(void) dt_set_errno(dtp, EDT_NOMEM);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
index 1aeb95f..f4b02c9 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
@@ -35,14 +35,26 @@
#include <dt_impl.h>
#include <dt_pid.h>
+#include <libproc_compat.h>
+
/*ARGSUSED*/
int
dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
{
+ ftp->ftps_type = DTFTP_ENTRY;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = 0;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
- dt_dprintf("%s: unimplemented\n", __func__);
- return (DT_PROC_ERR);
+ return (1);
}
int
@@ -50,8 +62,74 @@ dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
{
- dt_dprintf("%s: unimplemented\n", __func__);
- return (DT_PROC_ERR);
+ uintptr_t temp;
+ uint32_t *text;
+ int i;
+ int srdepth = 0;
+
+ if ((text = malloc(symp->st_size + 4)) == NULL) {
+ dt_dprintf("mr sparkle: malloc() failed\n");
+ return (DT_PROC_ERR);
+ }
+
+ if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+ dt_dprintf("mr sparkle: Pread() failed\n");
+ free(text);
+ return (DT_PROC_ERR);
+ }
+
+ /*
+ * Leave a dummy instruction in the last slot to simplify edge
+ * conditions.
+ */
+ text[symp->st_size / 4] = 0;
+
+ ftp->ftps_type = DTFTP_RETURN;
+ ftp->ftps_pc = symp->st_value;
+ ftp->ftps_size = symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ for (i = 0; i < symp->st_size / 4; i++) {
+
+ if ((text[i] & 0xfc000001) != 0x48000000 &&
+ text[i] != 0x4e800020)
+ continue;
+
+ /*
+ * Check for a jump within this function. If it's outside this
+ * function then it's a tail-call, so a return point.
+ */
+ if ((text[i] & 0xfc000000) == 0x48000000) {
+ temp = (text[i] & 0x03fffffc);
+ /* Bit 30 denotes an absolute address. */
+ if (!(text[i] & 0x02)) {
+ temp += symp->st_value + i * 4;
+ }
+ else {
+ /* Sign extend the absolute address. */
+ if (temp & 0x02000000) {
+ temp |= (UINTPTR_MAX - 0x03ffffff);
+ }
+ }
+ if (temp >= symp->st_value &&
+ temp <= (symp->st_value + symp->st_size))
+ continue;
+ }
+ dt_dprintf("return at offset %x\n", i * 4);
+ ftp->ftps_offs[ftp->ftps_noffs++] = i * 4;
+ }
+
+ free(text);
+ if (ftp->ftps_noffs > 0) {
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
+ }
+
+
+ return (ftp->ftps_noffs);
}
/*ARGSUSED*/
@@ -59,9 +137,22 @@ int
dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
{
+ if (off & 0x3)
+ return (DT_PROC_ALIGN);
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 1;
+ ftp->ftps_offs[0] = off;
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
- dt_dprintf("%s: unimplemented\n", __func__);
- return (DT_PROC_ERR);
+ return (1);
}
/*ARGSUSED*/
@@ -69,7 +160,38 @@ int
dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
{
+ ulong_t i;
+
+ ftp->ftps_type = DTFTP_OFFSETS;
+ ftp->ftps_pc = (uintptr_t)symp->st_value;
+ ftp->ftps_size = (size_t)symp->st_size;
+ ftp->ftps_noffs = 0;
+
+ /*
+ * If we're matching against everything, just iterate through each
+ * instruction in the function, otherwise look for matching offset
+ * names by constructing the string and comparing it against the
+ * pattern.
+ */
+ if (strcmp("*", pattern) == 0) {
+ for (i = 0; i < symp->st_size; i += 4) {
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ } else {
+ char name[sizeof (i) * 2 + 1];
+
+ for (i = 0; i < symp->st_size; i += 4) {
+ (void) sprintf(name, "%lx", i);
+ if (gmatch(name, pattern))
+ ftp->ftps_offs[ftp->ftps_noffs++] = i;
+ }
+ }
+
+ if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+ dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+ strerror(errno));
+ return (dt_set_errno(dtp, errno));
+ }
- dt_dprintf("%s: unimplemented\n", __func__);
- return (DT_PROC_ERR);
+ return (ftp->ftps_noffs);
}
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
index 3302ac7..7a265bd 100644
--- a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
+++ b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
@@ -210,7 +210,7 @@ NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")
NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
-NVLIST_PRTFUNC(double, double, double, "0x%llf")
+NVLIST_PRTFUNC(double, double, double, "0x%f")
NVLIST_PRTFUNC(string, char *, char *, "%s")
NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
index 308e920..5e78ece 100644
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
+++ b/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
@@ -128,6 +128,7 @@ uu_avl_pool_destroy(uu_avl_pool_t *pp)
pp->uap_next->uap_prev = pp->uap_prev;
pp->uap_prev->uap_next = pp->uap_next;
(void) pthread_mutex_unlock(&uu_apool_list_lock);
+ (void) pthread_mutex_destroy(&pp->uap_lock);
pp->uap_prev = NULL;
pp->uap_next = NULL;
uu_free(pp);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
index 0a5ca82..24131d6 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
@@ -21,13 +21,13 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _LIBZFS_H
@@ -193,6 +193,7 @@ extern int zpool_log_history(libzfs_handle_t *, const char *);
extern int libzfs_errno(libzfs_handle_t *);
extern const char *libzfs_error_action(libzfs_handle_t *);
extern const char *libzfs_error_description(libzfs_handle_t *);
+extern int zfs_standard_error(libzfs_handle_t *, int, const char *);
extern void libzfs_mnttab_init(libzfs_handle_t *);
extern void libzfs_mnttab_fini(libzfs_handle_t *);
extern void libzfs_mnttab_cache(libzfs_handle_t *, boolean_t);
@@ -269,7 +270,7 @@ extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, const char *);
*/
extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
extern int zpool_get_prop(zpool_handle_t *, zpool_prop_t, char *,
- size_t proplen, zprop_source_t *);
+ size_t proplen, zprop_source_t *, boolean_t);
extern uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t,
zprop_source_t *);
@@ -463,7 +464,8 @@ typedef struct zprop_list {
boolean_t pl_fixed;
} zprop_list_t;
-extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t);
+extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t,
+ boolean_t);
extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *);
#define ZFS_MOUNTPOINT_NONE "none"
@@ -536,6 +538,7 @@ extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_snapshots(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
+extern int zfs_iter_bookmarks(zfs_handle_t *, zfs_iter_f, void *);
typedef struct get_all_cb {
zfs_handle_t **cb_handles;
@@ -610,6 +613,7 @@ typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
extern int zfs_send(zfs_handle_t *, const char *, const char *,
sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
+extern int zfs_send_one(zfs_handle_t *, const char *, int);
extern int zfs_promote(zfs_handle_t *);
extern int zfs_hold(zfs_handle_t *, const char *, const char *,
@@ -679,6 +683,7 @@ extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t);
extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
zfs_type_t);
extern int zfs_spa_version(zfs_handle_t *, int *);
+extern boolean_t zfs_bookmark_exists(const char *path);
/*
* Mount support functions.
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
index e330ad2..11378a2 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
@@ -21,13 +21,14 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include <ctype.h>
@@ -295,7 +296,7 @@ zpool_handle(zfs_handle_t *zhp)
int len;
zpool_handle_t *zph;
- len = strcspn(zhp->zfs_name, "/@") + 1;
+ len = strcspn(zhp->zfs_name, "/@#") + 1;
pool_name = zfs_alloc(zhp->zfs_hdl, len);
(void) strlcpy(pool_name, zhp->zfs_name, len);
@@ -579,6 +580,70 @@ zfs_handle_dup(zfs_handle_t *zhp_orig)
return (zhp);
}
+boolean_t
+zfs_bookmark_exists(const char *path)
+{
+ nvlist_t *bmarks;
+ nvlist_t *props;
+ char fsname[ZFS_MAXNAMELEN];
+ char *bmark_name;
+ char *pound;
+ int err;
+ boolean_t rv;
+
+
+ (void) strlcpy(fsname, path, sizeof (fsname));
+ pound = strchr(fsname, '#');
+ if (pound == NULL)
+ return (B_FALSE);
+
+ *pound = '\0';
+ bmark_name = pound + 1;
+ props = fnvlist_alloc();
+ err = lzc_get_bookmarks(fsname, props, &bmarks);
+ nvlist_free(props);
+ if (err != 0) {
+ nvlist_free(bmarks);
+ return (B_FALSE);
+ }
+
+ rv = nvlist_exists(bmarks, bmark_name);
+ nvlist_free(bmarks);
+ return (rv);
+}
+
+zfs_handle_t *
+make_bookmark_handle(zfs_handle_t *parent, const char *path,
+ nvlist_t *bmark_props)
+{
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ /* Fill in the name. */
+ zhp->zfs_hdl = parent->zfs_hdl;
+ (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+
+ /* Set the property lists. */
+ if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
+ free(zhp);
+ return (NULL);
+ }
+
+ /* Set the types. */
+ zhp->zfs_head_type = parent->zfs_head_type;
+ zhp->zfs_type = ZFS_TYPE_BOOKMARK;
+
+ if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
+ nvlist_free(zhp->zfs_props);
+ free(zhp);
+ return (NULL);
+ }
+
+ return (zhp);
+}
+
/*
* Opens the given snapshot, filesystem, or volume. The 'types'
* argument is a mask of acceptable types. The function will print an
@@ -1846,6 +1911,10 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
case ZFS_PROP_REFQUOTA:
case ZFS_PROP_RESERVATION:
case ZFS_PROP_REFRESERVATION:
+ case ZFS_PROP_FILESYSTEM_LIMIT:
+ case ZFS_PROP_SNAPSHOT_LIMIT:
+ case ZFS_PROP_FILESYSTEM_COUNT:
+ case ZFS_PROP_SNAPSHOT_COUNT:
*val = getprop_uint64(zhp, prop, source);
if (*source == NULL) {
@@ -2173,8 +2242,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
}
if ((zpool_get_prop(zhp->zpool_hdl,
- ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) ||
- (strcmp(root, "-") == 0))
+ ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
+ B_FALSE)) || (strcmp(root, "-") == 0))
root[0] = '\0';
/*
* Special case an alternate root of '/'. This will
@@ -2251,6 +2320,30 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
}
break;
+ case ZFS_PROP_FILESYSTEM_LIMIT:
+ case ZFS_PROP_SNAPSHOT_LIMIT:
+ case ZFS_PROP_FILESYSTEM_COUNT:
+ case ZFS_PROP_SNAPSHOT_COUNT:
+
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
+
+ /*
+ * If limit is UINT64_MAX, we translate this into 'none' (unless
+ * literal is set), and indicate that it's the default value.
+ * Otherwise, we print the number nicely and indicate that it's
+ * set locally.
+ */
+ if (literal) {
+ (void) snprintf(propbuf, proplen, "%llu",
+ (u_longlong_t)val);
+ } else if (val == UINT64_MAX) {
+ (void) strlcpy(propbuf, "none", proplen);
+ } else {
+ zfs_nicenum(val, propbuf, proplen);
+ }
+ break;
+
case ZFS_PROP_REFRATIO:
case ZFS_PROP_COMPRESSRATIO:
if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
@@ -2271,6 +2364,9 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
case ZFS_TYPE_SNAPSHOT:
str = "snapshot";
break;
+ case ZFS_TYPE_BOOKMARK:
+ str = "bookmark";
+ break;
default:
abort();
}
@@ -2477,6 +2573,7 @@ out:
return (err);
#else /* !sun */
assert(!"invalid code path");
+ return (EINVAL); // silence compiler warning
#endif /* !sun */
}
@@ -3133,6 +3230,19 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
{
zfs_cmd_t zc = { 0 };
+ if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
+ nvlist_t *nv = fnvlist_alloc();
+ fnvlist_add_boolean(nv, zhp->zfs_name);
+ int error = lzc_destroy_bookmarks(nv, NULL);
+ fnvlist_free(nv);
+ if (error != 0) {
+ return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+ zhp->zfs_name));
+ }
+ return (0);
+ }
+
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
if (ZFS_IS_VOLUME(zhp)) {
@@ -3515,45 +3625,44 @@ typedef struct rollback_data {
const char *cb_target; /* the snapshot */
uint64_t cb_create; /* creation time reference */
boolean_t cb_error;
- boolean_t cb_dependent;
boolean_t cb_force;
} rollback_data_t;
static int
-rollback_destroy(zfs_handle_t *zhp, void *data)
+rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
{
rollback_data_t *cbp = data;
+ prop_changelist_t *clp;
- if (!cbp->cb_dependent) {
- if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 &&
- zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
- zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
- cbp->cb_create) {
+ /* We must destroy this clone; first unmount it */
+ clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+ cbp->cb_force ? MS_FORCE: 0);
+ if (clp == NULL || changelist_prefix(clp) != 0) {
+ cbp->cb_error = B_TRUE;
+ zfs_close(zhp);
+ return (0);
+ }
+ if (zfs_destroy(zhp, B_FALSE) != 0)
+ cbp->cb_error = B_TRUE;
+ else
+ changelist_remove(clp, zhp->zfs_name);
+ (void) changelist_postfix(clp);
+ changelist_free(clp);
- cbp->cb_dependent = B_TRUE;
- cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
- rollback_destroy, cbp);
- cbp->cb_dependent = B_FALSE;
+ zfs_close(zhp);
+ return (0);
+}
- cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
- }
- } else {
- /* We must destroy this clone; first unmount it */
- prop_changelist_t *clp;
+static int
+rollback_destroy(zfs_handle_t *zhp, void *data)
+{
+ rollback_data_t *cbp = data;
- clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
- cbp->cb_force ? MS_FORCE: 0);
- if (clp == NULL || changelist_prefix(clp) != 0) {
- cbp->cb_error = B_TRUE;
- zfs_close(zhp);
- return (0);
- }
- if (zfs_destroy(zhp, B_FALSE) != 0)
- cbp->cb_error = B_TRUE;
- else
- changelist_remove(clp, zhp->zfs_name);
- (void) changelist_postfix(clp);
- changelist_free(clp);
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
+ cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
+ rollback_destroy_dependent, cbp);
+
+ cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
}
zfs_close(zhp);
@@ -3564,8 +3673,8 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
* Given a dataset, rollback to a specific snapshot, discarding any
* data changes since then and making it the active dataset.
*
- * Any snapshots more recent than the target are destroyed, along with
- * their dependents.
+ * Any snapshots and bookmarks more recent than the target are
+ * destroyed, along with their dependents (i.e. clones).
*/
int
zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
@@ -3585,7 +3694,8 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
cb.cb_force = force;
cb.cb_target = snap->zfs_name;
cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
- (void) zfs_iter_children(zhp, rollback_destroy, &cb);
+ (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb);
+ (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
if (cb.cb_error)
return (-1);
@@ -3882,7 +3992,8 @@ zfs_get_recvd_props(zfs_handle_t *zhp)
* of the RECEIVED column.
*/
int
-zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received)
+zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
+ boolean_t literal)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
zprop_list_t *entry;
@@ -3944,18 +4055,18 @@ zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received)
* Now go through and check the width of any non-fixed columns
*/
for (entry = *plp; entry != NULL; entry = entry->pl_next) {
- if (entry->pl_fixed)
+ if (entry->pl_fixed && !literal)
continue;
if (entry->pl_prop != ZPROP_INVAL) {
if (zfs_prop_get(zhp, entry->pl_prop,
- buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) {
+ buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
if (strlen(buf) > entry->pl_width)
entry->pl_width = strlen(buf);
}
if (received && zfs_prop_get_recvd(zhp,
zfs_prop_to_name(entry->pl_prop),
- buf, sizeof (buf), B_FALSE) == 0)
+ buf, sizeof (buf), literal) == 0)
if (strlen(buf) > entry->pl_recvd_width)
entry->pl_recvd_width = strlen(buf);
} else {
@@ -3968,7 +4079,7 @@ zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received)
}
if (received && zfs_prop_get_recvd(zhp,
entry->pl_user_prop,
- buf, sizeof (buf), B_FALSE) == 0)
+ buf, sizeof (buf), literal) == 0)
if (strlen(buf) > entry->pl_recvd_width)
entry->pl_recvd_width = strlen(buf);
}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
index 11a57a9..481ae52 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
@@ -23,7 +23,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
@@ -191,6 +191,8 @@ int create_parents(libzfs_handle_t *, char *, int);
boolean_t isa_child_of(const char *dataset, const char *parent);
zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
+zfs_handle_t *make_bookmark_handle(zfs_handle_t *, const char *,
+ nvlist_t *props);
int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
index fa3d609..e53a8cd 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
@@ -20,8 +20,8 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -995,10 +995,10 @@ nozpool_all_slices(avl_tree_t *r, const char *sname)
#endif /* sun */
}
+#ifdef sun
static void
check_slices(avl_tree_t *r, int fd, const char *sname)
{
-#ifdef sun
struct extvtoc vtoc;
struct dk_gpt *gpt;
char diskname[MAXNAMELEN];
@@ -1028,8 +1028,8 @@ check_slices(avl_tree_t *r, int fd, const char *sname)
check_one_slice(r, diskname, i, 0, 1);
efi_free(gpt);
}
-#endif /* sun */
}
+#endif /* sun */
static void
zpool_open_func(void *arg)
@@ -1059,6 +1059,7 @@ zpool_open_func(void *arg)
return;
}
/* this file is too small to hold a zpool */
+#ifdef sun
if (S_ISREG(statbuf.st_mode) &&
statbuf.st_size < SPA_MINDEVSIZE) {
(void) close(fd);
@@ -1070,6 +1071,12 @@ zpool_open_func(void *arg)
*/
check_slices(rn->rn_avl, fd, rn->rn_name);
}
+#else /* !sun */
+ if (statbuf.st_size < SPA_MINDEVSIZE) {
+ (void) close(fd);
+ return;
+ }
+#endif /* sun */
if ((zpool_read_label(fd, &config)) != 0) {
(void) close(fd);
@@ -1606,9 +1613,16 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,
* its state to active.
*/
if (pool_active(hdl, name, guid, &isactive) == 0 && isactive &&
- (zhp = zpool_open_canfail(hdl, name)) != NULL &&
- zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
- stateval = POOL_STATE_ACTIVE;
+ (zhp = zpool_open_canfail(hdl, name)) != NULL) {
+ if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
+ stateval = POOL_STATE_ACTIVE;
+
+ /*
+ * All we needed the zpool handle for is the
+ * readonly prop check.
+ */
+ zpool_close(zhp);
+ }
ret = B_TRUE;
break;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
index 259d045..9698a72 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
@@ -146,7 +146,8 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
zfs_handle_t *nzhp;
int ret;
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
+ zhp->zfs_type == ZFS_TYPE_BOOKMARK)
return (0);
zc.zc_simple = simple;
@@ -173,6 +174,59 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
}
/*
+ * Iterate over all bookmarks
+ */
+int
+zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ zfs_handle_t *nzhp;
+ nvlist_t *props = NULL;
+ nvlist_t *bmarks = NULL;
+ int err;
+
+ if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0)
+ return (0);
+
+ /* Setup the requested properties nvlist. */
+ props = fnvlist_alloc();
+ fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
+ fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
+ fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));
+
+ /* Allocate an nvlist to hold the bookmarks. */
+ bmarks = fnvlist_alloc();
+
+ if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
+ goto out;
+
+ for (nvpair_t *pair = nvlist_next_nvpair(bmarks, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
+ char name[ZFS_MAXNAMELEN];
+ char *bmark_name;
+ nvlist_t *bmark_props;
+
+ bmark_name = nvpair_name(pair);
+ bmark_props = fnvpair_value_nvlist(pair);
+
+ (void) snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name,
+ bmark_name);
+
+ nzhp = make_bookmark_handle(zhp, name, bmark_props);
+ if (nzhp == NULL)
+ continue;
+
+ if ((err = func(nzhp, data)) != 0)
+ goto out;
+ }
+
+out:
+ fnvlist_free(props);
+ fnvlist_free(bmarks);
+
+ return (err);
+}
+
+/*
* Routines for dealing with the sorted snapshot functionality
*/
typedef struct zfs_node {
@@ -406,13 +460,13 @@ static int
iter_dependents_cb(zfs_handle_t *zhp, void *arg)
{
iter_dependents_arg_t *ida = arg;
- int err;
+ int err = 0;
boolean_t first = ida->first;
ida->first = B_FALSE;
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
- } else {
+ } else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
iter_stack_frame_t isf;
iter_stack_frame_t *f;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
index df8317f..8dd24a7 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -240,7 +240,7 @@ zpool_pool_state_to_name(pool_state_t state)
*/
int
zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
- zprop_source_t *srctype)
+ zprop_source_t *srctype, boolean_t literal)
{
uint64_t intval;
const char *strval;
@@ -272,9 +272,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
(void) strlcpy(buf,
zpool_get_prop_string(zhp, prop, &src),
len);
- if (srctype != NULL)
- *srctype = src;
- return (0);
+ break;
}
/* FALLTHROUGH */
default:
@@ -306,12 +304,22 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
case ZPOOL_PROP_FREE:
case ZPOOL_PROP_FREEING:
case ZPOOL_PROP_EXPANDSZ:
- (void) zfs_nicenum(intval, buf, len);
+ if (literal) {
+ (void) snprintf(buf, len, "%llu",
+ (u_longlong_t)intval);
+ } else {
+ (void) zfs_nicenum(intval, buf, len);
+ }
break;
case ZPOOL_PROP_CAPACITY:
- (void) snprintf(buf, len, "%llu%%",
- (u_longlong_t)intval);
+ if (literal) {
+ (void) snprintf(buf, len, "%llu",
+ (u_longlong_t)intval);
+ } else {
+ (void) snprintf(buf, len, "%llu%%",
+ (u_longlong_t)intval);
+ }
break;
case ZPOOL_PROP_DEDUPRATIO:
@@ -407,7 +415,7 @@ zpool_is_bootable(zpool_handle_t *zhp)
char bootfs[ZPOOL_MAXNAMELEN];
return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
- sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-",
+ sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
sizeof (bootfs)) != 0);
}
@@ -443,10 +451,9 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
prop = zpool_name_to_prop(propname);
if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
int err;
- zfeature_info_t *feature;
char *fname = strchr(propname, '@') + 1;
- err = zfeature_lookup_name(fname, &feature);
+ err = zfeature_lookup_name(fname, NULL);
if (err != 0) {
ASSERT3U(err, ==, ENOENT);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -807,7 +814,7 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
if (entry->pl_prop != ZPROP_INVAL &&
zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
- NULL) == 0) {
+ NULL, B_FALSE) == 0) {
if (strlen(buf) > entry->pl_width)
entry->pl_width = strlen(buf);
}
@@ -839,14 +846,14 @@ zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
*/
if (supported) {
int ret;
- zfeature_info_t *fi;
+ spa_feature_t fid;
- ret = zfeature_lookup_name(feature, &fi);
+ ret = zfeature_lookup_name(feature, &fid);
if (ret != 0) {
(void) strlcpy(buf, "-", len);
return (ENOTSUP);
}
- feature = fi->fi_guid;
+ feature = spa_feature_table[fid].fi_guid;
}
if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
@@ -3737,7 +3744,9 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
return (0);
}
-#define HIS_BUF_LEN (128*1024)
+/* from spa_history.c: spa_history_create_obj() */
+#define HIS_BUF_LEN_DEF (128 << 10)
+#define HIS_BUF_LEN_MAX (1 << 30)
/*
* Retrieve the command history of a pool.
@@ -3745,21 +3754,24 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
int
zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
{
- char buf[HIS_BUF_LEN];
+ char *buf = NULL;
+ uint64_t bufsize = HIS_BUF_LEN_DEF;
uint64_t off = 0;
nvlist_t **records = NULL;
uint_t numrecords = 0;
int err, i;
+ if ((buf = malloc(bufsize)) == NULL)
+ return (ENOMEM);
do {
- uint64_t bytes_read = sizeof (buf);
+ uint64_t bytes_read = bufsize;
uint64_t leftover;
if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
break;
/* if nothing else was read in, we're at EOF, just return */
- if (!bytes_read)
+ if (bytes_read == 0)
break;
if ((err = zpool_history_unpack(buf, bytes_read,
@@ -3767,8 +3779,25 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
break;
off -= leftover;
+ /*
+ * If the history block is too big, double the buffer
+ * size and try again.
+ */
+ if (leftover == bytes_read) {
+ free(buf);
+ buf = NULL;
+
+ bufsize <<= 1;
+ if ((bufsize >= HIS_BUF_LEN_MAX) ||
+ ((buf = malloc(bufsize)) == NULL)) {
+ err = ENOMEM;
+ break;
+ }
+ }
+
/* CONSTCOND */
} while (1);
+ free(buf);
if (!err) {
verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
index 1fc46c2..feddb69 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
@@ -1619,6 +1619,62 @@ err_out:
return (err);
}
+int
+zfs_send_one(zfs_handle_t *zhp, const char *from, int fd)
+{
+ int err;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot send '%s'"), zhp->zfs_name);
+
+ err = lzc_send(zhp->zfs_name, from, fd);
+ if (err != 0) {
+ switch (errno) {
+ case EXDEV:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not an earlier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+ case ENOENT:
+ case ESRCH:
+ if (lzc_exists(zhp->zfs_name)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source (%s) does not exist"),
+ from);
+ }
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "target is busy; if a filesystem, "
+ "it must not be mounted"));
+ return (zfs_error(hdl, EZFS_BUSY, errbuf));
+
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+#ifdef illumos
+ case ENOSTR:
+#endif
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+ }
+ return (err != 0);
+}
+
/*
* Routines specific to "zfs recv"
*/
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
index 6823c07..3b59914 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
@@ -1268,6 +1269,16 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,
"use 'none' to disable quota/refquota"));
goto error;
}
+
+ /*
+ * Special handling for "*_limit=none". In this case it's not
+ * 0 but UINT64_MAX.
+ */
+ if ((type & ZFS_TYPE_DATASET) && isnone &&
+ (prop == ZFS_PROP_FILESYSTEM_LIMIT ||
+ prop == ZFS_PROP_SNAPSHOT_LIMIT)) {
+ *ivalp = UINT64_MAX;
+ }
break;
case PROP_TYPE_INDEX:
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
index 6f4b46c..1c87223 100644
--- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
@@ -486,18 +486,30 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp)
}
/*
- * If fromsnap is NULL, a full (non-incremental) stream will be sent.
+ *
+ * "snapname" is the full name of the snapshot to send (e.g. "pool/fs@snap")
+ *
+ * If "from" is NULL, a full (non-incremental) stream will be sent.
+ * If "from" is non-NULL, it must be the full name of a snapshot or
+ * bookmark to send an incremental from (e.g. "pool/fs@earlier_snap" or
+ * "pool/fs#earlier_bmark"). If non-NULL, the specified snapshot or
+ * bookmark must represent an earlier point in the history of "snapname").
+ * It can be an earlier snapshot in the same filesystem or zvol as "snapname",
+ * or it can be the origin of "snapname"'s filesystem, or an earlier
+ * snapshot in the origin, etc.
+ *
+ * "fd" is the file descriptor to write the send stream to.
*/
int
-lzc_send(const char *snapname, const char *fromsnap, int fd)
+lzc_send(const char *snapname, const char *from, int fd)
{
nvlist_t *args;
int err;
args = fnvlist_alloc();
fnvlist_add_int32(args, "fd", fd);
- if (fromsnap != NULL)
- fnvlist_add_string(args, "fromsnap", fromsnap);
+ if (from != NULL)
+ fnvlist_add_string(args, "fromsnap", from);
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
nvlist_free(args);
return (err);
@@ -652,3 +664,97 @@ lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen)
}
return (err);
}
+
+/*
+ * Creates bookmarks.
+ *
+ * The bookmarks nvlist maps from name of the bookmark (e.g. "pool/fs#bmark") to
+ * the name of the snapshot (e.g. "pool/fs@snap"). All the bookmarks and
+ * snapshots must be in the same pool.
+ *
+ * The returned results nvlist will have an entry for each bookmark that failed.
+ * The value will be the (int32) error code.
+ *
+ * The return value will be 0 if all bookmarks were created, otherwise it will
+ * be the errno of a (undetermined) bookmarks that failed.
+ */
+int
+lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist)
+{
+ nvpair_t *elem;
+ int error;
+ char pool[MAXNAMELEN];
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(bookmarks, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/#")] = '\0';
+
+ error = lzc_ioctl(ZFS_IOC_BOOKMARK, pool, bookmarks, errlist);
+
+ return (error);
+}
+
+/*
+ * Retrieve bookmarks.
+ *
+ * Retrieve the list of bookmarks for the given file system. The props
+ * parameter is an nvlist of property names (with no values) that will be
+ * returned for each bookmark.
+ *
+ * The following are valid properties on bookmarks, all of which are numbers
+ * (represented as uint64 in the nvlist)
+ *
+ * "guid" - globally unique identifier of the snapshot it refers to
+ * "createtxg" - txg when the snapshot it refers to was created
+ * "creation" - timestamp when the snapshot it refers to was created
+ *
+ * The format of the returned nvlist as follows:
+ * <short name of bookmark> -> {
+ * <name of property> -> {
+ * "value" -> uint64
+ * }
+ * }
+ */
+int
+lzc_get_bookmarks(const char *fsname, nvlist_t *props, nvlist_t **bmarks)
+{
+ return (lzc_ioctl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks));
+}
+
+/*
+ * Destroys bookmarks.
+ *
+ * The keys in the bmarks nvlist are the bookmarks to be destroyed.
+ * They must all be in the same pool. Bookmarks are specified as
+ * <fs>#<bmark>.
+ *
+ * Bookmarks that do not exist will be silently ignored.
+ *
+ * The return value will be 0 if all bookmarks that existed were destroyed.
+ *
+ * Otherwise the return value will be the errno of a (undetermined) bookmark
+ * that failed, no bookmarks will be destroyed, and the errlist will have an
+ * entry for each bookmarks that failed. The value in the errlist will be
+ * the (int32) error code.
+ */
+int
+lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist)
+{
+ nvpair_t *elem;
+ int error;
+ char pool[MAXNAMELEN];
+
+ /* determine the pool name */
+ elem = nvlist_next_nvpair(bmarks, NULL);
+ if (elem == NULL)
+ return (0);
+ (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+ pool[strcspn(pool, "/#")] = '\0';
+
+ error = lzc_ioctl(ZFS_IOC_DESTROY_BOOKMARKS, pool, bmarks, errlist);
+
+ return (error);
+}
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
index c55caf4..380560f 100644
--- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
@@ -39,27 +39,27 @@ extern "C" {
int libzfs_core_init(void);
void libzfs_core_fini(void);
-int lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist);
-int lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props);
-int lzc_clone(const char *fsname, const char *origin, nvlist_t *props);
-int lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist);
+int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
+int lzc_create(const char *, dmu_objset_type_t, nvlist_t *);
+int lzc_clone(const char *, const char *, nvlist_t *);
+int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
+int lzc_bookmark(nvlist_t *, nvlist_t **);
+int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **);
+int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **);
-int lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
- uint64_t *usedp);
+int lzc_snaprange_space(const char *, const char *, uint64_t *);
-int lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist);
-int lzc_release(nvlist_t *holds, nvlist_t **errlist);
-int lzc_get_holds(const char *snapname, nvlist_t **holdsp);
+int lzc_hold(nvlist_t *, int, nvlist_t **);
+int lzc_release(nvlist_t *, nvlist_t **);
+int lzc_get_holds(const char *, nvlist_t **);
-int lzc_send(const char *snapname, const char *fromsnap, int fd);
-int lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
- boolean_t force, int fd);
-int lzc_send_space(const char *snapname, const char *fromsnap,
- uint64_t *result);
+int lzc_send(const char *, const char *, int);
+int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
+int lzc_send_space(const char *, const char *, uint64_t *);
-boolean_t lzc_exists(const char *dataset);
+boolean_t lzc_exists(const char *);
-int lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen);
+int lzc_rollback(const char *, char *, int);
#ifdef __cplusplus
}
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
index c4e2d2e..2b174f9 100644
--- a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
@@ -20,6 +20,8 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <assert.h>
@@ -661,7 +663,7 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
if (dprintf_find_string("pid"))
(void) printf("%d ", getpid());
if (dprintf_find_string("tid"))
- (void) printf("%u ", thr_self());
+ (void) printf("%ul ", thr_self());
#if 0
if (dprintf_find_string("cpu"))
(void) printf("%u ", getcpuid());
@@ -800,20 +802,17 @@ delay(clock_t ticks)
/*
* Find highest one bit set.
* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
- * High order bit is 31 (or 63 in _LP64 kernel).
*/
int
-highbit(ulong_t i)
+highbit64(uint64_t i)
{
- register int h = 1;
+ int h = 1;
if (i == 0)
return (0);
-#ifdef _LP64
- if (i & 0xffffffff00000000ul) {
+ if (i & 0xffffffff00000000ULL) {
h += 32; i >>= 32;
}
-#endif
if (i & 0xffff0000) {
h += 16; i >>= 16;
}
@@ -1125,3 +1124,50 @@ zvol_create_minors(const char *name)
return (0);
}
#endif
+
+#ifdef illumos
+void
+bioinit(buf_t *bp)
+{
+ bzero(bp, sizeof (buf_t));
+}
+
+void
+biodone(buf_t *bp)
+{
+ if (bp->b_iodone != NULL) {
+ (*(bp->b_iodone))(bp);
+ return;
+ }
+ ASSERT((bp->b_flags & B_DONE) == 0);
+ bp->b_flags |= B_DONE;
+}
+
+void
+bioerror(buf_t *bp, int error)
+{
+ ASSERT(bp != NULL);
+ ASSERT(error >= 0);
+
+ if (error != 0) {
+ bp->b_flags |= B_ERROR;
+ } else {
+ bp->b_flags &= ~B_ERROR;
+ }
+ bp->b_error = error;
+}
+
+
+int
+geterror(struct buf *bp)
+{
+ int error = 0;
+
+ if (bp->b_flags & B_ERROR) {
+ error = bp->b_error;
+ if (!error)
+ error = EIO;
+ }
+ return (error);
+}
+#endif
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
index 15c181e..cc8285d 100644
--- a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
@@ -20,9 +20,12 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
#ifndef _SYS_ZFS_CONTEXT_H
#define _SYS_ZFS_CONTEXT_H
@@ -62,6 +65,7 @@ extern "C" {
#include <inttypes.h>
#include <fsshare.h>
#include <pthread.h>
+#include <sched.h>
#include <sys/debug.h>
#include <sys/note.h>
#include <sys/types.h>
@@ -201,6 +205,8 @@ extern int aok;
*/
#define curthread ((void *)(uintptr_t)thr_self())
+#define kpreempt(x) sched_yield()
+
typedef struct kthread kthread_t;
#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \
@@ -367,6 +373,16 @@ typedef struct taskq taskq_t;
typedef uintptr_t taskqid_t;
typedef void (task_func_t)(void *);
+typedef struct taskq_ent {
+ struct taskq_ent *tqent_next;
+ struct taskq_ent *tqent_prev;
+ task_func_t *tqent_func;
+ void *tqent_arg;
+ uintptr_t tqent_flags;
+} taskq_ent_t;
+
+#define TQENT_FLAG_PREALLOC 0x1 /* taskq_dispatch_ent used */
+
#define TASKQ_PREPOPULATE 0x0001
#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
@@ -378,6 +394,7 @@ typedef void (task_func_t)(void *);
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
#define TQ_FRONT 0x08 /* Queue in front */
+
extern taskq_t *system_taskq;
extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
@@ -386,6 +403,8 @@ extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
#define taskq_create_sysdc(a, b, d, e, p, dc, f) \
(taskq_create(a, b, maxclsyspri, d, e, f))
extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
+extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
+ taskq_ent_t *);
extern void taskq_destroy(taskq_t *);
extern void taskq_wait(taskq_t *);
extern int taskq_member(taskq_t *, void *);
@@ -539,7 +558,7 @@ extern void delay(clock_t ticks);
extern uint64_t physmem;
-extern int highbit(ulong_t i);
+extern int highbit64(uint64_t i);
extern int random_get_bytes(uint8_t *ptr, size_t len);
extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
@@ -759,6 +778,38 @@ extern void cyclic_remove(cyclic_id_t);
extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
#endif /* illumos */
+#ifdef illumos
+/*
+ * Buf structure
+ */
+#define B_BUSY 0x0001
+#define B_DONE 0x0002
+#define B_ERROR 0x0004
+#define B_READ 0x0040 /* read when I/O occurs */
+#define B_WRITE 0x0100 /* non-read pseudo-flag */
+
+typedef struct buf {
+ int b_flags;
+ size_t b_bcount;
+ union {
+ caddr_t b_addr;
+ } b_un;
+
+ lldaddr_t _b_blkno;
+#define b_lblkno _b_blkno._f
+ size_t b_resid;
+ size_t b_bufsize;
+ int (*b_iodone)(struct buf *);
+ int b_error;
+ void *b_private;
+} buf_t;
+
+extern void bioinit(buf_t *);
+extern void biodone(buf_t *);
+extern void bioerror(buf_t *, int);
+extern int geterror(buf_t *);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c b/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c
index c407bba..d4036d0 100644
--- a/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c
@@ -22,19 +22,15 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
#include <sys/zfs_context.h>
int taskq_now;
taskq_t *system_taskq;
-typedef struct task {
- struct task *task_next;
- struct task *task_prev;
- task_func_t *task_func;
- void *task_arg;
-} task_t;
-
#define TASKQ_ACTIVE 0x00010000
struct taskq {
@@ -51,18 +47,18 @@ struct taskq {
int tq_maxalloc;
kcondvar_t tq_maxalloc_cv;
int tq_maxalloc_wait;
- task_t *tq_freelist;
- task_t tq_task;
+ taskq_ent_t *tq_freelist;
+ taskq_ent_t tq_task;
};
-static task_t *
+static taskq_ent_t *
task_alloc(taskq_t *tq, int tqflags)
{
- task_t *t;
+ taskq_ent_t *t;
int rv;
again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
- tq->tq_freelist = t->task_next;
+ tq->tq_freelist = t->tqent_next;
} else {
if (tq->tq_nalloc >= tq->tq_maxalloc) {
if (!(tqflags & KM_SLEEP))
@@ -87,7 +83,7 @@ again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
}
mutex_exit(&tq->tq_lock);
- t = kmem_alloc(sizeof (task_t), tqflags & KM_SLEEP);
+ t = kmem_alloc(sizeof (taskq_ent_t), tqflags & KM_SLEEP);
mutex_enter(&tq->tq_lock);
if (t != NULL)
@@ -97,15 +93,15 @@ again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
}
static void
-task_free(taskq_t *tq, task_t *t)
+task_free(taskq_t *tq, taskq_ent_t *t)
{
if (tq->tq_nalloc <= tq->tq_minalloc) {
- t->task_next = tq->tq_freelist;
+ t->tqent_next = tq->tq_freelist;
tq->tq_freelist = t;
} else {
tq->tq_nalloc--;
mutex_exit(&tq->tq_lock);
- kmem_free(t, sizeof (task_t));
+ kmem_free(t, sizeof (taskq_ent_t));
mutex_enter(&tq->tq_lock);
}
@@ -116,7 +112,7 @@ task_free(taskq_t *tq, task_t *t)
taskqid_t
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
{
- task_t *t;
+ taskq_ent_t *t;
if (taskq_now) {
func(arg);
@@ -130,26 +126,58 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
return (0);
}
if (tqflags & TQ_FRONT) {
- t->task_next = tq->tq_task.task_next;
- t->task_prev = &tq->tq_task;
+ t->tqent_next = tq->tq_task.tqent_next;
+ t->tqent_prev = &tq->tq_task;
} else {
- t->task_next = &tq->tq_task;
- t->task_prev = tq->tq_task.task_prev;
+ t->tqent_next = &tq->tq_task;
+ t->tqent_prev = tq->tq_task.tqent_prev;
}
- t->task_next->task_prev = t;
- t->task_prev->task_next = t;
- t->task_func = func;
- t->task_arg = arg;
+ t->tqent_next->tqent_prev = t;
+ t->tqent_prev->tqent_next = t;
+ t->tqent_func = func;
+ t->tqent_arg = arg;
cv_signal(&tq->tq_dispatch_cv);
mutex_exit(&tq->tq_lock);
return (1);
}
void
+taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
+ taskq_ent_t *t)
+{
+ ASSERT(func != NULL);
+ ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
+
+ /*
+ * Mark it as a prealloc'd task. This is important
+ * to ensure that we don't free it later.
+ */
+ t->tqent_flags |= TQENT_FLAG_PREALLOC;
+ /*
+ * Enqueue the task to the underlying queue.
+ */
+ mutex_enter(&tq->tq_lock);
+
+ if (flags & TQ_FRONT) {
+ t->tqent_next = tq->tq_task.tqent_next;
+ t->tqent_prev = &tq->tq_task;
+ } else {
+ t->tqent_next = &tq->tq_task;
+ t->tqent_prev = tq->tq_task.tqent_prev;
+ }
+ t->tqent_next->tqent_prev = t;
+ t->tqent_prev->tqent_next = t;
+ t->tqent_func = func;
+ t->tqent_arg = arg;
+ cv_signal(&tq->tq_dispatch_cv);
+ mutex_exit(&tq->tq_lock);
+}
+
+void
taskq_wait(taskq_t *tq)
{
mutex_enter(&tq->tq_lock);
- while (tq->tq_task.task_next != &tq->tq_task || tq->tq_active != 0)
+ while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
mutex_exit(&tq->tq_lock);
}
@@ -158,27 +186,32 @@ static void *
taskq_thread(void *arg)
{
taskq_t *tq = arg;
- task_t *t;
+ taskq_ent_t *t;
+ boolean_t prealloc;
mutex_enter(&tq->tq_lock);
while (tq->tq_flags & TASKQ_ACTIVE) {
- if ((t = tq->tq_task.task_next) == &tq->tq_task) {
+ if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
if (--tq->tq_active == 0)
cv_broadcast(&tq->tq_wait_cv);
cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
tq->tq_active++;
continue;
}
- t->task_prev->task_next = t->task_next;
- t->task_next->task_prev = t->task_prev;
+ t->tqent_prev->tqent_next = t->tqent_next;
+ t->tqent_next->tqent_prev = t->tqent_prev;
+ t->tqent_next = NULL;
+ t->tqent_prev = NULL;
+ prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
mutex_exit(&tq->tq_lock);
rw_enter(&tq->tq_threadlock, RW_READER);
- t->task_func(t->task_arg);
+ t->tqent_func(t->tqent_arg);
rw_exit(&tq->tq_threadlock);
mutex_enter(&tq->tq_lock);
- task_free(tq, t);
+ if (!prealloc)
+ task_free(tq, t);
}
tq->tq_nthreads--;
cv_broadcast(&tq->tq_wait_cv);
@@ -217,8 +250,8 @@ taskq_create(const char *name, int nthreads, pri_t pri,
tq->tq_nthreads = nthreads;
tq->tq_minalloc = minalloc;
tq->tq_maxalloc = maxalloc;
- tq->tq_task.task_next = &tq->tq_task;
- tq->tq_task.task_prev = &tq->tq_task;
+ tq->tq_task.tqent_next = &tq->tq_task;
+ tq->tq_task.tqent_prev = &tq->tq_task;
tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
if (flags & TASKQ_PREPOPULATE) {
diff --git a/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py b/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
index fa8209f..7ad4b49 100644
--- a/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
+++ b/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
@@ -20,6 +20,7 @@
# CDDL HEADER END
#
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013 by Delphix. All rights reserved.
#
"""This module implements the "zfs allow" and "zfs unallow" subcommands.
@@ -219,6 +220,7 @@ perms_subcmd = dict(
hold=_("Allows adding a user hold to a snapshot"),
release=_("Allows releasing a user hold which\n\t\t\t\tmight destroy the snapshot"),
diff=_("Allows lookup of paths within a dataset,\n\t\t\t\tgiven an object number. Ordinary users need this\n\t\t\t\tin order to use zfs diff"),
+ bookmark="",
)
perms_other = dict(
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
index 0738dd0..55ce7b2 100644
--- a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
@@ -96,9 +96,6 @@
#include "list.h"
#include "traverse.h"
-/* The version of DWARF which we support. */
-#define DWARF_VERSION 2
-
/*
* We need to define a couple of our own intrinsics, to smooth out some of the
* differences between the GCC and DevPro DWARF emitters. See the referenced
@@ -271,7 +268,7 @@ die_off(dwarf_t *dw, Dwarf_Die die)
return (off);
terminate("failed to get offset for die: %s\n",
- dwarf_errmsg(&dw->dw_err));
+ dwarf_errmsg(dw->dw_err));
/*NOTREACHED*/
return (0);
}
@@ -289,7 +286,7 @@ die_sibling(dwarf_t *dw, Dwarf_Die die)
return (NULL);
terminate("die %llu: failed to find type sibling: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
/*NOTREACHED*/
return (NULL);
}
@@ -306,7 +303,7 @@ die_child(dwarf_t *dw, Dwarf_Die die)
return (NULL);
terminate("die %llu: failed to find type child: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
/*NOTREACHED*/
return (NULL);
}
@@ -320,7 +317,7 @@ die_tag(dwarf_t *dw, Dwarf_Die die)
return (tag);
terminate("die %llu: failed to get tag for type: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
/*NOTREACHED*/
return (0);
}
@@ -343,7 +340,7 @@ die_attr(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, int req)
}
terminate("die %llu: failed to get attribute for type: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
/*NOTREACHED*/
return (NULL);
}
@@ -353,10 +350,10 @@ die_signed(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Signed *valp,
int req)
{
*valp = 0;
- if (dwarf_attrval_signed(die, name, valp, &dw->dw_err) != DWARF_E_NONE) {
+ if (dwarf_attrval_signed(die, name, valp, &dw->dw_err) != DW_DLV_OK) {
if (req)
terminate("die %llu: failed to get signed: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
return (0);
}
@@ -368,10 +365,10 @@ die_unsigned(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Unsigned *valp,
int req)
{
*valp = 0;
- if (dwarf_attrval_unsigned(die, name, valp, &dw->dw_err) != DWARF_E_NONE) {
+ if (dwarf_attrval_unsigned(die, name, valp, &dw->dw_err) != DW_DLV_OK) {
if (req)
terminate("die %llu: failed to get unsigned: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
return (0);
}
@@ -383,10 +380,10 @@ die_bool(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Bool *valp, int req)
{
*valp = 0;
- if (dwarf_attrval_flag(die, name, valp, &dw->dw_err) != DWARF_E_NONE) {
+ if (dwarf_attrval_flag(die, name, valp, &dw->dw_err) != DW_DLV_OK) {
if (req)
terminate("die %llu: failed to get flag: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
return (0);
}
@@ -398,11 +395,11 @@ die_string(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, char **strp, int req)
{
const char *str = NULL;
- if (dwarf_attrval_string(die, name, &str, &dw->dw_err) != DWARF_E_NONE ||
+ if (dwarf_attrval_string(die, name, &str, &dw->dw_err) != DW_DLV_OK ||
str == NULL) {
if (req)
terminate("die %llu: failed to get string: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
else
*strp = NULL;
return (0);
@@ -417,9 +414,9 @@ die_attr_ref(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name)
{
Dwarf_Off off;
- if (dwarf_attrval_unsigned(die, name, &off, &dw->dw_err) != DWARF_E_NONE) {
+ if (dwarf_attrval_unsigned(die, name, &off, &dw->dw_err) != DW_DLV_OK) {
terminate("die %llu: failed to get ref: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ die_off(dw, die), dwarf_errmsg(dw->dw_err));
}
return (off);
@@ -431,6 +428,8 @@ die_name(dwarf_t *dw, Dwarf_Die die)
char *str = NULL;
(void) die_string(dw, die, DW_AT_name, &str, 0);
+ if (str == NULL)
+ str = xstrdup("");
return (str);
}
@@ -489,21 +488,73 @@ die_mem_offset(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name,
{
Dwarf_Locdesc *loc = NULL;
Dwarf_Signed locnum = 0;
+ Dwarf_Attribute at;
+ Dwarf_Half form;
+
+ if (name != DW_AT_data_member_location)
+ terminate("die %llu: can only process attribute "
+ "DW_AT_data_member_location\n", die_off(dw, die));
- if (dwarf_locdesc(die, name, &loc, &locnum, &dw->dw_err) != DW_DLV_OK)
+ if ((at = die_attr(dw, die, name, 0)) == NULL)
return (0);
- if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
- terminate("die %llu: cannot parse member offset\n",
- die_off(dw, die));
- }
+ if (dwarf_whatform(at, &form, &dw->dw_err) != DW_DLV_OK)
+ return (0);
+
+ switch (form) {
+ case DW_FORM_sec_offset:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ /*
+ * GCC in base and Clang (3.3 or below) generates
+ * DW_AT_data_member_location attribute with DW_FORM_block*
+ * form. The attribute contains one DW_OP_plus_uconst
+ * operator. The member offset stores in the operand.
+ */
+ if (dwarf_loclist(at, &loc, &locnum, &dw->dw_err) != DW_DLV_OK)
+ return (0);
+ if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
+ terminate("die %llu: cannot parse member offset with "
+ "operator other than DW_OP_plus_uconst\n",
+ die_off(dw, die));
+ }
+ *valp = loc->ld_s->lr_number;
+ if (loc != NULL) {
+ dwarf_dealloc(dw->dw_dw, loc->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(dw->dw_dw, loc, DW_DLA_LOCDESC);
+ }
+ break;
- *valp = loc->ld_s->lr_number;
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ /*
+ * Clang 3.4 generates DW_AT_data_member_location attribute
+ * with DW_FORM_data* form (constant class). The attribute
+ * stores a contant value which is the member offset.
+ *
+ * However, note that DW_FORM_data[48] in DWARF version 2 or 3
+ * could be used as a section offset (offset into .debug_loc in
+ * this case). Here we assume the attribute always stores a
+ * constant because we know Clang 3.4 does this and GCC in
+ * base won't emit DW_FORM_data[48] for this attribute. This
+ * code will remain correct if future vesrions of Clang and
+ * GCC conform to DWARF4 standard and only use the form
+ * DW_FORM_sec_offset for section offset.
+ */
+ if (dwarf_attrval_unsigned(die, name, valp, &dw->dw_err) !=
+ DW_DLV_OK)
+ return (0);
+ break;
- if (loc != NULL)
- if (dwarf_locdesc_free(loc, &dw->dw_err) != DW_DLV_OK)
- terminate("die %llu: cannot free location descriptor: %s\n",
- die_off(dw, die), dwarf_errmsg(&dw->dw_err));
+ default:
+ terminate("die %llu: cannot parse member offset with form "
+ "%u\n", die_off(dw, die), form);
+ }
return (1);
}
@@ -885,6 +936,9 @@ die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp,
int type, const char *typename)
{
Dwarf_Unsigned sz, bitsz, bitoff, maxsz=0;
+#if BYTE_ORDER == _LITTLE_ENDIAN
+ Dwarf_Unsigned bysz;
+#endif
Dwarf_Die mem;
mlist_t *ml, **mlastp;
iidesc_t *ii;
@@ -959,8 +1013,26 @@ die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp,
#if BYTE_ORDER == _BIG_ENDIAN
ml->ml_offset += bitoff;
#else
- ml->ml_offset += tdesc_bitsize(ml->ml_type) - bitoff -
- ml->ml_size;
+ /*
+ * Note that Clang 3.4 will sometimes generate
+ * member DIE before generating the DIE for the
+ * member's type. The code can not handle this
+ * properly so that tdesc_bitsize(ml->ml_type) will
+ * return 0 because ml->ml_type is unknown. As a
+ * result, a wrong member offset will be calculated.
+ * To workaround this, we can instead try to
+ * retrieve the value of DW_AT_byte_size attribute
+ * which stores the byte size of the space occupied
+ * by the type. If this attribute exists, its value
+ * should equal to tdesc_bitsize(ml->ml_type)/NBBY.
+ */
+ if (die_unsigned(dw, mem, DW_AT_byte_size, &bysz, 0) &&
+ bysz > 0)
+ ml->ml_offset += bysz * NBBY - bitoff -
+ ml->ml_size;
+ else
+ ml->ml_offset += tdesc_bitsize(ml->ml_type) -
+ bitoff - ml->ml_size;
#endif
}
@@ -1852,7 +1924,7 @@ int
dw_read(tdata_t *td, Elf *elf, char *filename __unused)
{
Dwarf_Unsigned abboff, hdrlen, nxthdr;
- Dwarf_Half vers, addrsz;
+ Dwarf_Half vers, addrsz, offsz;
Dwarf_Die cu = 0;
Dwarf_Die child = 0;
dwarf_t dw;
@@ -1869,7 +1941,7 @@ dw_read(tdata_t *td, Elf *elf, char *filename __unused)
dw.dw_enumhash = hash_new(TDESC_HASH_BUCKETS, tdesc_namehash,
tdesc_namecmp);
- if ((rc = dwarf_elf_init(elf, DW_DLC_READ, &dw.dw_dw,
+ if ((rc = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dw.dw_dw,
&dw.dw_err)) == DW_DLV_NO_ENTRY) {
if (should_have_dwarf(elf)) {
errno = ENOENT;
@@ -1878,7 +1950,7 @@ dw_read(tdata_t *td, Elf *elf, char *filename __unused)
return (0);
}
} else if (rc != DW_DLV_OK) {
- if (dwarf_errno(&dw.dw_err) == DW_DLE_DEBUG_INFO_NULL) {
+ if (dwarf_errno(dw.dw_err) == DW_DLE_DEBUG_INFO_NULL) {
/*
* There's no type data in the DWARF section, but
* libdwarf is too clever to handle that properly.
@@ -1887,12 +1959,12 @@ dw_read(tdata_t *td, Elf *elf, char *filename __unused)
}
terminate("failed to initialize DWARF: %s\n",
- dwarf_errmsg(&dw.dw_err));
+ dwarf_errmsg(dw.dw_err));
}
- if ((rc = dwarf_next_cu_header(dw.dw_dw, &hdrlen, &vers, &abboff,
- &addrsz, &nxthdr, &dw.dw_err)) != DW_DLV_OK)
- terminate("rc = %d %s\n", rc, dwarf_errmsg(&dw.dw_err));
+ if ((rc = dwarf_next_cu_header_b(dw.dw_dw, &hdrlen, &vers, &abboff,
+ &addrsz, &offsz, NULL, &nxthdr, &dw.dw_err)) != DW_DLV_OK)
+ terminate("rc = %d %s\n", rc, dwarf_errmsg(dw.dw_err));
if ((cu = die_sibling(&dw, NULL)) == NULL ||
(((child = die_child(&dw, cu)) == NULL) &&
@@ -1909,9 +1981,9 @@ dw_read(tdata_t *td, Elf *elf, char *filename __unused)
terminate("file contains too many types\n");
debug(1, "DWARF version: %d\n", vers);
- if (vers != DWARF_VERSION) {
+ if (vers < 2 || vers > 4) {
terminate("file contains incompatible version %d DWARF code "
- "(version 2 required)\n", vers);
+ "(version 2, 3 or 4 required)\n", vers);
}
if (die_string(&dw, cu, DW_AT_producer, &prod, 0)) {
@@ -1930,11 +2002,11 @@ dw_read(tdata_t *td, Elf *elf, char *filename __unused)
if ((child = die_child(&dw, cu)) != NULL)
die_create(&dw, child);
- if ((rc = dwarf_next_cu_header(dw.dw_dw, &hdrlen, &vers, &abboff,
- &addrsz, &nxthdr, &dw.dw_err)) != DW_DLV_NO_ENTRY)
+ if ((rc = dwarf_next_cu_header_b(dw.dw_dw, &hdrlen, &vers, &abboff,
+ &addrsz, &offsz, NULL, &nxthdr, &dw.dw_err)) != DW_DLV_NO_ENTRY)
terminate("multiple compilation units not supported\n");
- (void) dwarf_finish(&dw.dw_dw, &dw.dw_err);
+ (void) dwarf_finish(dw.dw_dw, &dw.dw_err);
die_resolve(&dw);
diff --git a/cddl/lib/Makefile b/cddl/lib/Makefile
index 53d402a..fef1383 100644
--- a/cddl/lib/Makefile
+++ b/cddl/lib/Makefile
@@ -11,7 +11,12 @@ SUBDIR= ${_drti} \
libuutil \
${_libzfs_core} \
${_libzfs} \
- ${_libzpool}
+ ${_libzpool} \
+ ${_tests}
+
+.if ${MK_TESTS} != "no"
+_tests= tests
+.endif
.if ${MK_ZFS} != "no"
_libzfs_core= libzfs_core
diff --git a/cddl/lib/libctf/Makefile b/cddl/lib/libctf/Makefile
index 5829111..50c7937 100644
--- a/cddl/lib/libctf/Makefile
+++ b/cddl/lib/libctf/Makefile
@@ -27,5 +27,8 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${OPENSOLARIS_USR_DISTDIR}/lib/libctf/common \
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common
+DPADD= ${LIBZ}
+LDADD= -lz
+
.include <bsd.lib.mk>
diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile
index 46f7046..006740a 100644
--- a/cddl/lib/libdtrace/Makefile
+++ b/cddl/lib/libdtrace/Makefile
@@ -69,9 +69,11 @@ CFLAGS+= -I${.OBJDIR} -I${.CURDIR} \
#CFLAGS+= -DYYDEBUG
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+= -I${.CURDIR}/../../../sys/cddl/dev/dtrace/x86
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel -DDIS_MEM
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/i386
.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/${MACHINE_ARCH}
+.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/x86
.elif ${MACHINE_CPUARCH} == "sparc64"
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/sparc
diff --git a/cddl/lib/libdtrace/psinfo.d b/cddl/lib/libdtrace/psinfo.d
index 068e72e..c2219f7 100644
--- a/cddl/lib/libdtrace/psinfo.d
+++ b/cddl/lib/libdtrace/psinfo.d
@@ -57,7 +57,8 @@ translator psinfo_t < struct proc *T > {
pr_gid = T->p_ucred->cr_rgid;
pr_egid = T->p_ucred->cr_groups[0];
pr_addr = 0;
- pr_psargs = stringof(T->p_args->ar_args);
+ pr_psargs = (T->p_args->ar_args == 0) ? "" :
+ memstr(T->p_args->ar_args, ' ', T->p_args->ar_length);
pr_arglen = T->p_args->ar_length;
pr_jailid = T->p_ucred->cr_prison->pr_id;
};
diff --git a/cddl/lib/libnvpair/Makefile b/cddl/lib/libnvpair/Makefile
index bd159fc..677068f 100644
--- a/cddl/lib/libnvpair/Makefile
+++ b/cddl/lib/libnvpair/Makefile
@@ -21,4 +21,13 @@ CFLAGS+= -I${.CURDIR}/../../../sys
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
+# This library uses macros to define fprintf behavior for several object types
+# The compiler will see the non-string literal arguments to the fprintf calls and
+# omit warnings for them. Quiesce these warnings in contrib code:
+#
+# cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c:743:12: warning: format
+# string is not a string literal (potentially insecure) [-Wformat-security]
+# ARENDER(pctl, nvlist_array, nvl, name, val, nelem);
+#
+CFLAGS+= -Wno-format-security
.include <bsd.lib.mk>
diff --git a/cddl/lib/libzpool/Makefile b/cddl/lib/libzpool/Makefile
index 848325a..7d4528f 100644
--- a/cddl/lib/libzpool/Makefile
+++ b/cddl/lib/libzpool/Makefile
@@ -60,7 +60,7 @@ DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBZ}
LDADD= -lmd -lpthread -lz
# atomic.S doesn't like profiling.
-NO_PROFILE=
+MK_PROFILE= no
CSTD= c99
diff --git a/cddl/lib/tests/Makefile b/cddl/lib/tests/Makefile
new file mode 100644
index 0000000..4a49d9f
--- /dev/null
+++ b/cddl/lib/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/cddl/lib
+
+.PATH: ${.CURDIR:H:H:H}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
diff --git a/cddl/sbin/Makefile b/cddl/sbin/Makefile
index f74307c..4fd96f6 100644
--- a/cddl/sbin/Makefile
+++ b/cddl/sbin/Makefile
@@ -2,7 +2,11 @@
.include <bsd.own.mk>
-SUBDIR= ${_zfs} ${_zpool}
+SUBDIR= ${_tests} ${_zfs} ${_zpool}
+
+.if ${MK_TESTS} != "no"
+_tests= tests
+.endif
.if ${MK_ZFS} != "no"
_zfs= zfs
diff --git a/cddl/sbin/tests/Makefile b/cddl/sbin/tests/Makefile
new file mode 100644
index 0000000..91bbaee
--- /dev/null
+++ b/cddl/sbin/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/cddl/sbin
+
+.PATH: ${.CURDIR:H:H:H}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
diff --git a/cddl/tests/Makefile b/cddl/tests/Makefile
new file mode 100644
index 0000000..34a27ea
--- /dev/null
+++ b/cddl/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/cddl
+
+.PATH: ${.CURDIR:H:H}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
diff --git a/cddl/usr.bin/Makefile b/cddl/usr.bin/Makefile
index 13d3a86..3547ff7 100644
--- a/cddl/usr.bin/Makefile
+++ b/cddl/usr.bin/Makefile
@@ -7,11 +7,16 @@ SUBDIR= \
ctfdump \
ctfmerge \
sgsmsg \
+ ${_tests} \
${_zinject} \
${_zlook} \
${_zstreamdump} \
${_ztest}
+.if ${MK_TESTS} != "no"
+_tests= tests
+.endif
+
.if ${MK_ZFS} != "no"
_zinject= zinject
#_zlook= zlook
diff --git a/cddl/usr.bin/sgsmsg/Makefile b/cddl/usr.bin/sgsmsg/Makefile
index 8d1f70f..e1b318c 100644
--- a/cddl/usr.bin/sgsmsg/Makefile
+++ b/cddl/usr.bin/sgsmsg/Makefile
@@ -5,7 +5,7 @@
# This program is required as a bootstrap tool for 'make buildworld'
PROG= sgsmsg
-NO_MAN=
+MAN=
SRCS= avl.c sgsmsg.c string_table.c findprime.c
WARNS?= 0
diff --git a/cddl/usr.bin/tests/Makefile b/cddl/usr.bin/tests/Makefile
new file mode 100644
index 0000000..c94d591
--- /dev/null
+++ b/cddl/usr.bin/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/cddl/usr.bin
+
+.PATH: ${.CURDIR:H:H:H}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
diff --git a/cddl/usr.bin/zinject/Makefile b/cddl/usr.bin/zinject/Makefile
index 8c5c141..adb5023 100644
--- a/cddl/usr.bin/zinject/Makefile
+++ b/cddl/usr.bin/zinject/Makefile
@@ -4,7 +4,7 @@
PROG= zinject
SRCS= zinject.c translate.c
-NO_MAN=
+MAN=
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
@@ -16,6 +16,7 @@ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
+CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs/
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
diff --git a/cddl/usr.bin/zlook/Makefile b/cddl/usr.bin/zlook/Makefile
index 0251f57..eae2fd0 100644
--- a/cddl/usr.bin/zlook/Makefile
+++ b/cddl/usr.bin/zlook/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../contrib/opensolaris/cmd/zlook
PROG= zlook
-NO_MAN=
+MAN=
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
diff --git a/cddl/usr.bin/ztest/Makefile b/cddl/usr.bin/ztest/Makefile
index 370eacb5..0865226 100644
--- a/cddl/usr.bin/ztest/Makefile
+++ b/cddl/usr.bin/ztest/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../..//contrib/opensolaris/cmd/ztest
PROG= ztest
-NO_MAN=
+MAN=
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
diff --git a/cddl/usr.sbin/Makefile b/cddl/usr.sbin/Makefile
index fb2c437..8551c28 100644
--- a/cddl/usr.sbin/Makefile
+++ b/cddl/usr.sbin/Makefile
@@ -5,9 +5,14 @@
SUBDIR= ${_dtrace} \
${_dtruss} \
${_lockstat} \
+ ${_tests} \
${_zdb} \
${_zhack}
+.if ${MK_TESTS} != "no"
+_tests= tests
+.endif
+
.if ${MK_ZFS} != "no"
.if ${MK_LIBTHR} != "no"
_zdb= zdb
diff --git a/cddl/usr.sbin/lockstat/Makefile b/cddl/usr.sbin/lockstat/Makefile
index ef3ac3c..0668758 100644
--- a/cddl/usr.sbin/lockstat/Makefile
+++ b/cddl/usr.sbin/lockstat/Makefile
@@ -3,7 +3,6 @@
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/lockstat
PROG= lockstat
-NO_MAN=
SRCS= lockstat.c sym.c
BINDIR?= /usr/sbin
diff --git a/cddl/usr.sbin/tests/Makefile b/cddl/usr.sbin/tests/Makefile
new file mode 100644
index 0000000..0305aee
--- /dev/null
+++ b/cddl/usr.sbin/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/cddl/usr.sbin
+
+.PATH: ${.CURDIR:H:H:H}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
diff --git a/cddl/usr.sbin/zhack/Makefile b/cddl/usr.sbin/zhack/Makefile
index f09d2d8..9ae3395 100644
--- a/cddl/usr.sbin/zhack/Makefile
+++ b/cddl/usr.sbin/zhack/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/zhack
PROG= zhack
-NO_MAN=
+MAN=
WARNS?= 0
CSTD= c99
OpenPOWER on IntegriCloud