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 ***
_______________________________________________
svn-src-stable-9@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to