aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/zpool
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/zpool')
-rw-r--r--cmd/zpool/zpool_main.c204
1 files changed, 174 insertions, 30 deletions
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index cb0535a98..d0c0a923f 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -54,6 +54,7 @@
#include "zpool_util.h"
#include "zfs_comutil.h"
+#include "zfeature_common.h"
#include "statcommon.h"
@@ -208,7 +209,7 @@ get_usage(zpool_help_t idx) {
case HELP_CLEAR:
return (gettext("\tclear [-nF] <pool> [device]\n"));
case HELP_CREATE:
- return (gettext("\tcreate [-fn] [-o property=value] ... \n"
+ return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
"\t [-O file-system-property=value] ... \n"
"\t [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
case HELP_DESTROY:
@@ -341,6 +342,12 @@ usage(boolean_t requested)
/* Iterate over all properties */
(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
ZFS_TYPE_POOL);
+
+ (void) fprintf(fp, "\t%-15s ", "feature@...");
+ (void) fprintf(fp, "YES disabled | enabled | active\n");
+
+ (void) fprintf(fp, gettext("\nThe feature@ properties must be "
+ "appended with a feature name.\nSee zpool-features(5).\n"));
}
/*
@@ -407,12 +414,16 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
proplist = *props;
if (poolprop) {
- if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
+ if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
+ !zpool_prop_feature(propname)) {
(void) fprintf(stderr, gettext("property '%s' is "
"not a valid pool property\n"), propname);
return (2);
}
- normnm = zpool_prop_to_name(prop);
+ if (zpool_prop_feature(propname))
+ normnm = propname;
+ else
+ normnm = zpool_prop_to_name(prop);
} else {
if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
normnm = zfs_prop_to_name(fprop);
@@ -601,7 +612,7 @@ zpool_do_remove(int argc, char **argv)
}
/*
- * zpool create [-fn] [-o property=value] ...
+ * zpool create [-fnd] [-o property=value] ...
* [-O file-system-property=value] ...
* [-R root] [-m mountpoint] <pool> <dev> ...
*
@@ -610,8 +621,10 @@ zpool_do_remove(int argc, char **argv)
* were to be created.
* -R Create a pool under an alternate root
* -m Set default mountpoint for the root dataset. By default it's
- * '/<pool>'
+ * '/<pool>'
* -o Set property=value.
+ * -d Don't automatically enable all supported pool features
+ * (individual features can be enabled with -o).
* -O Set fsproperty=value in the pool's root file system
*
* Creates the named pool according to the given vdev specification. The
@@ -624,6 +637,7 @@ zpool_do_create(int argc, char **argv)
{
boolean_t force = B_FALSE;
boolean_t dryrun = B_FALSE;
+ boolean_t enable_all_pool_feat = B_TRUE;
int c;
nvlist_t *nvroot = NULL;
char *poolname;
@@ -635,7 +649,7 @@ zpool_do_create(int argc, char **argv)
char *propval;
/* check options */
- while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
+ while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) {
switch (c) {
case 'f':
force = B_TRUE;
@@ -643,6 +657,9 @@ zpool_do_create(int argc, char **argv)
case 'n':
dryrun = B_TRUE;
break;
+ case 'd':
+ enable_all_pool_feat = B_FALSE;
+ break;
case 'R':
altroot = optarg;
if (add_prop_list(zpool_prop_to_name(
@@ -670,6 +687,21 @@ zpool_do_create(int argc, char **argv)
if (add_prop_list(optarg, propval, &props, B_TRUE))
goto errout;
+
+ /*
+ * If the user is creating a pool that doesn't support
+ * feature flags, don't enable any features.
+ */
+ if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
+ char *end;
+ u_longlong_t ver;
+
+ ver = strtoull(propval, &end, 10);
+ if (*end == '\0' &&
+ ver < SPA_VERSION_FEATURES) {
+ enable_all_pool_feat = B_FALSE;
+ }
+ }
break;
case 'O':
if ((propval = strchr(optarg, '=')) == NULL) {
@@ -735,7 +767,6 @@ zpool_do_create(int argc, char **argv)
goto errout;
}
-
if (altroot != NULL && altroot[0] != '/') {
(void) fprintf(stderr, gettext("invalid alternate root '%s': "
"must be an absolute path\n"), altroot);
@@ -817,6 +848,27 @@ zpool_do_create(int argc, char **argv)
/*
* Hand off to libzfs.
*/
+ if (enable_all_pool_feat) {
+ int i;
+ for (i = 0; i < SPA_FEATURES; i++) {
+ char propname[MAXPATHLEN];
+ zfeature_info_t *feat = &spa_feature_table[i];
+
+ (void) snprintf(propname, sizeof (propname),
+ "feature@%s", feat->fi_uname);
+
+ /*
+ * Skip feature if user specified it manually
+ * on the command line.
+ */
+ if (nvlist_exists(props, propname))
+ continue;
+
+ if (add_prop_list(propname, ZFS_FEATURE_ENABLED,
+ &props, B_TRUE) != 0)
+ goto errout;
+ }
+ }
if (zpool_create(g_zfs, poolname,
nvroot, props, fsprops) == 0) {
zfs_handle_t *pool = zfs_open(g_zfs, poolname,
@@ -1148,6 +1200,10 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
(void) printf(gettext("newer version"));
break;
+ case VDEV_AUX_UNSUP_FEAT:
+ (void) printf(gettext("unsupported feature(s)"));
+ break;
+
case VDEV_AUX_SPARED:
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
&cb.cb_guid) == 0);
@@ -1265,6 +1321,10 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
(void) printf(gettext("newer version"));
break;
+ case VDEV_AUX_UNSUP_FEAT:
+ (void) printf(gettext("unsupported feature(s)"));
+ break;
+
case VDEV_AUX_ERR_EXCEEDED:
(void) printf(gettext("too many errors"));
break;
@@ -1431,6 +1491,20 @@ show_import(nvlist_t *config)
"incompatible version.\n"));
break;
+ case ZPOOL_STATUS_UNSUP_FEAT_READ:
+ (void) printf(gettext("status: The pool uses the following "
+ "feature(s) not supported on this sytem:\n"));
+ zpool_print_unsup_feat(config);
+ break;
+
+ case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+ (void) printf(gettext("status: The pool can only be accessed "
+ "in read-only mode on this system. It\n\tcannot be "
+ "accessed in read-write mode because it uses the "
+ "following\n\tfeature(s) not supported on this system:\n"));
+ zpool_print_unsup_feat(config);
+ break;
+
case ZPOOL_STATUS_HOSTID_MISMATCH:
(void) printf(gettext(" status: The pool was last accessed by "
"another system.\n"));
@@ -1488,6 +1562,20 @@ show_import(nvlist_t *config)
"newer\n\tsoftware, or recreate the pool from "
"backup.\n"));
break;
+ case ZPOOL_STATUS_UNSUP_FEAT_READ:
+ (void) printf(gettext("action: The pool cannot be "
+ "imported. Access the pool on a system that "
+ "supports\n\tthe required feature(s), or recreate "
+ "the pool from backup.\n"));
+ break;
+ case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+ (void) printf(gettext("action: The pool cannot be "
+ "imported in read-write mode. Import the pool "
+ "with\n"
+ "\t\"-o readonly=on\", access the pool on a system "
+ "that supports the\n\trequired feature(s), or "
+ "recreate the pool from backup.\n"));
+ break;
case ZPOOL_STATUS_MISSING_DEV_R:
case ZPOOL_STATUS_MISSING_DEV_NR:
case ZPOOL_STATUS_BAD_GUID_SUM:
@@ -1563,9 +1651,9 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
verify(nvlist_lookup_uint64(config,
ZPOOL_CONFIG_VERSION, &version) == 0);
- if (version > SPA_VERSION) {
+ if (!SPA_VERSION_IS_SUPPORTED(version)) {
(void) fprintf(stderr, gettext("cannot import '%s': pool "
- "is formatted using a newer ZFS version\n"), name);
+ "is formatted using an unsupported ZFS version\n"), name);
return (1);
} else if (state != POOL_STATE_EXPORTED &&
!(flags & ZFS_IMPORT_ANY_HOST)) {
@@ -2556,15 +2644,13 @@ static void
print_header(list_cbdata_t *cb)
{
zprop_list_t *pl = cb->cb_proplist;
+ char headerbuf[ZPOOL_MAXPROPLEN];
const char *header;
boolean_t first = B_TRUE;
boolean_t right_justify;
size_t width = 0;
for (; pl != NULL; pl = pl->pl_next) {
- if (pl->pl_prop == ZPROP_INVAL)
- continue;
-
width = pl->pl_width;
if (first && cb->cb_verbose) {
/*
@@ -2579,8 +2665,18 @@ print_header(list_cbdata_t *cb)
else
first = B_FALSE;
- header = zpool_prop_column_name(pl->pl_prop);
- right_justify = zpool_prop_align_right(pl->pl_prop);
+ right_justify = B_FALSE;
+ if (pl->pl_prop != ZPROP_INVAL) {
+ header = zpool_prop_column_name(pl->pl_prop);
+ right_justify = zpool_prop_align_right(pl->pl_prop);
+ } else {
+ int i;
+
+ for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
+ headerbuf[i] = toupper(pl->pl_user_prop[i]);
+ headerbuf[i] = '\0';
+ header = headerbuf;
+ }
if (pl->pl_next == NULL && !right_justify)
(void) printf("%s", header);
@@ -2639,6 +2735,11 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
propstr = property;
right_justify = zpool_prop_align_right(pl->pl_prop);
+ } else if ((zpool_prop_feature(pl->pl_user_prop) ||
+ zpool_prop_unsupported(pl->pl_user_prop)) &&
+ zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
+ sizeof (property)) == 0) {
+ propstr = property;
} else {
propstr = "-";
}
@@ -3958,6 +4059,31 @@ status_callback(zpool_handle_t *zhp, void *data)
"backup.\n"));
break;
+ case ZPOOL_STATUS_UNSUP_FEAT_READ:
+ (void) printf(gettext("status: The pool cannot be accessed on "
+ "this system because it uses the\n\tfollowing feature(s) "
+ "not supported on this system:\n"));
+ zpool_print_unsup_feat(config);
+ (void) printf("\n");
+ (void) printf(gettext("action: Access the pool from a system "
+ "that supports the required feature(s),\n\tor restore the "
+ "pool from backup.\n"));
+ break;
+
+ case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+ (void) printf(gettext("status: The pool can only be accessed "
+ "in read-only mode on this system. It\n\tcannot be "
+ "accessed in read-write mode because it uses the "
+ "following\n\tfeature(s) not supported on this system:\n"));
+ zpool_print_unsup_feat(config);
+ (void) printf("\n");
+ (void) printf(gettext("action: The pool cannot be accessed in "
+ "read-write mode. Import the pool with\n"
+ "\t\"-o readonly=on\", access the pool from a system that "
+ "supports the\n\trequired feature(s), or restore the "
+ "pool from backup.\n"));
+ break;
+
case ZPOOL_STATUS_FAULTED_DEV_R:
(void) printf(gettext("status: One or more devices are "
"faulted in response to persistent errors.\n\tSufficient "
@@ -4182,7 +4308,8 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
&version) == 0);
- if (!cbp->cb_newer && version < SPA_VERSION) {
+ if (!cbp->cb_newer && SPA_VERSION_IS_SUPPORTED(version) &&
+ version != SPA_VERSION) {
if (!cbp->cb_all) {
if (cbp->cb_first) {
(void) printf(gettext("The following pools are "
@@ -4205,13 +4332,14 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
"'%s'\n\n"), zpool_get_name(zhp));
}
}
- } else if (cbp->cb_newer && version > SPA_VERSION) {
+ } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
assert(!cbp->cb_all);
if (cbp->cb_first) {
(void) printf(gettext("The following pools are "
- "formatted using a newer software version and\n"
- "cannot be accessed on the current system.\n\n"));
+ "formatted using an unsupported software version "
+ "and\ncannot be accessed on the current "
+ "system.\n\n"));
(void) printf(gettext("VER POOL\n"));
(void) printf(gettext("--- ------------\n"));
cbp->cb_first = B_FALSE;
@@ -4295,8 +4423,8 @@ zpool_do_upgrade(int argc, char **argv)
break;
case 'V':
cb.cb_version = strtoll(optarg, &end, 10);
- if (*end != '\0' || cb.cb_version > SPA_VERSION ||
- cb.cb_version < SPA_VERSION_1) {
+ if (*end != '\0' ||
+ !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
(void) fprintf(stderr,
gettext("invalid version '%s'\n"), optarg);
usage(B_FALSE);
@@ -4341,8 +4469,8 @@ zpool_do_upgrade(int argc, char **argv)
}
}
- (void) printf(gettext("This system is currently running "
- "ZFS pool version %llu.\n\n"), SPA_VERSION);
+ (void) printf(gettext("This system supports ZFS pool feature "
+ "flags.\n\n"));
cb.cb_first = B_TRUE;
if (showversions) {
(void) printf(gettext("The following versions are "
@@ -4923,13 +5051,26 @@ get_callback(zpool_handle_t *zhp, void *data)
pl == cbp->cb_proplist)
continue;
- if (zpool_get_prop(zhp, pl->pl_prop,
- value, sizeof (value), &srctype) != 0)
- continue;
+ if (pl->pl_prop == ZPROP_INVAL &&
+ (zpool_prop_feature(pl->pl_user_prop) ||
+ zpool_prop_unsupported(pl->pl_user_prop))) {
+ srctype = ZPROP_SRC_LOCAL;
+
+ if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
+ value, sizeof (value)) == 0) {
+ zprop_print_one_property(zpool_get_name(zhp),
+ cbp, pl->pl_user_prop, value, srctype,
+ NULL, NULL);
+ }
+ } else {
+ if (zpool_get_prop(zhp, pl->pl_prop, value,
+ sizeof (value), &srctype) != 0)
+ continue;
- zprop_print_one_property(zpool_get_name(zhp), cbp,
- zpool_prop_to_name(pl->pl_prop), value, srctype, NULL,
- NULL);
+ zprop_print_one_property(zpool_get_name(zhp), cbp,
+ zpool_prop_to_name(pl->pl_prop), value, srctype,
+ NULL, NULL);
+ }
}
return (0);
}
@@ -4941,8 +5082,11 @@ zpool_do_get(int argc, char **argv)
zprop_list_t fake_name = { 0 };
int ret;
- if (argc < 3)
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing property "
+ "argument\n"));
usage(B_FALSE);
+ }
cb.cb_first = B_TRUE;
cb.cb_sources = ZPROP_SRC_ALL;
@@ -4952,7 +5096,7 @@ zpool_do_get(int argc, char **argv)
cb.cb_columns[3] = GET_COL_SOURCE;
cb.cb_type = ZFS_TYPE_POOL;
- if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
+ if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
ZFS_TYPE_POOL) != 0)
usage(B_FALSE);