summaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2009-08-18 11:43:27 -0700
committerBrian Behlendorf <[email protected]>2009-08-18 11:43:27 -0700
commit45d1cae3b8c949ecc391dd7a5b81963b34c71c29 (patch)
tree69b1f860eb1f9b1ebdef392760814c5cc089f345 /cmd
parent9babb37438b58e77bad04e820d5702e15b79e6a6 (diff)
Rebase master to b121
Diffstat (limited to 'cmd')
-rw-r--r--cmd/zdb/zdb.c3
-rw-r--r--cmd/zfs/zfs_iter.c2
-rw-r--r--cmd/zfs/zfs_main.c151
-rw-r--r--cmd/zpool/zpool_main.c34
-rw-r--r--cmd/zpool/zpool_vdev.c47
-rw-r--r--cmd/ztest/ztest.c18
6 files changed, 211 insertions, 44 deletions
diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c
index a310fc38b..292bb519a 100644
--- a/cmd/zdb/zdb.c
+++ b/cmd/zdb/zdb.c
@@ -818,6 +818,8 @@ dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
(u_longlong_t)ds->ds_snapnames_zapobj);
(void) printf("\t\tnum_children = %llu\n",
(u_longlong_t)ds->ds_num_children);
+ (void) printf("\t\tuserrefs_obj = %llu\n",
+ (u_longlong_t)ds->ds_userrefs_obj);
(void) printf("\t\tcreation_time = %s", ctime(&crtime));
(void) printf("\t\tcreation_txg = %llu\n",
(u_longlong_t)ds->ds_creation_txg);
@@ -1049,6 +1051,7 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES] = {
dump_zap, /* DSL scrub queue */
dump_zap, /* ZFS user/group used */
dump_zap, /* ZFS user/group quota */
+ dump_zap, /* snapshot refcount tags */
};
static void
diff --git a/cmd/zfs/zfs_iter.c b/cmd/zfs/zfs_iter.c
index ca5c2b232..04dd2bdeb 100644
--- a/cmd/zfs/zfs_iter.c
+++ b/cmd/zfs/zfs_iter.c
@@ -362,7 +362,7 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
cb.cb_types = types;
cb.cb_depth_limit = limit;
/*
- * If cb_proplist is provided then in the zfs_handles created we
+ * If cb_proplist is provided then in the zfs_handles created we
* retain only those properties listed in cb_proplist and sortcol.
* The rest are pruned. So, the caller should make sure that no other
* properties other than those listed in cb_proplist/sortcol are
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
index 0752a4772..1fbd8bc65 100644
--- a/cmd/zfs/zfs_main.c
+++ b/cmd/zfs/zfs_main.c
@@ -80,6 +80,8 @@ static int zfs_do_receive(int argc, char **argv);
static int zfs_do_promote(int argc, char **argv);
static int zfs_do_userspace(int argc, char **argv);
static int zfs_do_python(int argc, char **argv);
+static int zfs_do_hold(int argc, char **argv);
+static int zfs_do_release(int argc, char **argv);
/*
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
@@ -121,7 +123,10 @@ typedef enum {
HELP_ALLOW,
HELP_UNALLOW,
HELP_USERSPACE,
- HELP_GROUPSPACE
+ HELP_GROUPSPACE,
+ HELP_HOLD,
+ HELP_HOLDS,
+ HELP_RELEASE
} zfs_help_t;
typedef struct zfs_command {
@@ -169,6 +174,10 @@ static zfs_command_t command_table[] = {
{ "allow", zfs_do_python, HELP_ALLOW },
{ NULL },
{ "unallow", zfs_do_python, HELP_UNALLOW },
+ { NULL },
+ { "hold", zfs_do_hold, HELP_HOLD },
+ { "holds", zfs_do_python, HELP_HOLDS },
+ { "release", zfs_do_release, HELP_RELEASE },
};
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -189,7 +198,8 @@ get_usage(zfs_help_t idx)
"-V <size> <volume>\n"));
case HELP_DESTROY:
return (gettext("\tdestroy [-rRf] "
- "<filesystem|volume|snapshot>\n"));
+ "<filesystem|volume|snapshot>\n"
+ "\tdestroy -d [-r] <filesystem|volume|snapshot>\n"));
case HELP_GET:
return (gettext("\tget [-rHp] [-d max] "
"[-o field[,...]] [-s source[,...]]\n"
@@ -236,7 +246,7 @@ get_usage(zfs_help_t idx)
return (gettext("\tunmount [-f] "
"<-a | filesystem|mountpoint>\n"));
case HELP_UNSHARE:
- return (gettext("\tunshare [-f] "
+ return (gettext("\tunshare "
"<-a | filesystem|mountpoint>\n"));
case HELP_ALLOW:
return (gettext("\tallow <filesystem|volume>\n"
@@ -266,6 +276,12 @@ get_usage(zfs_help_t idx)
return (gettext("\tgroupspace [-hniHpU] [-o field[,...]] "
"[-sS field] ... [-t type[,...]]\n"
"\t <filesystem|snapshot>\n"));
+ case HELP_HOLD:
+ return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
+ case HELP_HOLDS:
+ return (gettext("\tholds [-r] <snapshot> ...\n"));
+ case HELP_RELEASE:
+ return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
}
abort();
@@ -769,11 +785,13 @@ badusage:
}
/*
- * zfs destroy [-rf] <fs, snap, vol>
+ * zfs destroy [-rRf] <fs, snap, vol>
+ * zfs destroy -d [-r] <fs, snap, vol>
*
* -r Recursively destroy all children
* -R Recursively destroy all dependents, including clones
* -f Force unmounting of any dependents
+ * -d If we can't destroy now, mark for deferred destruction
*
* Destroys the given dataset. By default, it will unmount any filesystems,
* and refuse to destroy a dataset that has any dependents. A dependent can
@@ -789,6 +807,7 @@ typedef struct destroy_cbdata {
boolean_t cb_closezhp;
zfs_handle_t *cb_target;
char *cb_snapname;
+ boolean_t cb_defer_destroy;
} destroy_cbdata_t;
/*
@@ -869,7 +888,7 @@ destroy_callback(zfs_handle_t *zhp, void *data)
* Bail out on the first error.
*/
if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 ||
- zfs_destroy(zhp) != 0) {
+ zfs_destroy(zhp, cbp->cb_defer_destroy) != 0) {
zfs_close(zhp);
return (-1);
}
@@ -923,8 +942,11 @@ zfs_do_destroy(int argc, char **argv)
char *cp;
/* check options */
- while ((c = getopt(argc, argv, "frR")) != -1) {
+ while ((c = getopt(argc, argv, "dfrR")) != -1) {
switch (c) {
+ case 'd':
+ cb.cb_defer_destroy = B_TRUE;
+ break;
case 'f':
cb.cb_force = 1;
break;
@@ -956,6 +978,9 @@ zfs_do_destroy(int argc, char **argv)
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.
@@ -977,7 +1002,7 @@ zfs_do_destroy(int argc, char **argv)
}
}
- ret = zfs_destroy_snaps(zhp, cp);
+ ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy);
zfs_close(zhp);
if (ret) {
(void) fprintf(stderr,
@@ -986,7 +1011,6 @@ zfs_do_destroy(int argc, char **argv)
return (ret != 0);
}
-
/* Open the given dataset */
if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
return (1);
@@ -1014,15 +1038,15 @@ zfs_do_destroy(int argc, char **argv)
* Check for any dependents and/or clones.
*/
cb.cb_first = B_TRUE;
- if (!cb.cb_doclones &&
+ if (!cb.cb_doclones && !cb.cb_defer_destroy &&
zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
&cb) != 0) {
zfs_close(zhp);
return (1);
}
- if (cb.cb_error ||
- zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0) {
+ if (cb.cb_error || (!cb.cb_defer_destroy &&
+ (zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0))) {
zfs_close(zhp);
return (1);
}
@@ -1035,7 +1059,6 @@ zfs_do_destroy(int argc, char **argv)
if (destroy_callback(zhp, &cb) != 0)
return (1);
-
return (0);
}
@@ -1613,7 +1636,7 @@ zfs_do_upgrade(int argc, char **argv)
(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 identifer (FUID)\n"));
+ "unique identifier (FUID)\n"));
(void) printf(gettext(" 4 userquota, groupquota "
"properties\n"));
(void) printf(gettext("\nFor more information on a particular "
@@ -2651,6 +2674,108 @@ zfs_do_receive(int argc, char **argv)
return (err != 0);
}
+static int
+zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
+{
+ int errors = 0;
+ int i;
+ const char *tag;
+ boolean_t recursive = B_FALSE;
+ int c;
+ int (*func)(zfs_handle_t *, const char *, const char *, boolean_t);
+
+ /* check options */
+ while ((c = getopt(argc, argv, "r")) != -1) {
+ switch (c) {
+ case 'r':
+ recursive = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* check number of arguments */
+ if (argc < 2)
+ usage(B_FALSE);
+
+ tag = argv[0];
+ --argc;
+ ++argv;
+
+ if (holding) {
+ if (tag[0] == '.') {
+ /* tags starting with '.' are reserved for libzfs */
+ (void) fprintf(stderr,
+ gettext("tag may not start with '.'\n"));
+ usage(B_FALSE);
+ }
+ func = zfs_hold;
+ } else {
+ func = zfs_release;
+ }
+
+ for (i = 0; i < argc; ++i) {
+ zfs_handle_t *zhp;
+ char parent[ZFS_MAXNAMELEN];
+ const char *delim;
+ char *path = argv[i];
+
+ delim = strchr(path, '@');
+ if (delim == NULL) {
+ (void) fprintf(stderr,
+ gettext("'%s' is not a snapshot\n"), path);
+ ++errors;
+ continue;
+ }
+ (void) strncpy(parent, path, delim - path);
+ parent[delim - path] = '\0';
+
+ zhp = zfs_open(g_zfs, parent,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL) {
+ ++errors;
+ continue;
+ }
+ if (func(zhp, delim+1, tag, recursive) != 0)
+ ++errors;
+ zfs_close(zhp);
+ }
+
+ return (errors != 0);
+}
+
+/*
+ * zfs hold [-r] <tag> <snap> ...
+ *
+ * -r Recursively hold
+ *
+ * Apply a user-hold with the given tag to the list of snapshots.
+ */
+static int
+zfs_do_hold(int argc, char **argv)
+{
+ return (zfs_do_hold_rele_impl(argc, argv, B_TRUE));
+}
+
+/*
+ * zfs release [-r] <tag> <snap> ...
+ *
+ * -r Recursively release
+ *
+ * Release a user-hold with the given tag from the list of snapshots.
+ */
+static int
+zfs_do_release(int argc, char **argv)
+{
+ return (zfs_do_hold_rele_impl(argc, argv, B_FALSE));
+}
+
typedef struct get_all_cbdata {
zfs_handle_t **cb_handles;
size_t cb_alloc;
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index c8a33df4d..c9b092e44 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -1469,7 +1469,7 @@ show_import(nvlist_t *config)
*/
static int
do_import(nvlist_t *config, const char *newname, const char *mntopts,
- int force, nvlist_t *props, boolean_t allowfaulted)
+ int force, nvlist_t *props, boolean_t do_verbatim)
{
zpool_handle_t *zhp;
char *name;
@@ -1522,14 +1522,14 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
}
}
- if (zpool_import_props(g_zfs, config, newname, props,
- allowfaulted) != 0)
+ if (zpool_import_props(g_zfs, config, newname, props, do_verbatim) != 0)
return (1);
if (newname != NULL)
name = (char *)newname;
- verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
+ if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
+ return (1);
if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
zpool_enable_datasets(zhp, mntopts, 0) != 0) {
@@ -1566,7 +1566,8 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
* -F Import even in the presence of faulted vdevs. This is an
* intentionally undocumented option for testing purposes, and
* treats the pool configuration as complete, leaving any bad
- * vdevs in the FAULTED state.
+ * vdevs in the FAULTED state. In other words, it does verbatim
+ * import.
*
* -a Import all pools found.
*
@@ -1595,7 +1596,7 @@ zpool_do_import(int argc, char **argv)
nvlist_t *found_config;
nvlist_t *props = NULL;
boolean_t first;
- boolean_t allow_faulted = B_FALSE;
+ boolean_t do_verbatim = B_FALSE;
uint64_t pool_state;
char *cachefile = NULL;
@@ -1628,7 +1629,7 @@ zpool_do_import(int argc, char **argv)
do_force = B_TRUE;
break;
case 'F':
- allow_faulted = B_TRUE;
+ do_verbatim = B_TRUE;
break;
case 'o':
if ((propval = strchr(optarg, '=')) != NULL) {
@@ -1778,7 +1779,7 @@ zpool_do_import(int argc, char **argv)
if (do_all)
err |= do_import(config, NULL, mntopts,
- do_force, props, allow_faulted);
+ do_force, props, do_verbatim);
else
show_import(config);
} else if (searchname != NULL) {
@@ -1826,7 +1827,7 @@ zpool_do_import(int argc, char **argv)
err = B_TRUE;
} else {
err |= do_import(found_config, argc == 1 ? NULL :
- argv[1], mntopts, do_force, props, allow_faulted);
+ argv[1], mntopts, do_force, props, do_verbatim);
}
}
@@ -3117,6 +3118,17 @@ status_callback(zpool_handle_t *zhp, void *data)
"replace'.\n"));
break;
+ case ZPOOL_STATUS_REMOVED_DEV:
+ (void) printf(gettext("status: One or more devices has "
+ "been removed by the administrator.\n\tSufficient "
+ "replicas exist for the pool to continue functioning in "
+ "a\n\tdegraded state.\n"));
+ (void) printf(gettext("action: Online the device using "
+ "'zpool online' or replace the device with\n\t'zpool "
+ "replace'.\n"));
+ break;
+
+
case ZPOOL_STATUS_RESILVERING:
(void) printf(gettext("status: One or more devices is "
"currently being resilvered. The pool will\n\tcontinue "
@@ -3539,6 +3551,8 @@ zpool_do_upgrade(int argc, char **argv)
(void) printf(gettext(" 14 passthrough-x aclinherit\n"));
(void) printf(gettext(" 15 user/group space accounting\n"));
(void) printf(gettext(" 16 stmf property support\n"));
+ (void) printf(gettext(" 17 Triple-parity RAID-Z\n"));
+ (void) printf(gettext(" 18 snapshot user holds\n"));
(void) printf(gettext("For more information on a particular "
"version, including supported releases, see:\n\n"));
(void) printf("http://www.opensolaris.org/os/community/zfs/"
@@ -3624,6 +3638,8 @@ char *hist_event_table[LOG_END] = {
"refquota set",
"refreservation set",
"pool scrub done",
+ "user hold",
+ "user release",
};
/*
diff --git a/cmd/zpool/zpool_vdev.c b/cmd/zpool/zpool_vdev.c
index 10007c149..621519197 100644
--- a/cmd/zpool/zpool_vdev.c
+++ b/cmd/zpool/zpool_vdev.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -67,6 +67,7 @@
#include <libdiskmgt.h>
#include <libintl.h>
#include <libnvpair.h>
+#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -1093,20 +1094,35 @@ check_in_use(nvlist_t *config, nvlist_t *nv, int force, int isreplacing,
}
static const char *
-is_grouping(const char *type, int *mindev)
+is_grouping(const char *type, int *mindev, int *maxdev)
{
- if (strcmp(type, "raidz") == 0 || strcmp(type, "raidz1") == 0) {
- if (mindev != NULL)
- *mindev = 2;
- return (VDEV_TYPE_RAIDZ);
- }
+ if (strncmp(type, "raidz", 5) == 0) {
+ const char *p = type + 5;
+ char *end;
+ long nparity;
+
+ if (*p == '\0') {
+ nparity = 1;
+ } else if (*p == '0') {
+ return (NULL); /* no zero prefixes allowed */
+ } else {
+ errno = 0;
+ nparity = strtol(p, &end, 10);
+ if (errno != 0 || nparity < 1 || nparity >= 255 ||
+ *end != '\0')
+ return (NULL);
+ }
- if (strcmp(type, "raidz2") == 0) {
if (mindev != NULL)
- *mindev = 3;
+ *mindev = nparity + 1;
+ if (maxdev != NULL)
+ *maxdev = 255;
return (VDEV_TYPE_RAIDZ);
}
+ if (maxdev != NULL)
+ *maxdev = INT_MAX;
+
if (strcmp(type, "mirror") == 0) {
if (mindev != NULL)
*mindev = 2;
@@ -1144,7 +1160,7 @@ nvlist_t *
construct_spec(int argc, char **argv)
{
nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
- int t, toplevels, mindev, nspares, nlogs, nl2cache;
+ int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
const char *type;
uint64_t is_log;
boolean_t seen_logs;
@@ -1166,7 +1182,7 @@ construct_spec(int argc, char **argv)
* If it's a mirror or raidz, the subsequent arguments are
* its leaves -- until we encounter the next mirror or raidz.
*/
- if ((type = is_grouping(argv[0], &mindev)) != NULL) {
+ if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
nvlist_t **child = NULL;
int c, children = 0;
@@ -1223,7 +1239,7 @@ construct_spec(int argc, char **argv)
}
for (c = 1; c < argc; c++) {
- if (is_grouping(argv[c], NULL) != NULL)
+ if (is_grouping(argv[c], NULL, NULL) != NULL)
break;
children++;
child = realloc(child,
@@ -1243,6 +1259,13 @@ construct_spec(int argc, char **argv)
return (NULL);
}
+ if (children > maxdev) {
+ (void) fprintf(stderr, gettext("invalid vdev "
+ "specification: %s supports no more than "
+ "%d devices\n"), argv[0], maxdev);
+ return (NULL);
+ }
+
argc -= c;
argv += c;
diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c
index 746db0c07..5f49fd5a0 100644
--- a/cmd/ztest/ztest.c
+++ b/cmd/ztest/ztest.c
@@ -479,7 +479,7 @@ process_options(int argc, char **argv)
zopt_raidz = MAX(1, value);
break;
case 'R':
- zopt_raidz_parity = MIN(MAX(value, 1), 2);
+ zopt_raidz_parity = MIN(MAX(value, 1), 3);
break;
case 'd':
zopt_datasets = MAX(1, value);
@@ -1387,7 +1387,7 @@ ztest_destroy_cb(char *name, void *arg)
/*
* Destroy the dataset.
*/
- error = dmu_objset_destroy(name);
+ error = dmu_objset_destroy(name, B_FALSE);
if (error) {
(void) dmu_objset_open(name, DMU_OST_OTHER,
DS_MODE_USER | DS_MODE_READONLY, &os);
@@ -1560,7 +1560,7 @@ ztest_dmu_objset_create_destroy(ztest_args_t *za)
zil_close(zilog);
dmu_objset_close(os);
- error = dmu_objset_destroy(name);
+ error = dmu_objset_destroy(name, B_FALSE);
if (error)
fatal(0, "dmu_objset_destroy(%s) = %d", name, error);
@@ -1583,7 +1583,7 @@ ztest_dmu_snapshot_create_destroy(ztest_args_t *za)
(void) snprintf(snapname, 100, "%s@%llu", osname,
(u_longlong_t)za->za_instance);
- error = dmu_objset_destroy(snapname);
+ error = dmu_objset_destroy(snapname, B_FALSE);
if (error != 0 && error != ENOENT)
fatal(0, "dmu_objset_destroy() = %d", error);
error = dmu_objset_snapshot(osname, strchr(snapname, '@')+1,
@@ -1614,19 +1614,19 @@ ztest_dsl_dataset_cleanup(char *osname, uint64_t curval)
(void) snprintf(clone2name, 100, "%s/c2_%llu", osname, curval);
(void) snprintf(snap3name, 100, "%s@s3_%llu", clone1name, curval);
- error = dmu_objset_destroy(clone2name);
+ error = dmu_objset_destroy(clone2name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", clone2name, error);
- error = dmu_objset_destroy(snap3name);
+ error = dmu_objset_destroy(snap3name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", snap3name, error);
- error = dmu_objset_destroy(snap2name);
+ error = dmu_objset_destroy(snap2name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", snap2name, error);
- error = dmu_objset_destroy(clone1name);
+ error = dmu_objset_destroy(clone1name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", clone1name, error);
- error = dmu_objset_destroy(snap1name);
+ error = dmu_objset_destroy(snap1name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", snap1name, error);
}