6873727 zfs destroy -d <fs> should fail more gracefully when children are present
authorChris Kirby <chris.kirby@sun.com>
Wed, 26 Aug 2009 12:54:24 -0600
changeset 10385 21cb6e67d108
parent 10384 73bb2903cf6f
child 10386 935ab057bcbb
6873727 zfs destroy -d <fs> should fail more gracefully when children are present
usr/src/cmd/zfs/zfs_main.c
usr/src/uts/common/fs/zfs/dsl_dataset.c
--- a/usr/src/cmd/zfs/zfs_main.c	Wed Aug 26 10:24:43 2009 -0700
+++ b/usr/src/cmd/zfs/zfs_main.c	Wed Aug 26 12:54:24 2009 -0600
@@ -197,9 +197,8 @@
 		    "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
 		    "-V <size> <volume>\n"));
 	case HELP_DESTROY:
-		return (gettext("\tdestroy [-rRf] "
-		    "<filesystem|volume|snapshot>\n"
-		    "\tdestroy -d [-r] <filesystem|volume|snapshot>\n"));
+		return (gettext("\tdestroy [-rRf] <filesystem|volume>\n"
+		    "\tdestroy [-rRd] <snapshot>\n"));
 	case HELP_GET:
 		return (gettext("\tget [-rHp] [-d max] "
 		    "[-o field[,...]] [-s source[,...]]\n"
@@ -785,8 +784,8 @@
 }
 
 /*
- * zfs destroy [-rRf] <fs, snap, vol>
- * zfs destroy -d [-r] <fs, snap, vol>
+ * zfs destroy [-rRf] <fs, vol>
+ * zfs destroy [-rRd] <snap>
  *
  * 	-r	Recursively destroy all children
  * 	-R	Recursively destroy all dependents, including clones
@@ -940,12 +939,14 @@
 	int c;
 	zfs_handle_t *zhp;
 	char *cp;
+	zfs_type_t type = ZFS_TYPE_DATASET;
 
 	/* check options */
 	while ((c = getopt(argc, argv, "dfrR")) != -1) {
 		switch (c) {
 		case 'd':
 			cb.cb_defer_destroy = B_TRUE;
+			type = ZFS_TYPE_SNAPSHOT;
 			break;
 		case 'f':
 			cb.cb_force = 1;
@@ -978,9 +979,6 @@
 		usage(B_FALSE);
 	}
 
-	if (cb.cb_defer_destroy && cb.cb_doclones)
-		usage(B_FALSE);
-
 	/*
 	 * If we are doing recursive destroy of a snapshot, then the
 	 * named snapshot may not exist.  Go straight to libzfs.
@@ -995,11 +993,19 @@
 		cp++;
 
 		if (cb.cb_doclones) {
+			boolean_t defer = cb.cb_defer_destroy;
+
+			/*
+			 * 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);
 			}
+			cb.cb_defer_destroy = defer;
 		}
 
 		ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy);
@@ -1012,7 +1018,7 @@
 	}
 
 	/* Open the given dataset */
-	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
+	if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
 		return (1);
 
 	cb.cb_target = zhp;
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c	Wed Aug 26 10:24:43 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c	Wed Aug 26 12:54:24 2009 -0600
@@ -1036,13 +1036,15 @@
 			dmu_objset_evict(ds->ds_objset);
 			ds->ds_objset = NULL;
 		}
-		/* NOTE: defer is always B_FALSE for non-snapshots */
 		dsda.defer = defer;
 		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
 		    dsl_dataset_destroy_check, dsl_dataset_destroy_sync,
 		    &dsda, tag, 0);
 		ASSERT3P(dsda.rm_origin, ==, NULL);
 		goto out;
+	} else if (defer) {
+		err = EINVAL;
+		goto out;
 	}
 
 	dd = ds->ds_dir;