Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Apr 2013 09:19:10 +0000 (UTC)
From:      Martin Matuska <mm@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r249643 - in stable/9: . cddl/contrib/opensolaris/cmd/zdb cddl/contrib/opensolaris/cmd/zfs cddl/contrib/opensolaris/cmd/zhack cddl/contrib/opensolaris/cmd/zpool cddl/contrib/opensolaris...
Message-ID:  <201304190919.r3J9JA19035885@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mm
Date: Fri Apr 19 09:19:10 2013
New Revision: 249643
URL: http://svnweb.freebsd.org/changeset/base/249643

Log:
  MFC 248571,248976,249004,249042,249188,249195-249196,249206,249207,249319,
      249326,249356-249357
  
  Merge libzfs_core and other ZFS bugfixes and improvements.
  
  MFC r248571:
    MFV 238590, 238592:
    In the first zfs ioctl restructuring phase, the libzfs_core library was
    introduced. It is a new thin library that wraps around kernel ioctl's.
    The idea is to provide a forward-compatible way of dealing with new
    features. Arguments are passed in nvlists and not random zfs_cmd fields,
    new-style ioctls are logged to pool history using a new method of
    history logging.
  
    http://blog.delphix.com/matt/2012/01/17/the-future-of-libzfs/
  
    MFV 247580 [1]:
    To address issues of several deadlocks and race conditions the locking
    code around dsl_dataset was rewritten and the interface to synctasks
    was changed.
  
    User-Visible Changes:
    "zfs snapshot" can create more arbitrary snapshots at once (atomically)
    "zfs destroy" destroys multiple snapshots at once
    "zfs recv" has improved performance
  
    Backward Compatibility:
    I have extended the compatibility layer to support full backward
    compatibility by remapping or rewriting the responsible ioctl arguments.
    Old utilities are fully supported by the new kernel module.
  
    Forward Compatibility:
    New utilities work with old kernels with the following restrictions:
      - creating, destroying, holding and releasing of multiple snapshots
        at once is not supported, this includes recursive (-r) commands
  
    Illumos ZFS issues:
      2882 implement libzfs_core
      2900 "zfs snapshot" should be able to create multiple,
           arbitrary snapshots at once
      3464 zfs synctask code needs restructuring
  
  MFC r248976:
    Call dmu_snapshot_list_next() in zvol.c with dsl_pool_config lock held
  
  MFC r249004:
    Do not check against uninitialized rc and comment out vendor code
  
  MFC r249042:
    Fix possible pool hold leak in dmu_send_impl()
  
    Illumos ZFS issues:
      3645 dmu_send_impl: possibilty of pool hold leak
  
  MFC r249188:
    Import vendor change to reduce diff, no effect on FreeBSD.
  
    Illumos ZFS issues:
      3517 importing pool with autoreplace=on and "hole" vdevs crashes
  	 syseventd
  
  MFC r249195:
    Merge change from vendor to reduce diff only.
    ZFS dtrace probes are not supported on FreeBSD yet.
  
    Illumos ZFS issues:
      3598 want to dtrace when errors are generated in zfs
  
  MFC r249196:
    Provide a fix for kernel panic if receiving recursive deduplicated
    streams. Problem reported to vendor.
  
    Illumos ZFS issues:
      3692 Panic on zfs receive of a recursive deduplicated stream
  
  MFC r249206:
    Merge vendor change - modify time processing in deadman thread.
  
    Illumos ZFS issues:
      3618 ::zio dcmd does not show timestamp data
  
  MFC r249207:
    Allow zdb to output a histogram of compressed block sizes.
  
    Illumos ZFS issues:
      3641 want a histogram of compressed block sizes
  
  MFC r249319:
    ZFS expects a copyout of zfs_cmd_t on an ioctl error. Our sys_ioctl()
    doesn't copyout in this case.
  
    To solve this a new struct zfs_iocparm_t is introduced consisting of:
    - zfs_ioctl_version (future backwards compatibility purposes)
    - user space pointer to zfs_cmd_t (copyin and copyout)
    - size of zfs_cmd_t (verification purposes)
  
    The copyin and copyout of zfs_cmd_t is now done the illumos (vendor) way
    what makes porting of new changes easier and ensures correct behavior if
    returning an error.
  
  MFC r249326:
    Cast (void *)(uintptr_t) on copyout and copyin of zfs_iocparm_t.zfs_cmd
  
  MFC r249356:
    Merge bugfixes accepted and integrated by vendor. Underlying problems
    have been reported by us and fixed in r240942 and r249196.
  
    Illumos ZFS issues:
      3645 dmu_send_impl: possibilty of pool hold leak
      3692 Panic on zfs receive of a recursive deduplicated stream
  
  MFC r249357:
    Fix libzfs to report error instead of returning zero if trying to hold or
    release a non-existing snapshot of a existing dataset. In recursive case
    error is reported if no snapshots with the requested name have been found.
  
    Illumos ZFS issues:
      3699 zfs hold or release of a non-existent snapshot does not output
  	 error

Added:
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
     - copied, changed from r248571, head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
     - copied unchanged from r248571, head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
  stable/9/cddl/contrib/opensolaris/lib/libzfs_core/
     - copied from r248571, head/cddl/contrib/opensolaris/lib/libzfs_core/
  stable/9/cddl/contrib/opensolaris/lib/libzpool/common/zfs.d
     - copied unchanged from r249195, head/cddl/contrib/opensolaris/lib/libzpool/common/zfs.d
  stable/9/cddl/lib/libzfs_core/
     - copied from r248571, head/cddl/lib/libzfs_core/
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
     - copied, changed from r248571, head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_userhold.c
     - copied, changed from r248571, head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_userhold.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_send.h
     - copied unchanged from r248571, head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_send.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h
     - copied unchanged from r248571, head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_userhold.h
     - copied unchanged from r248571, head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_userhold.h
Modified:
  stable/9/Makefile.inc1   (contents, props changed)
  stable/9/cddl/contrib/opensolaris/cmd/zdb/zdb.c
  stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs.8
  stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
  stable/9/cddl/contrib/opensolaris/cmd/zhack/zhack.c
  stable/9/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
  stable/9/cddl/contrib/opensolaris/cmd/ztest/ztest.c
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
  stable/9/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
  stable/9/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
  stable/9/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
  stable/9/cddl/lib/Makefile
  stable/9/cddl/lib/libzfs/Makefile
  stable/9/cddl/sbin/zfs/Makefile
  stable/9/cddl/sbin/zpool/Makefile
  stable/9/cddl/usr.bin/zinject/Makefile
  stable/9/cddl/usr.bin/ztest/Makefile
  stable/9/cddl/usr.sbin/zdb/Makefile
  stable/9/cddl/usr.sbin/zhack/Makefile
  stable/9/rescue/rescue/Makefile
  stable/9/share/mk/bsd.libnames.mk
  stable/9/sys/cddl/compat/opensolaris/sys/cred.h
  stable/9/sys/cddl/compat/opensolaris/sys/sdt.h
  stable/9/sys/cddl/contrib/opensolaris/common/nvpair/fnvpair.c
  stable/9/sys/cddl/contrib/opensolaris/common/zfs/zfs_comutil.c
  stable/9/sys/cddl/contrib/opensolaris/common/zfs/zfs_comutil.h
  stable/9/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c
  stable/9/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h
  stable/9/sys/cddl/contrib/opensolaris/common/zfs/zprop_common.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/Makefile.files
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bplist.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bpobj.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/ddt.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_diff.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_object.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_deleg.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_prop.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_synctask.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/refcount.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/rrwlock.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_errlog.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_history.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dbuf.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_objset.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_tx.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_deleg.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_pool.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_prop.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_synctask.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/refcount.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/rrwlock.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/space_map.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/txg.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev_impl.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfeature.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_debug.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/uberblock.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_cache.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_disk.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_file.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_mirror.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_missing.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_raidz.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_root.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap_leaf.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap_micro.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_checksum.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_compress.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_inject.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/sys/feature_tests.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
  stable/9/sys/cddl/contrib/opensolaris/uts/common/sys/nvpair.h
Directory Properties:
  stable/9/cddl/   (props changed)
  stable/9/cddl/contrib/opensolaris/   (props changed)
  stable/9/cddl/contrib/opensolaris/cmd/zfs/   (props changed)
  stable/9/cddl/contrib/opensolaris/lib/libzfs/   (props changed)
  stable/9/cddl/lib/   (props changed)
  stable/9/rescue/rescue/   (props changed)
  stable/9/share/mk/   (props changed)
  stable/9/sys/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)

Modified: stable/9/Makefile.inc1
==============================================================================
--- stable/9/Makefile.inc1	Fri Apr 19 08:06:45 2013	(r249642)
+++ stable/9/Makefile.inc1	Fri Apr 19 09:19:10 2013	(r249643)
@@ -1321,6 +1321,7 @@ _prebuild_libs=	${_kerberos5_lib_libasn1
 		lib/libopie lib/libpam ${_lib_libthr} \
 		lib/libradius lib/libsbuf lib/libtacplus \
 		${_cddl_lib_libumem} ${_cddl_lib_libnvpair} \
+		${_cddl_lib_libzfs_core} \
 		lib/libutil ${_lib_libypclnt} lib/libz lib/msun \
 		${_secure_lib_libcrypto} ${_secure_lib_libssh} \
 		${_secure_lib_libssl}
@@ -1340,7 +1341,9 @@ lib/libopie__L lib/libtacplus__L: lib/li
 .if ${MK_CDDL} != "no"
 _cddl_lib_libumem= cddl/lib/libumem
 _cddl_lib_libnvpair= cddl/lib/libnvpair
+_cddl_lib_libzfs_core= cddl/lib/libzfs_core
 _cddl_lib= cddl/lib
+cddl/lib/libzfs_core__L: cddl/lib/libnvpair__L
 .endif
 
 .if ${MK_CRYPT} != "no"

Modified: stable/9/cddl/contrib/opensolaris/cmd/zdb/zdb.c
==============================================================================
--- stable/9/cddl/contrib/opensolaris/cmd/zdb/zdb.c	Fri Apr 19 08:06:45 2013	(r249642)
+++ stable/9/cddl/contrib/opensolaris/cmd/zdb/zdb.c	Fri Apr 19 09:19:10 2013	(r249643)
@@ -21,10 +21,11 @@
 
 /*
  * 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.
  */
 
 #include <stdio.h>
+#include <unistd.h>
 #include <stdio_ext.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -57,6 +58,7 @@
 #include <sys/arc.h>
 #include <sys/ddt.h>
 #include <sys/zfeature.h>
+#include <zfs_comutil.h>
 #undef ZFS_MAXNAMELEN
 #undef verify
 #include <libzfs.h>
@@ -206,6 +208,27 @@ dump_packed_nvlist(objset_t *os, uint64_
 	nvlist_free(nv);
 }
 
+/* ARGSUSED */
+static void
+dump_history_offsets(objset_t *os, uint64_t object, void *data, size_t size)
+{
+	spa_history_phys_t *shp = data;
+
+	if (shp == NULL)
+		return;
+
+	(void) printf("\t\tpool_create_len = %llu\n",
+	    (u_longlong_t)shp->sh_pool_create_len);
+	(void) printf("\t\tphys_max_off = %llu\n",
+	    (u_longlong_t)shp->sh_phys_max_off);
+	(void) printf("\t\tbof = %llu\n",
+	    (u_longlong_t)shp->sh_bof);
+	(void) printf("\t\teof = %llu\n",
+	    (u_longlong_t)shp->sh_eof);
+	(void) printf("\t\trecords_lost = %llu\n",
+	    (u_longlong_t)shp->sh_records_lost);
+}
+
 static void
 zdb_nicenum(uint64_t num, char *buf)
 {
@@ -215,18 +238,18 @@ zdb_nicenum(uint64_t num, char *buf)
 		nicenum(num, buf);
 }
 
-const char dump_zap_stars[] = "****************************************";
-const int dump_zap_width = sizeof (dump_zap_stars) - 1;
+const char histo_stars[] = "****************************************";
+const int histo_width = sizeof (histo_stars) - 1;
 
 static void
-dump_zap_histogram(uint64_t histo[ZAP_HISTOGRAM_SIZE])
+dump_histogram(const uint64_t *histo, int size)
 {
 	int i;
-	int minidx = ZAP_HISTOGRAM_SIZE - 1;
+	int minidx = size - 1;
 	int maxidx = 0;
 	uint64_t max = 0;
 
-	for (i = 0; i < ZAP_HISTOGRAM_SIZE; i++) {
+	for (i = 0; i < size; i++) {
 		if (histo[i] > max)
 			max = histo[i];
 		if (histo[i] > 0 && i > maxidx)
@@ -235,12 +258,14 @@ dump_zap_histogram(uint64_t histo[ZAP_HI
 			minidx = i;
 	}
 
-	if (max < dump_zap_width)
-		max = dump_zap_width;
+	if (max < histo_width)
+		max = histo_width;
 
-	for (i = minidx; i <= maxidx; i++)
-		(void) printf("\t\t\t%u: %6llu %s\n", i, (u_longlong_t)histo[i],
-		    &dump_zap_stars[(max - histo[i]) * dump_zap_width / max]);
+	for (i = minidx; i <= maxidx; i++) {
+		(void) printf("\t\t\t%3u: %6llu %s\n",
+		    i, (u_longlong_t)histo[i],
+		    &histo_stars[(max - histo[i]) * histo_width / max]);
+	}
 }
 
 static void
@@ -291,19 +316,19 @@ dump_zap_stats(objset_t *os, uint64_t ob
 	    (u_longlong_t)zs.zs_salt);
 
 	(void) printf("\t\tLeafs with 2^n pointers:\n");
-	dump_zap_histogram(zs.zs_leafs_with_2n_pointers);
+	dump_histogram(zs.zs_leafs_with_2n_pointers, ZAP_HISTOGRAM_SIZE);
 
 	(void) printf("\t\tBlocks with n*5 entries:\n");
-	dump_zap_histogram(zs.zs_blocks_with_n5_entries);
+	dump_histogram(zs.zs_blocks_with_n5_entries, ZAP_HISTOGRAM_SIZE);
 
 	(void) printf("\t\tBlocks n/10 full:\n");
-	dump_zap_histogram(zs.zs_blocks_n_tenths_full);
+	dump_histogram(zs.zs_blocks_n_tenths_full, ZAP_HISTOGRAM_SIZE);
 
 	(void) printf("\t\tEntries with n chunks:\n");
-	dump_zap_histogram(zs.zs_entries_using_n_chunks);
+	dump_histogram(zs.zs_entries_using_n_chunks, ZAP_HISTOGRAM_SIZE);
 
 	(void) printf("\t\tBuckets with n entries:\n");
-	dump_zap_histogram(zs.zs_buckets_with_n_entries);
+	dump_histogram(zs.zs_buckets_with_n_entries, ZAP_HISTOGRAM_SIZE);
 }
 
 /*ARGSUSED*/
@@ -857,21 +882,22 @@ dump_history(spa_t *spa)
 	for (int i = 0; i < num; i++) {
 		uint64_t time, txg, ievent;
 		char *cmd, *intstr;
+		boolean_t printed = B_FALSE;
 
 		if (nvlist_lookup_uint64(events[i], ZPOOL_HIST_TIME,
 		    &time) != 0)
-			continue;
+			goto next;
 		if (nvlist_lookup_string(events[i], ZPOOL_HIST_CMD,
 		    &cmd) != 0) {
 			if (nvlist_lookup_uint64(events[i],
 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
-				continue;
+				goto next;
 			verify(nvlist_lookup_uint64(events[i],
 			    ZPOOL_HIST_TXG, &txg) == 0);
 			verify(nvlist_lookup_string(events[i],
 			    ZPOOL_HIST_INT_STR, &intstr) == 0);
-			if (ievent >= LOG_END)
-				continue;
+			if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS)
+				goto next;
 
 			(void) snprintf(internalstr,
 			    sizeof (internalstr),
@@ -884,6 +910,14 @@ dump_history(spa_t *spa)
 		(void) localtime_r(&tsec, &t);
 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
 		(void) printf("%s %s\n", tbuf, cmd);
+		printed = B_TRUE;
+
+next:
+		if (dump_opt['h'] > 1) {
+			if (!printed)
+				(void) printf("unrecognized record:\n");
+			dump_nvlist(events[i], 2);
+		}
 	}
 }
 
@@ -916,7 +950,7 @@ sprintf_blkptr_compact(char *blkbuf, con
 	const dva_t *dva = bp->blk_dva;
 	int ndvas = dump_opt['d'] > 5 ? BP_GET_NDVAS(bp) : 1;
 
-	if (dump_opt['b'] >= 5) {
+	if (dump_opt['b'] >= 6) {
 		sprintf_blkptr(blkbuf, bp);
 		return;
 	}
@@ -1496,7 +1530,7 @@ static object_viewer_t *object_viewer[DM
 	dump_zap,		/* other ZAP			*/
 	dump_zap,		/* persistent error log		*/
 	dump_uint8,		/* SPA history			*/
-	dump_uint64,		/* SPA history offsets		*/
+	dump_history_offsets,	/* SPA history offsets		*/
 	dump_zap,		/* Pool properties		*/
 	dump_zap,		/* DSL permissions		*/
 	dump_acl,		/* ZFS ACL			*/
@@ -1661,7 +1695,9 @@ dump_dir(objset_t *os)
 	int print_header = 1;
 	int i, error;
 
+	dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
 	dmu_objset_fast_stat(os, &dds);
+	dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
 
 	if (dds.dds_type < DMU_OST_NUMTYPES)
 		type = objset_types[dds.dds_type];
@@ -1953,11 +1989,13 @@ dump_one_dir(const char *dsname, void *a
 /*
  * Block statistics.
  */
+#define	PSIZE_HISTO_SIZE (SPA_MAXBLOCKSIZE / SPA_MINBLOCKSIZE + 1)
 typedef struct zdb_blkstats {
-	uint64_t	zb_asize;
-	uint64_t	zb_lsize;
-	uint64_t	zb_psize;
-	uint64_t	zb_count;
+	uint64_t zb_asize;
+	uint64_t zb_lsize;
+	uint64_t zb_psize;
+	uint64_t zb_count;
+	uint64_t zb_psize_histogram[PSIZE_HISTO_SIZE];
 } zdb_blkstats_t;
 
 /*
@@ -1981,6 +2019,9 @@ typedef struct zdb_cb {
 	zdb_blkstats_t	zcb_type[ZB_TOTAL + 1][ZDB_OT_TOTAL + 1];
 	uint64_t	zcb_dedup_asize;
 	uint64_t	zcb_dedup_blocks;
+	uint64_t	zcb_start;
+	uint64_t	zcb_lastprint;
+	uint64_t	zcb_totalasize;
 	uint64_t	zcb_errors[256];
 	int		zcb_readfails;
 	int		zcb_haderrors;
@@ -2007,6 +2048,7 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *
 		zb->zb_lsize += BP_GET_LSIZE(bp);
 		zb->zb_psize += BP_GET_PSIZE(bp);
 		zb->zb_count++;
+		zb->zb_psize_histogram[BP_GET_PSIZE(bp) >> SPA_MINBLOCKSHIFT]++;
 	}
 
 	if (dump_opt['L'])
@@ -2070,7 +2112,6 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog
 		    NULL, NULL, ZIO_PRIORITY_ASYNC_READ, flags, zb));
 
 		free(data);
-
 		if (ioerr && !(flags & ZIO_FLAG_SPECULATIVE)) {
 			zcb->zcb_haderrors = 1;
 			zcb->zcb_errors[ioerr]++;
@@ -2094,7 +2135,7 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog
 
 	zcb->zcb_readfails = 0;
 
-	if (dump_opt['b'] >= 4) {
+	if (dump_opt['b'] >= 5) {
 		sprintf_blkptr(blkbuf, bp);
 		(void) printf("objset %llu object %llu "
 		    "level %lld offset 0x%llx %s\n",
@@ -2105,6 +2146,28 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog
 		    blkbuf);
 	}
 
+	if (dump_opt['b'] < 5 && isatty(STDERR_FILENO) &&
+	    gethrtime() > zcb->zcb_lastprint + NANOSEC) {
+		uint64_t now = gethrtime();
+		char buf[10];
+		uint64_t bytes = zcb->zcb_type[ZB_TOTAL][ZDB_OT_TOTAL].zb_asize;
+		int kb_per_sec =
+		    1 + bytes / (1 + ((now - zcb->zcb_start) / 1000 / 1000));
+		int sec_remaining =
+		    (zcb->zcb_totalasize - bytes) / 1024 / kb_per_sec;
+
+		zfs_nicenum(bytes, buf, sizeof (buf));
+		(void) fprintf(stderr,
+		    "\r%5s completed (%4dMB/s) "
+		    "estimated time remaining: %uhr %02umin %02usec        ",
+		    buf, kb_per_sec / 1024,
+		    sec_remaining / 60 / 60,
+		    sec_remaining / 60 % 60,
+		    sec_remaining % 60);
+
+		zcb->zcb_lastprint = now;
+	}
+
 	return (0);
 }
 
@@ -2236,7 +2299,7 @@ count_block_cb(void *arg, const blkptr_t
 {
 	zdb_cb_t *zcb = arg;
 
-	if (dump_opt['b'] >= 4) {
+	if (dump_opt['b'] >= 5) {
 		char blkbuf[BP_SPRINTF_LEN];
 		sprintf_blkptr(blkbuf, bp);
 		(void) printf("[%s] %s\n",
@@ -2255,7 +2318,7 @@ dump_block_stats(spa_t *spa)
 	int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_HARD;
 	int leaks = 0;
 
-	(void) printf("\nTraversing all blocks %s%s%s%s%s...\n",
+	(void) printf("\nTraversing all blocks %s%s%s%s%s...\n\n",
 	    (dump_opt['c'] || !dump_opt['L']) ? "to verify " : "",
 	    (dump_opt['c'] == 1) ? "metadata " : "",
 	    dump_opt['c'] ? "checksums " : "",
@@ -2291,6 +2354,8 @@ dump_block_stats(spa_t *spa)
 	if (dump_opt['c'] > 1)
 		flags |= TRAVERSE_PREFETCH_DATA;
 
+	zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa));
+	zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
 	zcb.zcb_haderrors |= traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
 
 	if (zcb.zcb_haderrors) {
@@ -2418,6 +2483,14 @@ dump_block_stats(spa_t *spa)
 				else
 					(void) printf("    L%d %s\n",
 					    level, typename);
+
+				if (dump_opt['b'] >= 4) {
+					(void) printf("psize "
+					    "(in 512-byte sectors): "
+					    "number of blocks\n");
+					dump_histogram(zb->zb_psize_histogram,
+					    PSIZE_HISTO_SIZE);
+				}
 			}
 		}
 	}

Modified: stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs.8
==============================================================================
--- stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs.8	Fri Apr 19 08:06:45 2013	(r249642)
+++ stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs.8	Fri Apr 19 09:19:10 2013	(r249643)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 1, 2013
+.Dd March 21, 2013
 .Dt ZFS 8
 .Os
 .Sh NAME
@@ -65,6 +65,7 @@
 .Op Fl r
 .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
 .Ar filesystem@snapname Ns | Ns Ar volume@snapname
+.Ar filesystem@snapname Ns | Ns Ar volume@snapname Ns ...
 .Nm
 .Cm rollback
 .Op Fl rRf
@@ -1609,7 +1610,11 @@ multiple snapshots.
 Destroy (or mark for deferred deletion) all snapshots with this name in
 descendent file systems.
 .It Fl R
-Recursively destroy all dependents.
+Recursively destroy all clones of these snapshots, including the clones,
+snapshots, and children.
+If this flag is specified, the
+.Op fl d
+flag will have no effect.
 .It Fl n
 Do a dry-run ("No-op") deletion. No data will be deleted. This is useful in
 conjunction with the
@@ -1637,17 +1642,18 @@ behavior for mounted file systems in use
 .Op Fl r
 .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
 .Ar filesystem@snapname Ns | Ns volume@snapname
+.Ar filesystem@snapname Ns | Ns volume@snapname Ns ...
 .Xc
 .Pp
-Creates a snapshot with the given name. All previous modifications by
-successful system calls to the file system are part of the snapshot. See the
+Creates snapshots with the given names. All previous modifications by
+successful system calls to the file system are part of the snapshots.
+Snapshots are taken atomically, so that all snapshots correspond to the same
+moment in time. See the
 .Qq Sx Snapshots
 section for details.
 .Bl -tag -width indent
 .It Fl r
-Recursively create snapshots of all descendent datasets. Snapshots are taken
-atomically, so that all recursive snapshots correspond to the same moment in
-time.
+Recursively create snapshots of all descendent datasets
 .It Fl o Ar property Ns = Ns Ar value
 Sets the specified property; see
 .Qq Nm Cm create

Modified: stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
==============================================================================
--- stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c	Fri Apr 19 08:06:45 2013	(r249642)
+++ stable/9/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c	Fri Apr 19 09:19:10 2013	(r249643)
@@ -58,6 +58,7 @@
 #include <time.h>
 
 #include <libzfs.h>
+#include <libzfs_core.h>
 #include <zfs_prop.h>
 #include <zfs_deleg.h>
 #include <libuutil.h>
@@ -74,6 +75,7 @@ libzfs_handle_t *g_zfs;
 
 static FILE *mnttab_file;
 static char history_str[HIS_MAX_RECORD_LEN];
+static boolean_t log_history = B_TRUE;
 
 static int zfs_do_clone(int argc, char **argv);
 static int zfs_do_create(int argc, char **argv);
@@ -276,7 +278,7 @@ get_usage(zfs_help_t idx)
 		return (gettext("\tshare <-a | filesystem>\n"));
 	case HELP_SNAPSHOT:
 		return (gettext("\tsnapshot [-r] [-o property=value] ... "
-		    "<filesystem@snapname|volume@snapname>\n"));
+		    "<filesystem@snapname|volume@snapname> ...\n"));
 	case HELP_UNMOUNT:
 		return (gettext("\tunmount [-f] "
 		    "<-a | filesystem|mountpoint>\n"));
@@ -903,11 +905,12 @@ typedef struct destroy_cbdata {
 	boolean_t	cb_parsable;
 	boolean_t	cb_dryrun;
 	nvlist_t	*cb_nvl;
+	nvlist_t	*cb_batchedsnaps;
 
 	/* first snap in contiguous run */
-	zfs_handle_t	*cb_firstsnap;
+	char		*cb_firstsnap;
 	/* previous snap in contiguous run */
-	zfs_handle_t	*cb_prevsnap;
+	char		*cb_prevsnap;
 	int64_t		cb_snapused;
 	char		*cb_snapspec;
 } destroy_cbdata_t;
@@ -999,9 +1002,27 @@ destroy_callback(zfs_handle_t *zhp, void
 		zfs_close(zhp);
 		return (0);
 	}
+	if (cb->cb_dryrun) {
+		zfs_close(zhp);
+		return (0);
+	}
+
+	/*
+	 * We batch up all contiguous snapshots (even of different
+	 * filesystems) and destroy them with one ioctl.  We can't
+	 * simply do all snap deletions and then all fs deletions,
+	 * because we must delete a clone before its origin.
+	 */
+	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
+		fnvlist_add_boolean(cb->cb_batchedsnaps, name);
+	} else {
+		int error = zfs_destroy_snaps_nvl(g_zfs,
+		    cb->cb_batchedsnaps, B_FALSE);
+		fnvlist_free(cb->cb_batchedsnaps);
+		cb->cb_batchedsnaps = fnvlist_alloc();
 
-	if (!cb->cb_dryrun) {
-		if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
+		if (error != 0 ||
+		    zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
 		    zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
 			zfs_close(zhp);
 			return (-1);
@@ -1021,11 +1042,13 @@ destroy_print_cb(zfs_handle_t *zhp, void
 
 	if (nvlist_exists(cb->cb_nvl, name)) {
 		if (cb->cb_firstsnap == NULL)
-			cb->cb_firstsnap = zfs_handle_dup(zhp);
+			cb->cb_firstsnap = strdup(name);
 		if (cb->cb_prevsnap != NULL)
-			zfs_close(cb->cb_prevsnap);
+			free(cb->cb_prevsnap);
 		/* this snap continues the current range */
-		cb->cb_prevsnap = zfs_handle_dup(zhp);
+		cb->cb_prevsnap = strdup(name);
+		if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
+			nomem();
 		if (cb->cb_verbose) {
 			if (cb->cb_parsable) {
 				(void) printf("destroy\t%s\n", name);
@@ -1040,12 +1063,12 @@ destroy_print_cb(zfs_handle_t *zhp, void
 	} else if (cb->cb_firstsnap != NULL) {
 		/* end of this range */
 		uint64_t used = 0;
-		err = zfs_get_snapused_int(cb->cb_firstsnap,
+		err = lzc_snaprange_space(cb->cb_firstsnap,
 		    cb->cb_prevsnap, &used);
 		cb->cb_snapused += used;
-		zfs_close(cb->cb_firstsnap);
+		free(cb->cb_firstsnap);
 		cb->cb_firstsnap = NULL;
-		zfs_close(cb->cb_prevsnap);
+		free(cb->cb_prevsnap);
 		cb->cb_prevsnap = NULL;
 	}
 	zfs_close(zhp);
@@ -1062,13 +1085,13 @@ destroy_print_snapshots(zfs_handle_t *fs
 	if (cb->cb_firstsnap != NULL) {
 		uint64_t used = 0;
 		if (err == 0) {
-			err = zfs_get_snapused_int(cb->cb_firstsnap,
+			err = lzc_snaprange_space(cb->cb_firstsnap,
 			    cb->cb_prevsnap, &used);
 		}
 		cb->cb_snapused += used;
-		zfs_close(cb->cb_firstsnap);
+		free(cb->cb_firstsnap);
 		cb->cb_firstsnap = NULL;
-		zfs_close(cb->cb_prevsnap);
+		free(cb->cb_prevsnap);
 		cb->cb_prevsnap = NULL;
 	}
 	return (err);
@@ -1155,8 +1178,10 @@ static int
 zfs_do_destroy(int argc, char **argv)
 {
 	destroy_cbdata_t cb = { 0 };
+	int rv = 0;
+	int err = 0;
 	int c;
-	zfs_handle_t *zhp;
+	zfs_handle_t *zhp = NULL;
 	char *at;
 	zfs_type_t type = ZFS_TYPE_DATASET;
 
@@ -1210,11 +1235,9 @@ zfs_do_destroy(int argc, char **argv)
 
 	at = strchr(argv[0], '@');
 	if (at != NULL) {
-		int err = 0;
 
 		/* Build the list of snaps to destroy in cb_nvl. */
-		if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
-			nomem();
+		cb.cb_nvl = fnvlist_alloc();
 
 		*at = '\0';
 		zhp = zfs_open(g_zfs, argv[0],
@@ -1225,17 +1248,15 @@ zfs_do_destroy(int argc, char **argv)
 		cb.cb_snapspec = at + 1;
 		if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
 		    cb.cb_error) {
-			zfs_close(zhp);
-			nvlist_free(cb.cb_nvl);
-			return (1);
+			rv = 1;
+			goto out;
 		}
 
 		if (nvlist_empty(cb.cb_nvl)) {
 			(void) fprintf(stderr, gettext("could not find any "
 			    "snapshots to destroy; check snapshot names.\n"));
-			zfs_close(zhp);
-			nvlist_free(cb.cb_nvl);
-			return (1);
+			rv = 1;
+			goto out;
 		}
 
 		if (cb.cb_verbose) {
@@ -1254,18 +1275,26 @@ zfs_do_destroy(int argc, char **argv)
 		}
 
 		if (!cb.cb_dryrun) {
-			if (cb.cb_doclones)
+			if (cb.cb_doclones) {
+				cb.cb_batchedsnaps = fnvlist_alloc();
 				err = destroy_clones(&cb);
+				if (err == 0) {
+					err = zfs_destroy_snaps_nvl(g_zfs,
+					    cb.cb_batchedsnaps, B_FALSE);
+				}
+				if (err != 0) {
+					rv = 1;
+					goto out;
+				}
+			}
 			if (err == 0) {
-				err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl,
+				err = zfs_destroy_snaps_nvl(g_zfs, cb.cb_nvl,
 				    cb.cb_defer_destroy);
 			}
 		}
 
-		zfs_close(zhp);
-		nvlist_free(cb.cb_nvl);
 		if (err != 0)
-			return (1);
+			rv = 1;
 	} else {
 		/* Open the given dataset */
 		if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
@@ -1286,8 +1315,8 @@ zfs_do_destroy(int argc, char **argv)
 			    zfs_get_name(zhp));
 			(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
 			    "to destroy the pool itself\n"), zfs_get_name(zhp));
-			zfs_close(zhp);
-			return (1);
+			rv = 1;
+			goto out;
 		}
 
 		/*
@@ -1297,30 +1326,42 @@ zfs_do_destroy(int argc, char **argv)
 		if (!cb.cb_doclones &&
 		    zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
 		    &cb) != 0) {
-			zfs_close(zhp);
-			return (1);
+			rv = 1;
+			goto out;
 		}
 
 		if (cb.cb_error) {
-			zfs_close(zhp);
-			return (1);
+			rv = 1;
+			goto out;
 		}
 
+		cb.cb_batchedsnaps = fnvlist_alloc();
 		if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
 		    &cb) != 0) {
-			zfs_close(zhp);
-			return (1);
+			rv = 1;
+			goto out;
 		}
 
 		/*
 		 * Do the real thing.  The callback will close the
 		 * handle regardless of whether it succeeds or not.
 		 */
-		if (destroy_callback(zhp, &cb) != 0)
-			return (1);
+		err = destroy_callback(zhp, &cb);
+		zhp = NULL;
+		if (err == 0) {
+			err = zfs_destroy_snaps_nvl(g_zfs,
+			    cb.cb_batchedsnaps, cb.cb_defer_destroy);
+		}
+		if (err != 0)
+			rv = 1;
 	}
 
-	return (0);
+out:
+	fnvlist_free(cb.cb_batchedsnaps);
+	fnvlist_free(cb.cb_nvl);
+	if (zhp != NULL)
+		zfs_close(zhp);
+	return (rv);
 }
 
 static boolean_t
@@ -1921,9 +1962,11 @@ upgrade_set_callback(zfs_handle_t *zhp, 
 			/*
 			 * If they did "zfs upgrade -a", then we could
 			 * be doing ioctls to different pools.  We need
-			 * to log this history once to each pool.
+			 * to log this history once to each pool, and bypass
+			 * the normal history logging that happens in main().
 			 */
-			verify(zpool_stage_history(g_zfs, history_str) == 0);
+			(void) zpool_log_history(g_zfs, history_str);
+			log_history = B_FALSE;
 		}
 		if (zfs_prop_set(zhp, "version", verstr) == 0)
 			cb->cb_numupgraded++;
@@ -3461,6 +3504,32 @@ zfs_do_set(int argc, char **argv)
 	return (ret);
 }
 
+typedef struct snap_cbdata {
+	nvlist_t *sd_nvl;
+	boolean_t sd_recursive;
+	const char *sd_snapname;
+} snap_cbdata_t;
+
+static int
+zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
+{
+	snap_cbdata_t *sd = arg;
+	char *name;
+	int rv = 0;
+	int error;
+
+	error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
+	if (error == -1)
+		nomem();
+	fnvlist_add_boolean(sd->sd_nvl, name);
+	free(name);
+
+	if (sd->sd_recursive)
+		rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
+	zfs_close(zhp);
+	return (rv);
+}
+
 /*
  * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
  *
@@ -3470,13 +3539,16 @@ zfs_do_set(int argc, char **argv)
 static int
 zfs_do_snapshot(int argc, char **argv)
 {
-	boolean_t recursive = B_FALSE;
 	int ret = 0;
 	char c;
 	nvlist_t *props;
+	snap_cbdata_t sd = { 0 };
+	boolean_t multiple_snaps = B_FALSE;
 
 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
 		nomem();
+	if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
+		nomem();
 
 	/* check options */
 	while ((c = getopt(argc, argv, "ro:")) != -1) {
@@ -3486,7 +3558,8 @@ zfs_do_snapshot(int argc, char **argv)
 				return (1);
 			break;
 		case 'r':
-			recursive = B_TRUE;
+			sd.sd_recursive = B_TRUE;
+			multiple_snaps = B_TRUE;
 			break;
 		case '?':
 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
@@ -3503,18 +3576,35 @@ zfs_do_snapshot(int argc, char **argv)
 		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
 		goto usage;
 	}
-	if (argc > 1) {
-		(void) fprintf(stderr, gettext("too many arguments\n"));
-		goto usage;
+
+	if (argc > 1)
+		multiple_snaps = B_TRUE;
+	for (; argc > 0; argc--, argv++) {
+		char *atp;
+		zfs_handle_t *zhp;
+
+		atp = strchr(argv[0], '@');
+		if (atp == NULL)
+			goto usage;
+		*atp = '\0';
+		sd.sd_snapname = atp + 1;
+		zhp = zfs_open(g_zfs, argv[0],
+		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+		if (zhp == NULL)
+			goto usage;
+		if (zfs_snapshot_cb(zhp, &sd) != 0)
+			goto usage;
 	}
 
-	ret = zfs_snapshot(g_zfs, argv[0], recursive, props);
+	ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
+	nvlist_free(sd.sd_nvl);
 	nvlist_free(props);
-	if (ret && recursive)
+	if (ret != 0 && multiple_snaps)
 		(void) fprintf(stderr, gettext("no snapshots were created\n"));
 	return (ret != 0);
 
 usage:
+	nvlist_free(sd.sd_nvl);
 	nvlist_free(props);
 	usage(B_FALSE);
 	return (-1);
@@ -5057,28 +5147,12 @@ cleanup2:
 	return (error);
 }
 
-/*
- * zfs allow [-r] [-t] <tag> <snap> ...
- *
- *	-r	Recursively hold
- *	-t	Temporary hold (hidden option)
- *
- * Apply a user-hold with the given tag to the list of snapshots.
- */
 static int
 zfs_do_allow(int argc, char **argv)
 {
 	return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE));
 }
 
-/*
- * zfs unallow [-r] [-t] <tag> <snap> ...
- *
- *	-r	Recursively hold
- *	-t	Temporary hold (hidden option)
- *
- * Apply a user-hold with the given tag to the list of snapshots.
- */
 static int
 zfs_do_unallow(int argc, char **argv)
 {
@@ -5092,7 +5166,6 @@ zfs_do_hold_rele_impl(int argc, char **a
 	int i;
 	const char *tag;
 	boolean_t recursive = B_FALSE;
-	boolean_t temphold = B_FALSE;
 	const char *opts = holding ? "rt" : "r";
 	int c;
 
@@ -5102,9 +5175,6 @@ zfs_do_hold_rele_impl(int argc, char **a
 		case 'r':
 			recursive = B_TRUE;
 			break;
-		case 't':
-			temphold = B_TRUE;
-			break;
 		case '?':
 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
 			    optopt);
@@ -5153,7 +5223,7 @@ zfs_do_hold_rele_impl(int argc, char **a
 		}
 		if (holding) {
 			if (zfs_hold(zhp, delim+1, tag, recursive,
-			    temphold, B_FALSE, -1, 0, 0) != 0)
+			    B_FALSE, -1) != 0)
 				++errors;
 		} else {
 			if (zfs_release(zhp, delim+1, tag, recursive) != 0)
@@ -5169,7 +5239,6 @@ zfs_do_hold_rele_impl(int argc, char **a
  * zfs hold [-r] [-t] <tag> <snap> ...
  *
  *	-r	Recursively hold
- *	-t	Temporary hold (hidden option)
  *
  * Apply a user-hold with the given tag to the list of snapshots.
  */
@@ -6591,8 +6660,7 @@ main(int argc, char **argv)
 		return (1);
 	}
 
-	zpool_set_history_str("zfs", argc, argv, history_str);
-	verify(zpool_stage_history(g_zfs, history_str) == 0);
+	zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
 
 	libzfs_print_on_error(g_zfs, B_TRUE);
 
@@ -6661,6 +6729,9 @@ main(int argc, char **argv)
 
 	(void) fclose(mnttab_file);
 
+	if (ret == 0 && log_history)
+		(void) zpool_log_history(g_zfs, history_str);
+
 	libzfs_fini(g_zfs);
 
 	/*

Modified: stable/9/cddl/contrib/opensolaris/cmd/zhack/zhack.c
==============================================================================
--- stable/9/cddl/contrib/opensolaris/cmd/zhack/zhack.c	Fri Apr 19 08:06:45 2013	(r249642)
+++ stable/9/cddl/contrib/opensolaris/cmd/zhack/zhack.c	Fri Apr 19 09:19:10 2013	(r249643)
@@ -46,6 +46,7 @@
 #include <sys/zio_checksum.h>
 #include <sys/zio_compress.h>
 #include <sys/zfeature.h>
+#include <sys/dmu_tx.h>
 #undef ZFS_MAXNAMELEN
 #undef verify
 #include <libzfs.h>
@@ -273,12 +274,15 @@ zhack_do_feature_stat(int argc, char **a
 }
 
 static void
-feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+feature_enable_sync(void *arg, dmu_tx_t *tx)
 {
-	spa_t *spa = arg1;
-	zfeature_info_t *feature = arg2;
+	spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+	zfeature_info_t *feature = arg;
 
 	spa_feature_enable(spa, feature, tx);
+	spa_history_log_internal(spa, "zhack enable feature", tx,
+	    "name=%s can_readonly=%u",
+	    feature->fi_guid, feature->fi_can_readonly);
 }
 
 static void
@@ -341,8 +345,8 @@ zhack_do_feature_enable(int argc, char *
 	if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
 		fatal("feature already enabled: %s", feature.fi_guid);
 
-	VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
-	    feature_enable_sync, spa, &feature, 5));
+	VERIFY0(dsl_sync_task(spa_name(spa), NULL,
+	    feature_enable_sync, &feature, 5));
 
 	spa_close(spa, FTAG);
 
@@ -350,21 +354,25 @@ zhack_do_feature_enable(int argc, char *
 }
 
 static void
-feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+feature_incr_sync(void *arg, dmu_tx_t *tx)
 {
-	spa_t *spa = arg1;
-	zfeature_info_t *feature = arg2;
+	spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+	zfeature_info_t *feature = arg;
 
 	spa_feature_incr(spa, feature, tx);
+	spa_history_log_internal(spa, "zhack feature incr", tx,
+	    "name=%s", feature->fi_guid);
 }
 
 static void
-feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+feature_decr_sync(void *arg, dmu_tx_t *tx)
 {
-	spa_t *spa = arg1;
-	zfeature_info_t *feature = arg2;
+	spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+	zfeature_info_t *feature = arg;
 
 	spa_feature_decr(spa, feature, tx);
+	spa_history_log_internal(spa, "zhack feature decr", tx,
+	    "name=%s", feature->fi_guid);
 }
 
 static void
@@ -435,8 +443,8 @@ zhack_do_feature_ref(int argc, char **ar
 	if (decr && !spa_feature_is_active(spa, &feature))
 		fatal("feature refcount already 0: %s", feature.fi_guid);
 
-	VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
-	    decr ? feature_decr_sync : feature_incr_sync, spa, &feature, 5));
+	VERIFY0(dsl_sync_task(spa_name(spa), NULL,
+	    decr ? feature_decr_sync : feature_incr_sync, &feature, 5));
 
 	spa_close(spa, FTAG);
 }

Modified: stable/9/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
==============================================================================
--- stable/9/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c	Fri Apr 19 08:06:45 2013	(r249642)
+++ stable/9/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c	Fri Apr 19 09:19:10 2013	(r249643)
@@ -192,9 +192,9 @@ static zpool_command_t command_table[] =
 
 #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
 
-zpool_command_t *current_command;
+static zpool_command_t *current_command;
 static char history_str[HIS_MAX_RECORD_LEN];
-
+static boolean_t log_history = B_TRUE;
 static uint_t timestamp_fmt = NODATE;
 
 static const char *
@@ -1092,7 +1092,10 @@ zpool_do_destroy(int argc, char **argv)
 		return (1);
 	}
 
-	ret = (zpool_destroy(zhp) != 0);
+	/* The history must be logged as part of the export */
+	log_history = B_FALSE;
+
+	ret = (zpool_destroy(zhp, history_str) != 0);
 
 	zpool_close(zhp);
 
@@ -1156,10 +1159,13 @@ zpool_do_export(int argc, char **argv)
 			continue;
 		}
 
+		/* The history must be logged as part of the export */
+		log_history = B_FALSE;
+
 		if (hardforce) {
-			if (zpool_export_force(zhp) != 0)
+			if (zpool_export_force(zhp, history_str) != 0)
 				ret = 1;
-		} else if (zpool_export(zhp, force) != 0) {
+		} else if (zpool_export(zhp, force, history_str) != 0) {
 			ret = 1;
 		}
 
@@ -4562,6 +4568,14 @@ upgrade_cb(zpool_handle_t *zhp, void *ar
 		if (count > 0) {
 			cbp->cb_first = B_FALSE;
 			printnl = B_TRUE;
+			/*
+			 * If they did "zpool upgrade -a", then we could
+			 * be doing ioctls to different pools.  We need
+			 * to log this history once to each pool, and bypass
+			 * the normal history logging that happens in main().
+			 */
+			(void) zpool_log_history(g_zfs, history_str);
+			log_history = B_FALSE;
 		}
 	}
 
@@ -4923,8 +4937,8 @@ zpool_do_upgrade(int argc, char **argv)
 
 typedef struct hist_cbdata {
 	boolean_t first;
-	int longfmt;
-	int internal;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304190919.r3J9JA19035885>