Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Nov 2011 21:40:00 +0000 (UTC)
From:      Martin Matuska <mm@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r228103 - in head: cddl/contrib/opensolaris/cmd/zfs cddl/contrib/opensolaris/cmd/zpool cddl/contrib/opensolaris/cmd/ztest cddl/contrib/opensolaris/lib/libzfs/common cddl/lib/libzfs sys/...
Message-ID:  <201111282140.pASLe0A9010284@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <pawel@dawidek.net>.
- * All rights reserved.
+ * Copyright (c) 2011 Martin Matuska <mm@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 <mm@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 ***



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