Print this page
2619 asynchronous destruction of ZFS file systems
2747 SPA versioning with zfs feature flags
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <gwilson@delphix.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>
Approved by: Dan McDonald <danmcd@nexenta.com>

*** 49,58 **** --- 49,59 ---- #include <libzfs.h> #include "zpool_util.h" #include "zfs_comutil.h" + #include "zfeature_common.h" #include "statcommon.h" static int zpool_do_create(int, char **); static int zpool_do_destroy(int, char **);
*** 198,208 **** return (gettext("\tattach [-f] <pool> <device> " "<new-device>\n")); case HELP_CLEAR: return (gettext("\tclear [-nF] <pool> [device]\n")); case HELP_CREATE: ! return (gettext("\tcreate [-fn] [-o property=value] ... \n" "\t [-O file-system-property=value] ... \n" "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); case HELP_DESTROY: return (gettext("\tdestroy [-f] <pool>\n")); case HELP_DETACH: --- 199,209 ---- return (gettext("\tattach [-f] <pool> <device> " "<new-device>\n")); case HELP_CLEAR: return (gettext("\tclear [-nF] <pool> [device]\n")); case HELP_CREATE: ! 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: return (gettext("\tdestroy [-f] <pool>\n")); case HELP_DETACH:
*** 329,338 **** --- 330,345 ---- "PROPERTY", "EDIT", "VALUES"); /* 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")); } /* * See comments at end of main(). */
*** 395,409 **** } proplist = *props; if (poolprop) { ! if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { (void) fprintf(stderr, gettext("property '%s' is " "not a valid pool property\n"), propname); return (2); } normnm = zpool_prop_to_name(prop); } else { if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { normnm = zfs_prop_to_name(fprop); } else { --- 402,420 ---- } proplist = *props; if (poolprop) { ! 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); } + 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); } else {
*** 572,582 **** return (ret); } /* ! * zpool create [-fn] [-o property=value] ... * [-O file-system-property=value] ... * [-R root] [-m mountpoint] <pool> <dev> ... * * -f Force creation, even if devices appear in use * -n Do not create the pool, but display the resulting layout if it --- 583,593 ---- return (ret); } /* ! * zpool create [-fnd] [-o property=value] ... * [-O file-system-property=value] ... * [-R root] [-m mountpoint] <pool> <dev> ... * * -f Force creation, even if devices appear in use * -n Do not create the pool, but display the resulting layout if it
*** 583,592 **** --- 594,605 ---- * 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>' * -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 * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once * we get the nvlist back from get_vdev_spec(), we either print out the contents
*** 595,604 **** --- 608,618 ---- int 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; int ret = 1; char *altroot = NULL;
*** 606,623 **** nvlist_t *fsprops = NULL; nvlist_t *props = NULL; char *propval; /* check options */ ! while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { switch (c) { case 'f': force = B_TRUE; break; case 'n': dryrun = B_TRUE; break; case 'R': altroot = optarg; if (add_prop_list(zpool_prop_to_name( ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) goto errout; --- 620,640 ---- nvlist_t *fsprops = NULL; nvlist_t *props = NULL; char *propval; /* check options */ ! while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) { switch (c) { case 'f': force = B_TRUE; break; 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( ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) goto errout;
*** 641,650 **** --- 658,682 ---- *propval = '\0'; propval++; 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) { (void) fprintf(stderr, gettext("missing " "'=' for -O option\n"));
*** 706,716 **** "specification: at least one toplevel vdev must be " "specified\n")); goto errout; } - if (altroot != NULL && altroot[0] != '/') { (void) fprintf(stderr, gettext("invalid alternate root '%s': " "must be an absolute path\n"), altroot); goto errout; } --- 738,747 ----
*** 788,797 **** --- 819,849 ---- ret = 0; } else { /* * 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, ZFS_TYPE_FILESYSTEM); if (pool != NULL) {
*** 1119,1128 **** --- 1171,1184 ---- case VDEV_AUX_VERSION_NEWER: (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); if (zpool_iter(g_zfs, find_spare, &cb) == 1) { if (strcmp(zpool_get_name(cb.cb_zhp),
*** 1236,1245 **** --- 1292,1305 ---- case VDEV_AUX_VERSION_NEWER: (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; default:
*** 1402,1411 **** --- 1462,1485 ---- case ZPOOL_STATUS_VERSION_NEWER: (void) printf(gettext(" status: The pool is formatted using an " "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")); break;
*** 1459,1468 **** --- 1533,1556 ---- (void) printf(gettext(" action: The pool cannot be " "imported. Access the pool on a system running " "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: (void) printf(gettext(" action: The pool cannot be " "imported. Attach the missing\n\tdevices and try "
*** 1534,1546 **** verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &state) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) == 0); ! if (version > SPA_VERSION) { (void) fprintf(stderr, gettext("cannot import '%s': pool " ! "is formatted using a newer ZFS version\n"), name); return (1); } else if (state != POOL_STATE_EXPORTED && !(flags & ZFS_IMPORT_ANY_HOST)) { uint64_t hostid; --- 1622,1634 ---- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &state) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) == 0); ! if (!SPA_VERSION_IS_SUPPORTED(version)) { (void) fprintf(stderr, gettext("cannot import '%s': pool " ! "is formatted using an unsupported ZFS version\n"), name); return (1); } else if (state != POOL_STATE_EXPORTED && !(flags & ZFS_IMPORT_ANY_HOST)) { uint64_t hostid;
*** 2471,2489 **** */ static void print_header(list_cbdata_t *cb) { zprop_list_t *pl = cb->cb_proplist; 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) { /* * Reset the width to accommodate the verbose listing * of devices. --- 2559,2575 ---- */ 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) { width = pl->pl_width; if (first && cb->cb_verbose) { /* * Reset the width to accommodate the verbose listing * of devices.
*** 2494,2506 **** --- 2580,2602 ---- if (!first) (void) printf(" "); else first = B_FALSE; + 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); else if (right_justify) (void) printf("%*s", width, header); else
*** 2555,2564 **** --- 2651,2665 ---- propstr = "-"; else 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 = "-"; }
*** 3894,3903 **** --- 3995,4029 ---- (void) printf(gettext("action: Access the pool from a system " "running more recent software, or\n\trestore the pool from " "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 " "replicas exist for the pool to continue functioning " "in a\n\tdegraded state.\n"));
*** 4118,4128 **** config = zpool_get_config(zhp, NULL); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) == 0); ! if (!cbp->cb_newer && version < SPA_VERSION) { if (!cbp->cb_all) { if (cbp->cb_first) { (void) printf(gettext("The following pools are " "out of date, and can be upgraded. After " "being\nupgraded, these pools will no " --- 4244,4255 ---- config = zpool_get_config(zhp, NULL); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) == 0); ! 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 " "out of date, and can be upgraded. After " "being\nupgraded, these pools will no "
*** 4141,4157 **** if (!ret) { (void) printf(gettext("Successfully upgraded " "'%s'\n\n"), zpool_get_name(zhp)); } } ! } else if (cbp->cb_newer && version > SPA_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")); (void) printf(gettext("VER POOL\n")); (void) printf(gettext("--- ------------\n")); cbp->cb_first = B_FALSE; } --- 4268,4285 ---- if (!ret) { (void) printf(gettext("Successfully upgraded " "'%s'\n\n"), zpool_get_name(zhp)); } } ! } 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 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; }
*** 4231,4242 **** case 'v': showversions = B_TRUE; break; case 'V': cb.cb_version = strtoll(optarg, &end, 10); ! if (*end != '\0' || cb.cb_version > SPA_VERSION || ! cb.cb_version < SPA_VERSION_1) { (void) fprintf(stderr, gettext("invalid version '%s'\n"), optarg); usage(B_FALSE); } break; --- 4359,4370 ---- case 'v': showversions = B_TRUE; break; case 'V': cb.cb_version = strtoll(optarg, &end, 10); ! if (*end != '\0' || ! !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { (void) fprintf(stderr, gettext("invalid version '%s'\n"), optarg); usage(B_FALSE); } break;
*** 4277,4288 **** "be used along with a pool name\n")); usage(B_FALSE); } } ! (void) printf(gettext("This system is currently running " ! "ZFS pool version %llu.\n\n"), SPA_VERSION); cb.cb_first = B_TRUE; if (showversions) { (void) printf(gettext("The following versions are " "supported:\n\n")); (void) printf(gettext("VER DESCRIPTION\n")); --- 4405,4416 ---- "be used along with a pool name\n")); usage(B_FALSE); } } ! (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 " "supported:\n\n")); (void) printf(gettext("VER DESCRIPTION\n"));
*** 4529,4546 **** */ if (pl->pl_prop == ZPOOL_PROP_NAME && pl == cbp->cb_proplist) continue; ! 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); } return (0); } int zpool_do_get(int argc, char **argv) --- 4657,4687 ---- */ if (pl->pl_prop == ZPOOL_PROP_NAME && pl == cbp->cb_proplist) 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); } + } return (0); } int zpool_do_get(int argc, char **argv)
*** 4547,4558 **** { zprop_get_cbdata_t cb = { 0 }; zprop_list_t fake_name = { 0 }; int ret; ! if (argc < 3) usage(B_FALSE); cb.cb_first = B_TRUE; cb.cb_sources = ZPROP_SRC_ALL; cb.cb_columns[0] = GET_COL_NAME; cb.cb_columns[1] = GET_COL_PROPERTY; --- 4688,4702 ---- { zprop_get_cbdata_t cb = { 0 }; zprop_list_t fake_name = { 0 }; int ret; ! 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; cb.cb_columns[0] = GET_COL_NAME; cb.cb_columns[1] = GET_COL_PROPERTY;