Author: mm
Date: Mon Nov 28 21:40:00 2011
New Revision: 228103
URL: http://svn.freebsd.org/changeset/base/228103

Log:
  Merge new ZFS features from illumos:
  
  1644 add ZFS "clones" property
  https://www.illumos.org/issues/1644
  
  1645 add ZFS "written" and "written@..." properties
  https://www.illumos.org/issues/1645
  
  1646 "zfs send" should estimate size of stream
  https://www.illumos.org/issues/1646
  
  1647 "zfs destroy" should determine space reclaimed by destroying multiple
  snapshots
  https://www.illumos.org/issues/1647
  
  1693 persistent 'comment' field for a zpool
  https://www.illumos.org/issues/1693
  
  1708 adjust size of zpool history data
  https://www.illumos.org/issues/1708
  
  1748 desire support for reguid in zfs
  https://www.illumos.org/issues/1748
  
  Obtained from:        illumos (changesets 13514, 13524, 13525)
  MFC after:    1 month

Added:
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
Deleted:
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_graph.c
Modified:
  head/cddl/contrib/opensolaris/cmd/zfs/zfs.8
  head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
  head/cddl/contrib/opensolaris/cmd/zpool/zpool.8
  head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
  head/cddl/contrib/opensolaris/cmd/ztest/ztest.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
  head/cddl/lib/libzfs/Makefile
  head/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c
  head/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.h
  head/sys/cddl/contrib/opensolaris/common/zfs/zpool_prop.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bpobj.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_deadlist.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_deleg.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_history.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_deleg.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap_micro.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
  head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
  head/sys/cddl/contrib/opensolaris/uts/common/sys/sysevent/eventdefs.h

Modified: head/cddl/contrib/opensolaris/cmd/zfs/zfs.8
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zfs/zfs.8 Mon Nov 28 20:48:35 2011        
(r228102)
+++ head/cddl/contrib/opensolaris/cmd/zfs/zfs.8 Mon Nov 28 21:40:00 2011        
(r228103)
@@ -48,12 +48,16 @@
 .Ar size volume
 .Nm
 .Cm destroy
-.Op Fl rRf
+.Op Fl fnpRrv
 .Ar filesystem Ns | Ns Ar volume
 .Nm
 .Cm destroy
-.Op Fl rRd
+.Op Fl dnpRrv
+.Sm off
 .Ar snapshot
+.Ns Op % Ns Ar snapname
+.Ns Op , Ns Ar ...
+.Sm on
 .Nm
 .Cm snapshot
 .Op Fl r
@@ -160,7 +164,7 @@
 .Fl a | Ar filesystem Ns | Ns Ar mountpoint
 .Nm
 .Cm send
-.Op Fl DvRp
+.Op Fl DnPpRrv
 .Op Fl i Ar snapshot | Fl I Ar snapshot
 .Ar snapshot
 .Nm
@@ -487,6 +491,17 @@ The default value is
 .Cm off .
 .It Sy creation
 The time this dataset was created.
+.It Sy clones
+For snapshots, this property is a comma-separated list of filesystems or
+volumes which are clones of this snapshot.  The clones'
+.Sy origin
+property is this snapshot.  If the
+.Sy clones
+property is not empty, then this snapshot can not be destroyed (even with the
+.Fl r
+or
+.Fl f
+options).
 .It Sy defer_destroy
 This property is
 .Cm on
@@ -644,6 +659,28 @@ power of 2 from 512 bytes to 128 Kbytes 
 .Pp
 This property can also be referred to by its shortened column name,
 .Sy volblock .
+.It Sy written
+The amount of
+.Sy referenced
+space written to this dataset since the previous snapshot.
+.It Sy written@ Ns Ar snapshot
+The amount of
+.Sy referenced
+space written to this dataset since the specified snapshot.  This is the space
+that is referenced by this dataset but was not referenced by the specified
+snapshot.
+.Pp
+The
+.Ar snapshot
+may be specified as a short snapshot name (just the part after the
+.Sy @ Ns ),
+in which case it will be interpreted as a snapshot in the same filesystem as
+this dataset. The
+.Ar snapshot
+may be a full snapshot name
+.Pq Em filesystem@snapshot ,
+which for clones may be a snapshot in the origin's filesystem (or the origin of
+the origin's filesystem, etc).
 .El
 .Pp
 The following native properties can be used to change the behavior of a
@@ -1403,7 +1440,7 @@ options.
 .It Xo
 .Nm
 .Cm destroy
-.Op Fl rRf
+.Op Fl fnpRrv
 .Ar filesystem Ns | Ns Ar volume
 .Xc
 .Pp
@@ -1422,6 +1459,17 @@ Force an unmount of any file systems usi
 .Qq Nm Cm unmount Fl f
 command. This option has no effect on non-file systems or unmounted file
 systems.
+.It Fl n
+Do a dry-run ("No-op") deletion. No data will be deleted. This is useful in
+conjunction with the
+.Fl v
+or
+.Fl p
+flags to determine what data would be deleted.
+.It Fl p
+Print machine-parsable verbose information about the deleted data.
+.It Fl v
+Print verbose information about the deleted data.
 .El
 .Pp
 Extreme care should be taken when applying either the
@@ -1433,11 +1481,15 @@ behavior for mounted file systems in use
 .It Xo
 .Nm
 .Cm destroy
-.Op Fl rRd
+.Op Fl dnpRrv
+.Sm off
 .Ar snapshot
+.Ns Op % Ns Ar snapname
+.Ns Op , Ns Ar ...
+.Sm on
 .Xc
 .Pp
-The given snapshot is destroyed immediately if and only if the
+The given snapshots are destroyed immediately if and only if the
 .Qq Nm Cm destroy
 command without the
 .Fl d
@@ -1445,15 +1497,41 @@ option would have destroyed it. Such imm
 example, if the snapshot had no clones and the user-initiated reference count
 were zero.
 .Pp
-If the snapshot does not qualify for immediate destruction, it is marked for
+If a snapshot does not qualify for immediate destruction, it is marked for
 deferred deletion. In this state, it exists as a usable, visible snapshot until
 both of the preconditions listed above are met, at which point it is destroyed.
+.Pp
+An inclusive range of snapshots may be specified by separating the
+first and last snapshots with a percent sign
+.Pq Sy % .
+The first and/or last snapshots may be left blank, in which case the
+filesystem's oldest or newest snapshot will be implied.
+.Pp
+Multiple snapshots
+(or ranges of snapshots) of the same filesystem or volume may be specified
+in a comma-separated list of snapshots.
+Only the snapshot's short name (the
+part after the
+.Sy @ )
+should be specified when using a range or comma-separated list to identify
+multiple snapshots.
 .Bl -tag -width indent
 .It Fl r
 Destroy (or mark for deferred deletion) all snapshots with this name in
 descendent file systems.
 .It Fl R
 Recursively destroy all dependents.
+.It Fl n
+Do a dry-run ("No-op") deletion. No data will be deleted. This is useful in
+conjunction with the
+.Fl v
+or
+.Fl p
+flags to determine what data would be deleted.
+.It Fl p
+Print machine-parsable verbose information about the deleted data.
+.It Fl v
+Print verbose information about the deleted data.
 .It Fl d
 Defer snapshot deletion.
 .El
@@ -2080,7 +2158,7 @@ file system shared on the system.
 .It Xo
 .Nm
 .Cm send
-.Op Fl DvRp
+.Op Fl DnPpRrv
 .Op Fl i Ar snapshot | Fl I Ar snapshot
 .Ar snapshot
 .Xc
@@ -2151,10 +2229,26 @@ be used regardless of the dataset's
 property, but performance will be much better if the filesystem uses a
 dedup-capable checksum (eg.
 .Sy sha256 Ns ).
+.It Fl r
+Recursively send all descendant snapshots.  This is similar to the
+.Fl R
+flag, but information about deleted and renamed datasets is not included, and
+property information is only included if the
+.Fl p
+flag is specified.
 .It Fl p
 Include the dataset's properties in the stream. This flag is implicit when
 .Fl R
 is specified. The receiving system must also support this feature.
+.It Fl n
+Do a dry-run ("No-op") send.  Do not generate any actual send data.  This is
+useful in conjunction with the
+.Fl v
+or
+.Fl P
+flags to determine what data will be sent.
+.It Fl P
+Print machine-parsable verbose information about the stream package generated.
 .It Fl v
 Print verbose information about the stream package generated.
 .El

Modified: head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c    Mon Nov 28 20:48:35 
2011        (r228102)
+++ head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c    Mon Nov 28 21:40:00 
2011        (r228103)
@@ -22,8 +22,9 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
  * Copyright (c) 2011 Pawel Jakub Dawidek <pa...@dawidek.net>.
- * All rights reserved.
+ * Copyright (c) 2011 Martin Matuska <m...@freebsd.org>. All rights reserved.
  */
 
 #include <assert.h>
@@ -145,7 +146,7 @@ typedef enum {
        HELP_HOLD,
        HELP_HOLDS,
        HELP_RELEASE,
-       HELP_DIFF
+       HELP_DIFF,
 } zfs_help_t;
 
 typedef struct zfs_command {
@@ -220,8 +221,9 @@ get_usage(zfs_help_t idx)
                    "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
                    "-V <size> <volume>\n"));
        case HELP_DESTROY:
-               return (gettext("\tdestroy [-rRf] <filesystem|volume>\n"
-                   "\tdestroy [-rRd] <snapshot>\n"));
+               return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
+                   "\tdestroy [-dnpRrv] "
+                   "<snapshot>[%<snapname>][,...]\n"));
        case HELP_GET:
                return (gettext("\tget [-rHp] [-d max] "
                    "[-o \"all\" | field[,...]] [-s source[,...]]\n"
@@ -260,7 +262,7 @@ get_usage(zfs_help_t idx)
        case HELP_ROLLBACK:
                return (gettext("\trollback [-rRf] <snapshot>\n"));
        case HELP_SEND:
-               return (gettext("\tsend [-DvRp] "
+               return (gettext("\tsend [-DnPpRrv] "
                    "[-i snapshot | -I snapshot] <snapshot>\n"));
        case HELP_SET:
                return (gettext("\tset <property=value> "
@@ -440,6 +442,8 @@ usage(boolean_t requested)
                (void) fprintf(fp, "YES       NO   <size> | none\n");
                (void) fprintf(fp, "\t%-15s ", "groupquota@...");
                (void) fprintf(fp, "YES       NO   <size> | none\n");
+               (void) fprintf(fp, "\t%-15s ", "written@<snap>");
+               (void) fprintf(fp, " NO       NO   <size>\n");
 
                (void) fprintf(fp, gettext("\nSizes are specified in bytes "
                    "with standard units such as K, M, G, etc.\n"));
@@ -885,15 +889,23 @@ badusage:
  */
 typedef struct destroy_cbdata {
        boolean_t       cb_first;
-       int             cb_force;
-       int             cb_recurse;
-       int             cb_error;
-       int             cb_needforce;
-       int             cb_doclones;
-       boolean_t       cb_closezhp;
+       boolean_t       cb_force;
+       boolean_t       cb_recurse;
+       boolean_t       cb_error;
+       boolean_t       cb_doclones;
        zfs_handle_t    *cb_target;
-       char            *cb_snapname;
        boolean_t       cb_defer_destroy;
+       boolean_t       cb_verbose;
+       boolean_t       cb_parsable;
+       boolean_t       cb_dryrun;
+       nvlist_t        *cb_nvl;
+
+       /* first snap in contiguous run */
+       zfs_handle_t    *cb_firstsnap;
+       /* previous snap in contiguous run */
+       zfs_handle_t    *cb_prevsnap;
+       int64_t         cb_snapused;
+       char            *cb_snapspec;
 } destroy_cbdata_t;
 
 /*
@@ -923,7 +935,7 @@ destroy_check_dependent(zfs_handle_t *zh
                        (void) fprintf(stderr, gettext("use '-r' to destroy "
                            "the following datasets:\n"));
                        cbp->cb_first = B_FALSE;
-                       cbp->cb_error = 1;
+                       cbp->cb_error = B_TRUE;
                }
 
                (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
@@ -944,7 +956,8 @@ destroy_check_dependent(zfs_handle_t *zh
                        (void) fprintf(stderr, gettext("use '-R' to destroy "
                            "the following datasets:\n"));
                        cbp->cb_first = B_FALSE;
-                       cbp->cb_error = 1;
+                       cbp->cb_error = B_TRUE;
+                       cbp->cb_dryrun = B_TRUE;
                }
 
                (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
@@ -958,7 +971,20 @@ out:
 static int
 destroy_callback(zfs_handle_t *zhp, void *data)
 {
-       destroy_cbdata_t *cbp = data;
+       destroy_cbdata_t *cb = data;
+       const char *name = zfs_get_name(zhp);
+
+       if (cb->cb_verbose) {
+               if (cb->cb_parsable) {
+                       (void) printf("destroy\t%s\n", name);
+               } else if (cb->cb_dryrun) {
+                       (void) printf(gettext("would destroy %s\n"),
+                           name);
+               } else {
+                       (void) printf(gettext("will destroy %s\n"),
+                           name);
+               }
+       }
 
        /*
         * Ignore pools (which we've already flagged as an error before getting
@@ -970,13 +996,12 @@ destroy_callback(zfs_handle_t *zhp, void
                return (0);
        }
 
-       /*
-        * Bail out on the first error.
-        */
-       if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 ||
-           zfs_destroy(zhp, cbp->cb_defer_destroy) != 0) {
-               zfs_close(zhp);
-               return (-1);
+       if (!cb->cb_dryrun) {
+               if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
+                   zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
+                       zfs_close(zhp);
+                       return (-1);
+               }
        }
 
        zfs_close(zhp);
@@ -984,39 +1009,142 @@ destroy_callback(zfs_handle_t *zhp, void
 }
 
 static int
-destroy_snap_clones(zfs_handle_t *zhp, void *arg)
+destroy_print_cb(zfs_handle_t *zhp, void *arg)
 {
-       destroy_cbdata_t *cbp = arg;
-       char thissnap[MAXPATHLEN];
-       zfs_handle_t *szhp;
-       boolean_t closezhp = cbp->cb_closezhp;
-       int rv;
+       destroy_cbdata_t *cb = arg;
+       const char *name = zfs_get_name(zhp);
+       int err = 0;
 
-       (void) snprintf(thissnap, sizeof (thissnap),
-           "%s@%s", zfs_get_name(zhp), cbp->cb_snapname);
+       if (nvlist_exists(cb->cb_nvl, name)) {
+               if (cb->cb_firstsnap == NULL)
+                       cb->cb_firstsnap = zfs_handle_dup(zhp);
+               if (cb->cb_prevsnap != NULL)
+                       zfs_close(cb->cb_prevsnap);
+               /* this snap continues the current range */
+               cb->cb_prevsnap = zfs_handle_dup(zhp);
+               if (cb->cb_verbose) {
+                       if (cb->cb_parsable) {
+                               (void) printf("destroy\t%s\n", name);
+                       } else if (cb->cb_dryrun) {
+                               (void) printf(gettext("would destroy %s\n"),
+                                   name);
+                       } else {
+                               (void) printf(gettext("will destroy %s\n"),
+                                   name);
+                       }
+               }
+       } else if (cb->cb_firstsnap != NULL) {
+               /* end of this range */
+               uint64_t used = 0;
+               err = zfs_get_snapused_int(cb->cb_firstsnap,
+                   cb->cb_prevsnap, &used);
+               cb->cb_snapused += used;
+               zfs_close(cb->cb_firstsnap);
+               cb->cb_firstsnap = NULL;
+               zfs_close(cb->cb_prevsnap);
+               cb->cb_prevsnap = NULL;
+       }
+       zfs_close(zhp);
+       return (err);
+}
 
-       libzfs_print_on_error(g_zfs, B_FALSE);
-       szhp = zfs_open(g_zfs, thissnap, ZFS_TYPE_SNAPSHOT);
-       libzfs_print_on_error(g_zfs, B_TRUE);
-       if (szhp) {
-               /*
-                * Destroy any clones of this snapshot
-                */
-               if (zfs_iter_dependents(szhp, B_FALSE, destroy_callback,
-                   cbp) != 0) {
-                       zfs_close(szhp);
-                       if (closezhp)
-                               zfs_close(zhp);
-                       return (-1);
+static int
+destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
+{
+       int err;
+       assert(cb->cb_firstsnap == NULL);
+       assert(cb->cb_prevsnap == NULL);
+       err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
+       if (cb->cb_firstsnap != NULL) {
+               uint64_t used = 0;
+               if (err == 0) {
+                       err = zfs_get_snapused_int(cb->cb_firstsnap,
+                           cb->cb_prevsnap, &used);
                }
-               zfs_close(szhp);
+               cb->cb_snapused += used;
+               zfs_close(cb->cb_firstsnap);
+               cb->cb_firstsnap = NULL;
+               zfs_close(cb->cb_prevsnap);
+               cb->cb_prevsnap = NULL;
        }
+       return (err);
+}
 
-       cbp->cb_closezhp = B_TRUE;
-       rv = zfs_iter_filesystems(zhp, destroy_snap_clones, arg);
-       if (closezhp)
-               zfs_close(zhp);
-       return (rv);
+static int
+snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
+{
+       destroy_cbdata_t *cb = arg;
+       int err = 0;
+
+       /* Check for clones. */
+       if (!cb->cb_doclones) {
+               cb->cb_target = zhp;
+               cb->cb_first = B_TRUE;
+               err = zfs_iter_dependents(zhp, B_TRUE,
+                   destroy_check_dependent, cb);
+       }
+
+       if (err == 0) {
+               if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
+                       nomem();
+       }
+       zfs_close(zhp);
+       return (err);
+}
+
+static int
+gather_snapshots(zfs_handle_t *zhp, void *arg)
+{
+       destroy_cbdata_t *cb = arg;
+       int err = 0;
+
+       err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb);
+       if (err == ENOENT)
+               err = 0;
+       if (err != 0)
+               goto out;
+
+       if (cb->cb_verbose) {
+               err = destroy_print_snapshots(zhp, cb);
+               if (err != 0)
+                       goto out;
+       }
+
+       if (cb->cb_recurse)
+               err = zfs_iter_filesystems(zhp, gather_snapshots, cb);
+
+out:
+       zfs_close(zhp);
+       return (err);
+}
+
+static int
+destroy_clones(destroy_cbdata_t *cb)
+{
+       nvpair_t *pair;
+       for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
+           pair != NULL;
+           pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
+               zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
+                   ZFS_TYPE_SNAPSHOT);
+               if (zhp != NULL) {
+                       boolean_t defer = cb->cb_defer_destroy;
+                       int err;
+
+                       /*
+                        * We can't defer destroy non-snapshots, so set it to
+                        * false while destroying the clones.
+                        */
+                       cb->cb_defer_destroy = B_FALSE;
+                       err = zfs_iter_dependents(zhp, B_FALSE,
+                           destroy_callback, cb);
+                       cb->cb_defer_destroy = defer;
+                       zfs_close(zhp);
+                       if (err != 0)
+                               return (err);
+               }
+       }
+       return (0);
 }
 
 static int
@@ -1025,25 +1153,35 @@ zfs_do_destroy(int argc, char **argv)
        destroy_cbdata_t cb = { 0 };
        int c;
        zfs_handle_t *zhp;
-       char *cp;
+       char *at;
        zfs_type_t type = ZFS_TYPE_DATASET;
 
        /* check options */
-       while ((c = getopt(argc, argv, "dfrR")) != -1) {
+       while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
                switch (c) {
+               case 'v':
+                       cb.cb_verbose = B_TRUE;
+                       break;
+               case 'p':
+                       cb.cb_verbose = B_TRUE;
+                       cb.cb_parsable = B_TRUE;
+                       break;
+               case 'n':
+                       cb.cb_dryrun = B_TRUE;
+                       break;
                case 'd':
                        cb.cb_defer_destroy = B_TRUE;
                        type = ZFS_TYPE_SNAPSHOT;
                        break;
                case 'f':
-                       cb.cb_force = 1;
+                       cb.cb_force = B_TRUE;
                        break;
                case 'r':
-                       cb.cb_recurse = 1;
+                       cb.cb_recurse = B_TRUE;
                        break;
                case 'R':
-                       cb.cb_recurse = 1;
-                       cb.cb_doclones = 1;
+                       cb.cb_recurse = B_TRUE;
+                       cb.cb_doclones = B_TRUE;
                        break;
                case '?':
                default:
@@ -1058,7 +1196,7 @@ zfs_do_destroy(int argc, char **argv)
 
        /* check number of arguments */
        if (argc == 0) {
-               (void) fprintf(stderr, gettext("missing path argument\n"));
+               (void) fprintf(stderr, gettext("missing dataset argument\n"));
                usage(B_FALSE);
        }
        if (argc > 1) {
@@ -1066,91 +1204,117 @@ zfs_do_destroy(int argc, char **argv)
                usage(B_FALSE);
        }
 
-       /*
-        * If we are doing recursive destroy of a snapshot, then the
-        * named snapshot may not exist.  Go straight to libzfs.
-        */
-       if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) {
-               int ret;
+       at = strchr(argv[0], '@');
+       if (at != NULL) {
+               int err;
 
-               *cp = '\0';
-               if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
+               /* Build the list of snaps to destroy in cb_nvl. */
+               if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
+                       nomem();
+
+               *at = '\0';
+               zhp = zfs_open(g_zfs, argv[0],
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+               if (zhp == NULL)
                        return (1);
-               *cp = '@';
-               cp++;
 
-               if (cb.cb_doclones) {
-                       boolean_t defer = cb.cb_defer_destroy;
+               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);
+               }
 
-                       /*
-                        * Temporarily ignore the defer_destroy setting since
-                        * it's not supported for clones.
-                        */
-                       cb.cb_defer_destroy = B_FALSE;
-                       cb.cb_snapname = cp;
-                       if (destroy_snap_clones(zhp, &cb) != 0) {
-                               zfs_close(zhp);
-                               return (1);
+               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);
+               }
+
+               if (cb.cb_verbose) {
+                       char buf[16];
+                       zfs_nicenum(cb.cb_snapused, buf, sizeof (buf));
+                       if (cb.cb_parsable) {
+                               (void) printf("reclaim\t%llu\n",
+                                   cb.cb_snapused);
+                       } else if (cb.cb_dryrun) {
+                               (void) printf(gettext("would reclaim %s\n"),
+                                   buf);
+                       } else {
+                               (void) printf(gettext("will reclaim %s\n"),
+                                   buf);
                        }
-                       cb.cb_defer_destroy = defer;
                }
 
-               ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy);
-               zfs_close(zhp);
-               if (ret) {
-                       (void) fprintf(stderr,
-                           gettext("no snapshots destroyed\n"));
+               if (!cb.cb_dryrun) {
+                       if (cb.cb_doclones)
+                               err = destroy_clones(&cb);
+                       if (err == 0) {
+                               err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl,
+                                   cb.cb_defer_destroy);
+                       }
                }
-               return (ret != 0);
-       }
 
-       /* Open the given dataset */
-       if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
-               return (1);
+               zfs_close(zhp);
+               nvlist_free(cb.cb_nvl);
+               if (err != 0)
+                       return (1);
+       } else {
+               /* Open the given dataset */
+               if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
+                       return (1);
 
-       cb.cb_target = zhp;
+               cb.cb_target = zhp;
 
-       /*
-        * Perform an explicit check for pools before going any further.
-        */
-       if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
-           zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
-               (void) fprintf(stderr, gettext("cannot destroy '%s': "
-                   "operation does not apply to pools\n"),
-                   zfs_get_name(zhp));
-               (void) fprintf(stderr, gettext("use 'zfs destroy -r "
-                   "%s' to destroy all datasets in the pool\n"),
-                   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);
-       }
+               /*
+                * Perform an explicit check for pools before going any further.
+                */
+               if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
+                   zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
+                       (void) fprintf(stderr, gettext("cannot destroy '%s': "
+                           "operation does not apply to pools\n"),
+                           zfs_get_name(zhp));
+                       (void) fprintf(stderr, gettext("use 'zfs destroy -r "
+                           "%s' to destroy all datasets in the pool\n"),
+                           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);
+               }
 
-       /*
-        * Check for any dependents and/or clones.
-        */
-       cb.cb_first = B_TRUE;
-       if (!cb.cb_doclones && !cb.cb_defer_destroy &&
-           zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
-           &cb) != 0) {
-               zfs_close(zhp);
-               return (1);
-       }
+               /*
+                * Check for any dependents and/or clones.
+                */
+               cb.cb_first = B_TRUE;
+               if (!cb.cb_doclones &&
+                   zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
+                   &cb) != 0) {
+                       zfs_close(zhp);
+                       return (1);
+               }
 
-       if (cb.cb_error || (!cb.cb_defer_destroy &&
-           (zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0))) {
-               zfs_close(zhp);
-               return (1);
-       }
+               if (cb.cb_error) {
+                       zfs_close(zhp);
+                       return (1);
+               }
 
-       /*
-        * Do the real thing.  The callback will close the handle regardless of
-        * whether it succeeds or not.
-        */
+               if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
+                   &cb) != 0) {
+                       zfs_close(zhp);
+                       return (1);
+               }
 
-       if (destroy_callback(zhp, &cb) != 0)
-               return (1);
+               /*
+                * 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);
+       }
 
        return (0);
 }
@@ -1252,6 +1416,17 @@ get_callback(zfs_handle_t *zhp, void *da
 
                        zprop_print_one_property(zfs_get_name(zhp), cbp,
                            pl->pl_user_prop, buf, sourcetype, source, NULL);
+               } else if (zfs_prop_written(pl->pl_user_prop)) {
+                       sourcetype = ZPROP_SRC_LOCAL;
+
+                       if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+                           buf, sizeof (buf), cbp->cb_literal) != 0) {
+                               sourcetype = ZPROP_SRC_NONE;
+                               (void) strlcpy(buf, "-", sizeof (buf));
+                       }
+
+                       zprop_print_one_property(zfs_get_name(zhp), cbp,
+                           pl->pl_user_prop, buf, sourcetype, source, NULL);
                } else {
                        if (nvlist_lookup_nvlist(user_props,
                            pl->pl_user_prop, &propval) != 0) {
@@ -1796,8 +1971,8 @@ zfs_do_upgrade(int argc, char **argv)
                    "---------------\n");
                (void) printf(gettext(" 1   Initial ZFS filesystem version\n"));
                (void) printf(gettext(" 2   Enhanced directory entries\n"));
-               (void) printf(gettext(" 3   Case insensitive and File system "
-                   "unique identifier (FUID)\n"));
+               (void) printf(gettext(" 3   Case insensitive and filesystem "
+                   "user identifier (FUID)\n"));
                (void) printf(gettext(" 4   userquota, groupquota "
                    "properties\n"));
                (void) printf(gettext(" 5   System attributes\n"));
@@ -2677,6 +2852,13 @@ print_dataset(zfs_handle_t *zhp, zprop_l
                        else
                                propstr = property;
                        right_justify = B_TRUE;
+               } else if (zfs_prop_written(pl->pl_user_prop)) {
+                       if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+                           property, sizeof (property), B_FALSE) != 0)
+                               propstr = "-";
+                       else
+                               propstr = property;
+                       right_justify = B_TRUE;
                } else {
                        if (nvlist_lookup_nvlist(userprops,
                            pl->pl_user_prop, &propval) != 0)
@@ -3303,9 +3485,6 @@ usage:
 }
 
 /*
- * zfs send [-vDp] -R [-i|-I <@snap>] <fs@snap>
- * zfs send [-vDp] [-i|-I <@snap>] <fs@snap>
- *
  * Send a backup stream to stdout.
  */
 static int
@@ -3317,11 +3496,11 @@ zfs_do_send(int argc, char **argv)
        zfs_handle_t *zhp;
        sendflags_t flags = { 0 };
        int c, err;
-       nvlist_t *dbgnv;
+       nvlist_t *dbgnv = NULL;
        boolean_t extraverbose = B_FALSE;
 
        /* check options */
-       while ((c = getopt(argc, argv, ":i:I:RDpv")) != -1) {
+       while ((c = getopt(argc, argv, ":i:I:RDpvnP")) != -1) {
                switch (c) {
                case 'i':
                        if (fromname)
@@ -3340,6 +3519,10 @@ zfs_do_send(int argc, char **argv)
                case 'p':
                        flags.props = B_TRUE;
                        break;
+               case 'P':
+                       flags.parsable = B_TRUE;
+                       flags.verbose = B_TRUE;
+                       break;
                case 'v':
                        if (flags.verbose)
                                extraverbose = B_TRUE;
@@ -3348,6 +3531,9 @@ zfs_do_send(int argc, char **argv)
                case 'D':
                        flags.dedup = B_TRUE;
                        break;
+               case 'n':
+                       flags.dryrun = B_TRUE;
+                       break;
                case ':':
                        (void) fprintf(stderr, gettext("missing argument for "
                            "'%c' option\n"), optopt);
@@ -3373,7 +3559,7 @@ zfs_do_send(int argc, char **argv)
                usage(B_FALSE);
        }
 
-       if (isatty(STDOUT_FILENO)) {
+       if (!flags.dryrun && isatty(STDOUT_FILENO)) {
                (void) fprintf(stderr,
                    gettext("Error: Stream can not be written to a terminal.\n"
                    "You must redirect standard output.\n"));
@@ -3427,10 +3613,10 @@ zfs_do_send(int argc, char **argv)
        if (flags.replicate && fromname == NULL)
                flags.doall = B_TRUE;
 
-       err = zfs_send(zhp, fromname, toname, flags, STDOUT_FILENO, NULL, 0,
+       err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0,
            extraverbose ? &dbgnv : NULL);
 
-       if (extraverbose) {
+       if (extraverbose && dbgnv != NULL) {
                /*
                 * dump_nvlist prints to stdout, but that's been
                 * redirected to a file.  Make it print to stderr
@@ -3511,7 +3697,7 @@ zfs_do_receive(int argc, char **argv)
                return (1);
        }
 
-       err = zfs_receive(g_zfs, argv[0], flags, STDIN_FILENO, NULL);
+       err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL);
 
        return (err != 0);
 }

Modified: head/cddl/contrib/opensolaris/cmd/zpool/zpool.8
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zpool/zpool.8     Mon Nov 28 20:48:35 
2011        (r228102)
+++ head/cddl/contrib/opensolaris/cmd/zpool/zpool.8     Mon Nov 28 21:40:00 
2011        (r228103)
@@ -23,7 +23,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 26, 2011
+.Dd November 28, 2011
 .Dt ZPOOL 8
 .Os
 .Sh NAME
@@ -133,6 +133,9 @@
 .Op Fl e
 .Ar pool device ...
 .Nm
+.Cm reguid
+.Ar pool
+.Nm
 .Cm remove
 .Ar pool device ...
 .Nm
@@ -1346,6 +1349,14 @@ available to the pool.
 .El
 .It Xo
 .Nm
+.Cm reguid
+.Ar pool
+.Xc
+.Pp
+Generates a new unique identifier for the pool.  You must ensure that all
+devices in this pool are online and healthy before performing this action.
+.It Xo
+.Nm
 .Cm remove
 .Ar pool device ...
 .Xc

Modified: head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c        Mon Nov 28 
20:48:35 2011        (r228102)
+++ head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c        Mon Nov 28 
21:40:00 2011        (r228103)
@@ -22,6 +22,8 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2011 Martin Matuska <m...@freebsd.org>. All rights reserved.
  */
 
 #include <solaris.h>
@@ -68,6 +70,8 @@ static int zpool_do_online(int, char **)
 static int zpool_do_offline(int, char **);
 static int zpool_do_clear(int, char **);
 
+static int zpool_do_reguid(int, char **);
+
 static int zpool_do_attach(int, char **);
 static int zpool_do_detach(int, char **);
 static int zpool_do_replace(int, char **);
@@ -126,7 +130,8 @@ typedef enum {
        HELP_UPGRADE,
        HELP_GET,
        HELP_SET,
-       HELP_SPLIT
+       HELP_SPLIT,
+       HELP_REGUID
 } zpool_help_t;
 
 
@@ -172,6 +177,7 @@ static zpool_command_t command_table[] =
        { "import",     zpool_do_import,        HELP_IMPORT             },
        { "export",     zpool_do_export,        HELP_EXPORT             },
        { "upgrade",    zpool_do_upgrade,       HELP_UPGRADE            },
+       { "reguid",     zpool_do_reguid,        HELP_REGUID             },
        { NULL },
        { "history",    zpool_do_history,       HELP_HISTORY            },
        { "get",        zpool_do_get,           HELP_GET                },
@@ -251,6 +257,8 @@ get_usage(zpool_help_t idx) {
                return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
                    "\t    [-o property=value] <pool> <newpool> "
                    "[<device> ...]\n"));
+       case HELP_REGUID:
+               return (gettext("\treguid <pool>\n"));
        }
 
        abort();
@@ -1454,6 +1462,7 @@ show_import(nvlist_t *config)
        const char *health;
        uint_t vsc;
        int namewidth;
+       char *comment;
 
        verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
            &name) == 0);
@@ -1470,9 +1479,9 @@ show_import(nvlist_t *config)
 
        reason = zpool_import_status(config, &msgid);
 
-       (void) printf(gettext("  pool: %s\n"), name);
-       (void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
-       (void) printf(gettext(" state: %s"), health);
+       (void) printf(gettext("   pool: %s\n"), name);
+       (void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
+       (void) printf(gettext("  state: %s"), health);
        if (pool_state == POOL_STATE_DESTROYED)
                (void) printf(gettext(" (DESTROYED)"));
        (void) printf("\n");
@@ -1481,58 +1490,59 @@ show_import(nvlist_t *config)
        case ZPOOL_STATUS_MISSING_DEV_R:
        case ZPOOL_STATUS_MISSING_DEV_NR:
        case ZPOOL_STATUS_BAD_GUID_SUM:
-               (void) printf(gettext("status: One or more devices are missing "
-                   "from the system.\n"));
+               (void) printf(gettext(" status: One or more devices are "
+                   "missing from the system.\n"));
                break;
 
        case ZPOOL_STATUS_CORRUPT_LABEL_R:
        case ZPOOL_STATUS_CORRUPT_LABEL_NR:
-               (void) printf(gettext("status: One or more devices contains "
+               (void) printf(gettext(" status: One or more devices contains "
                    "corrupted data.\n"));
                break;
 
        case ZPOOL_STATUS_CORRUPT_DATA:
-               (void) printf(gettext("status: The pool data is corrupted.\n"));
+               (void) printf(
+                   gettext(" status: The pool data is corrupted.\n"));
                break;
 

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to