diff options
author | Christopher Siden <chris.siden@delphix.com> | 2012-07-19 04:58:27 -0700 |
---|---|---|
committer | Christopher Siden <chris.siden@delphix.com> | 2012-07-19 04:58:27 -0700 |
commit | 57221772c3fc05faba04bf48ddff45abf2bbf2bd (patch) | |
tree | c5cee9fd458d8493bc0a7be97ba725ffdc17eed7 /usr/src | |
parent | 21b27315a4575c86ba26ddfbccfaa768f2d1d37a (diff) | |
download | illumos-joyent-57221772c3fc05faba04bf48ddff45abf2bbf2bd.tar.gz |
2762 zpool command should have better support for feature flags
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Approved by: Eric Schrock <Eric.Schrock@delphix.com>
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/zhack/zhack.c | 6 | ||||
-rw-r--r-- | usr/src/cmd/zpool/zpool_main.c | 406 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_status.c | 25 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/mapfile-vers | 1 | ||||
-rw-r--r-- | usr/src/man/man1m/zpool.1m | 32 | ||||
-rw-r--r-- | usr/src/man/man5/zpool-features.5 | 5 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 21 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/zfeature.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfeature.c | 9 | ||||
-rw-r--r-- | usr/src/uts/common/sys/fs/zfs.h | 1 |
11 files changed, 392 insertions, 119 deletions
diff --git a/usr/src/cmd/zhack/zhack.c b/usr/src/cmd/zhack/zhack.c index f4be0b2a55..7cc83d2dc0 100644 --- a/usr/src/cmd/zhack/zhack.c +++ b/usr/src/cmd/zhack/zhack.c @@ -280,7 +280,7 @@ feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx) spa_feature_enable(spa, feature, tx); spa_history_log_internal(spa, "zhack enable feature", tx, - "name=%s can_readonly=%u", + "guid=%s can_readonly=%u", feature->fi_guid, feature->fi_can_readonly); } @@ -360,7 +360,7 @@ feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx) spa_feature_incr(spa, feature, tx); spa_history_log_internal(spa, "zhack feature incr", tx, - "name=%s", feature->fi_guid); + "guid=%s", feature->fi_guid); } static void @@ -371,7 +371,7 @@ feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx) spa_feature_decr(spa, feature, tx); spa_history_log_internal(spa, "zhack feature decr", tx, - "name=%s", feature->fi_guid); + "guid=%s", feature->fi_guid); } static void diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c index 3ecdbec968..36b1201777 100644 --- a/usr/src/cmd/zpool/zpool_main.c +++ b/usr/src/cmd/zpool/zpool_main.c @@ -381,6 +381,18 @@ print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, } } +static boolean_t +prop_list_contains_feature(nvlist_t *proplist) +{ + nvpair_t *nvp; + for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; + nvp = nvlist_next_nvpair(proplist, nvp)) { + if (zpool_prop_feature(nvpair_name(nvp))) + return (B_TRUE); + } + return (B_FALSE); +} + /* * Add a property pair (name, string-value) into a property nvlist. */ @@ -404,12 +416,30 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props, proplist = *props; if (poolprop) { + const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); + 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); } + + /* + * feature@ properties and version should not be specified + * at the same time. + */ + if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && + nvlist_exists(proplist, vname)) || + (prop == ZPOOL_PROP_VERSION && + prop_list_contains_feature(proplist))) { + (void) fprintf(stderr, gettext("'feature@' and " + "'version' properties cannot be specified " + "together\n")); + return (2); + } + + if (zpool_prop_feature(propname)) normnm = propname; else @@ -1461,8 +1491,8 @@ show_import(nvlist_t *config) break; case ZPOOL_STATUS_VERSION_OLDER: - (void) printf(gettext(" status: The pool is formatted using an " - "older on-disk version.\n")); + (void) printf(gettext(" status: The pool is formatted using a " + "legacy on-disk version.\n")); break; case ZPOOL_STATUS_VERSION_NEWER: @@ -1470,6 +1500,11 @@ show_import(nvlist_t *config) "incompatible version.\n")); break; + case ZPOOL_STATUS_FEAT_DISABLED: + (void) printf(gettext(" status: Some supported features are " + "not enabled on the pool.\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")); @@ -1516,19 +1551,21 @@ show_import(nvlist_t *config) * Print out an action according to the overall state of the pool. */ if (vs->vs_state == VDEV_STATE_HEALTHY) { - if (reason == ZPOOL_STATUS_VERSION_OLDER) + if (reason == ZPOOL_STATUS_VERSION_OLDER || + reason == ZPOOL_STATUS_FEAT_DISABLED) { (void) printf(gettext(" action: The pool can be " "imported using its name or numeric identifier, " "though\n\tsome features will not be available " "without an explicit 'zpool upgrade'.\n")); - else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) + } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { (void) printf(gettext(" action: The pool can be " "imported using its name or numeric " "identifier and\n\tthe '-f' flag.\n")); - else + } else { (void) printf(gettext(" action: The pool can be " "imported using its name or numeric " "identifier.\n")); + } } else if (vs->vs_state == VDEV_STATE_DEGRADED) { (void) printf(gettext(" action: The pool can be imported " "despite missing or damaged devices. The\n\tfault " @@ -3986,12 +4023,13 @@ status_callback(zpool_handle_t *zhp, void *data) break; case ZPOOL_STATUS_VERSION_OLDER: - (void) printf(gettext("status: The pool is formatted using an " - "older on-disk format. The pool can\n\tstill be used, but " - "some features are unavailable.\n")); + (void) printf(gettext("status: The pool is formatted using a " + "legacy on-disk format. The pool can\n\tstill be used, " + "but some features are unavailable.\n")); (void) printf(gettext("action: Upgrade the pool using 'zpool " "upgrade'. Once this is done, the\n\tpool will no longer " - "be accessible on older software versions.\n")); + "be accessible on software that does not support feature\n" + "\tflags.\n")); break; case ZPOOL_STATUS_VERSION_NEWER: @@ -4003,6 +4041,16 @@ status_callback(zpool_handle_t *zhp, void *data) "backup.\n")); break; + case ZPOOL_STATUS_FEAT_DISABLED: + (void) printf(gettext("status: Some supported features are not " + "enabled on the pool. The pool can\n\tstill be used, but " + "some features are unavailable.\n")); + (void) printf(gettext("action: Enable all features using " + "'zpool upgrade'. Once this is done,\n\tthe pool may no " + "longer be accessible by software that does not support\n\t" + "the features. See zpool-features(5) for details.\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) " @@ -4232,66 +4280,153 @@ zpool_do_status(int argc, char **argv) } typedef struct upgrade_cbdata { - int cb_all; int cb_first; - int cb_newer; int cb_argc; uint64_t cb_version; char **cb_argv; } upgrade_cbdata_t; static int +upgrade_version(zpool_handle_t *zhp, uint64_t version) +{ + int ret; + nvlist_t *config; + uint64_t oldversion; + + config = zpool_get_config(zhp, NULL); + verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, + &oldversion) == 0); + + assert(SPA_VERSION_IS_SUPPORTED(oldversion)); + assert(oldversion < version); + + ret = zpool_upgrade(zhp, version); + if (ret != 0) + return (ret); + + if (version >= SPA_VERSION_FEATURES) { + (void) printf(gettext("Successfully upgraded " + "'%s' from version %llu to feature flags.\n"), + zpool_get_name(zhp), oldversion); + } else { + (void) printf(gettext("Successfully upgraded " + "'%s' from version %llu to version %llu.\n"), + zpool_get_name(zhp), oldversion, version); + } + + return (0); +} + +static int +upgrade_enable_all(zpool_handle_t *zhp, int *countp) +{ + int i, ret, count; + boolean_t firstff = B_TRUE; + nvlist_t *enabled = zpool_get_features(zhp); + + count = 0; + for (i = 0; i < SPA_FEATURES; i++) { + const char *fname = spa_feature_table[i].fi_uname; + const char *fguid = spa_feature_table[i].fi_guid; + if (!nvlist_exists(enabled, fguid)) { + char *propname; + verify(-1 != asprintf(&propname, "feature@%s", fname)); + ret = zpool_set_prop(zhp, propname, + ZFS_FEATURE_ENABLED); + if (ret != 0) { + free(propname); + return (ret); + } + count++; + + if (firstff) { + (void) printf(gettext("Enabled the " + "following features on '%s':\n"), + zpool_get_name(zhp)); + firstff = B_FALSE; + } + (void) printf(gettext(" %s\n"), fname); + free(propname); + } + } + + if (countp != NULL) + *countp = count; + return (0); +} + +static int upgrade_cb(zpool_handle_t *zhp, void *arg) { upgrade_cbdata_t *cbp = arg; nvlist_t *config; uint64_t version; - int ret = 0; + boolean_t printnl = B_FALSE; + int ret; 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 " - "longer be accessible by older software " - "versions.\n\n")); - (void) printf(gettext("VER POOL\n")); - (void) printf(gettext("--- ------------\n")); - cbp->cb_first = B_FALSE; - } + assert(SPA_VERSION_IS_SUPPORTED(version)); - (void) printf("%2llu %s\n", (u_longlong_t)version, - zpool_get_name(zhp)); - } else { + if (version < cbp->cb_version) { + cbp->cb_first = B_FALSE; + ret = upgrade_version(zhp, cbp->cb_version); + if (ret != 0) + return (ret); + printnl = B_TRUE; + + /* + * If they did "zpool upgrade -a", then we could + * be doing ioctls to different pools. We need + * to log this history once to each pool, and bypass + * the normal history logging that happens in main(). + */ + (void) zpool_log_history(g_zfs, history_str); + log_history = B_FALSE; + } + + if (cbp->cb_version >= SPA_VERSION_FEATURES) { + int count; + ret = upgrade_enable_all(zhp, &count); + if (ret != 0) + return (ret); + + if (count > 0) { cbp->cb_first = B_FALSE; - ret = zpool_upgrade(zhp, cbp->cb_version); - if (!ret) { - (void) printf(gettext("Successfully upgraded " - "'%s'\n\n"), zpool_get_name(zhp)); - } - /* - * If they did "zpool upgrade -a", then we could - * be doing ioctls to different pools. We need - * to log this history once to each pool, and bypass - * the normal history logging that happens in main(). - */ - (void) zpool_log_history(g_zfs, history_str); - log_history = B_FALSE; + printnl = B_TRUE; } - } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) { - assert(!cbp->cb_all); + } + if (printnl) { + (void) printf(gettext("\n")); + } + + return (0); +} + +static int +upgrade_list_older_cb(zpool_handle_t *zhp, void *arg) +{ + upgrade_cbdata_t *cbp = arg; + nvlist_t *config; + uint64_t version; + + config = zpool_get_config(zhp, NULL); + verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, + &version) == 0); + + assert(SPA_VERSION_IS_SUPPORTED(version)); + + if (version < SPA_VERSION_FEATURES) { 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")); + "formatted with legacy version numbers and can\n" + "be upgraded to use feature flags. After " + "being upgraded, these pools\nwill no " + "longer be accessible by software that does not " + "support feature\nflags.\n\n")); (void) printf(gettext("VER POOL\n")); (void) printf(gettext("--- ------------\n")); cbp->cb_first = B_FALSE; @@ -4301,14 +4436,65 @@ upgrade_cb(zpool_handle_t *zhp, void *arg) zpool_get_name(zhp)); } - zpool_close(zhp); - return (ret); + return (0); +} + +static int +upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) +{ + upgrade_cbdata_t *cbp = arg; + nvlist_t *config; + uint64_t version; + + config = zpool_get_config(zhp, NULL); + verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, + &version) == 0); + + if (version >= SPA_VERSION_FEATURES) { + int i; + boolean_t poolfirst = B_TRUE; + nvlist_t *enabled = zpool_get_features(zhp); + + for (i = 0; i < SPA_FEATURES; i++) { + const char *fguid = spa_feature_table[i].fi_guid; + const char *fname = spa_feature_table[i].fi_uname; + if (!nvlist_exists(enabled, fguid)) { + if (cbp->cb_first) { + (void) printf(gettext("\nSome " + "supported features are not " + "enabled on the following pools. " + "Once a\nfeature is enabled the " + "pool may become incompatible with " + "software\nthat does not support " + "the feature. See " + "zpool-features(5) for " + "details.\n\n")); + (void) printf(gettext("POOL " + "FEATURE\n")); + (void) printf(gettext("------" + "---------\n")); + cbp->cb_first = B_FALSE; + } + + if (poolfirst) { + (void) printf(gettext("%s\n"), + zpool_get_name(zhp)); + poolfirst = B_FALSE; + } + + (void) printf(gettext(" %s\n"), fname); + } + } + } + + return (0); } /* ARGSUSED */ static int upgrade_one(zpool_handle_t *zhp, void *data) { + boolean_t printnl = B_FALSE; upgrade_cbdata_t *cbp = data; uint64_t cur_version; int ret; @@ -4323,26 +4509,45 @@ upgrade_one(zpool_handle_t *zhp, void *data) cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); if (cur_version > cbp->cb_version) { (void) printf(gettext("Pool '%s' is already formatted " - "using more current version '%llu'.\n"), + "using more current version '%llu'.\n\n"), zpool_get_name(zhp), cur_version); return (0); } - if (cur_version == cbp->cb_version) { + + if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { (void) printf(gettext("Pool '%s' is already formatted " - "using the current version.\n"), zpool_get_name(zhp)); + "using version %llu.\n\n"), zpool_get_name(zhp), + cbp->cb_version); return (0); } - ret = zpool_upgrade(zhp, cbp->cb_version); + if (cur_version != cbp->cb_version) { + printnl = B_TRUE; + ret = upgrade_version(zhp, cbp->cb_version); + if (ret != 0) + return (ret); + } - if (!ret) { - (void) printf(gettext("Successfully upgraded '%s' " - "from version %llu to version %llu\n\n"), - zpool_get_name(zhp), (u_longlong_t)cur_version, - (u_longlong_t)cbp->cb_version); + if (cbp->cb_version >= SPA_VERSION_FEATURES) { + int count = 0; + ret = upgrade_enable_all(zhp, &count); + if (ret != 0) + return (ret); + + if (count != 0) { + printnl = B_TRUE; + } else if (cur_version == SPA_VERSION) { + (void) printf(gettext("Pool '%s' already has all " + "supported features enabled.\n"), + zpool_get_name(zhp)); + } + } + + if (printnl) { + (void) printf(gettext("\n")); } - return (ret != 0); + return (0); } /* @@ -4361,6 +4566,7 @@ zpool_do_upgrade(int argc, char **argv) upgrade_cbdata_t cb = { 0 }; int ret = 0; boolean_t showversions = B_FALSE; + boolean_t upgradeall = B_FALSE; char *end; @@ -4368,7 +4574,7 @@ zpool_do_upgrade(int argc, char **argv) while ((c = getopt(argc, argv, ":avV:")) != -1) { switch (c) { case 'a': - cb.cb_all = B_TRUE; + upgradeall = B_TRUE; break; case 'v': showversions = B_TRUE; @@ -4401,19 +4607,19 @@ zpool_do_upgrade(int argc, char **argv) if (cb.cb_version == 0) { cb.cb_version = SPA_VERSION; - } else if (!cb.cb_all && argc == 0) { + } else if (!upgradeall && argc == 0) { (void) fprintf(stderr, gettext("-V option is " "incompatible with other arguments\n")); usage(B_FALSE); } if (showversions) { - if (cb.cb_all || argc != 0) { + if (upgradeall || argc != 0) { (void) fprintf(stderr, gettext("-v option is " "incompatible with other arguments\n")); usage(B_FALSE); } - } else if (cb.cb_all) { + } else if (upgradeall) { if (argc != 0) { (void) fprintf(stderr, gettext("-a option should not " "be used along with a pool name\n")); @@ -4423,9 +4629,25 @@ zpool_do_upgrade(int argc, char **argv) (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 " + int i; + + (void) printf(gettext("The following features are " + "supported:\n\n")); + (void) printf(gettext("FEAT DESCRIPTION\n")); + (void) printf("----------------------------------------------" + "---------------\n"); + for (i = 0; i < SPA_FEATURES; i++) { + zfeature_info_t *fi = &spa_feature_table[i]; + const char *ro = fi->fi_can_readonly ? + " (read-only compatible)" : ""; + + (void) printf("%-37s%s\n", fi->fi_uname, ro); + (void) printf(" %s\n", fi->fi_desc); + } + (void) printf("\n"); + + (void) printf(gettext("The following legacy versions are also " "supported:\n\n")); (void) printf(gettext("VER DESCRIPTION\n")); (void) printf("--- -----------------------------------------" @@ -4468,32 +4690,44 @@ zpool_do_upgrade(int argc, char **argv) (void) printf(gettext("\nFor more information on a particular " "version, including supported releases,\n")); (void) printf(gettext("see the ZFS Administration Guide.\n\n")); - } else if (argc == 0) { - int notfound; - + } else if (argc == 0 && upgradeall) { + cb.cb_first = B_TRUE; ret = zpool_iter(g_zfs, upgrade_cb, &cb); - notfound = cb.cb_first; - - if (!cb.cb_all && ret == 0) { - if (!cb.cb_first) - (void) printf("\n"); - cb.cb_first = B_TRUE; - cb.cb_newer = B_TRUE; - ret = zpool_iter(g_zfs, upgrade_cb, &cb); - if (!cb.cb_first) { - notfound = B_FALSE; - (void) printf("\n"); + if (ret == 0 && cb.cb_first) { + if (cb.cb_version == SPA_VERSION) { + (void) printf(gettext("All pools are already " + "formatted using feature flags.\n\n")); + (void) printf(gettext("Every feature flags " + "pool already has all supported features " + "enabled.\n")); + } else { + (void) printf(gettext("All pools are already " + "formatted with version %llu or higher.\n"), + cb.cb_version); } } + } else if (argc == 0) { + cb.cb_first = B_TRUE; + ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); + assert(ret == 0); - if (ret == 0) { - if (notfound) - (void) printf(gettext("All pools are formatted " - "using this version.\n")); - else if (!cb.cb_all) - (void) printf(gettext("Use 'zpool upgrade -v' " - "for a list of available versions and " - "their associated\nfeatures.\n")); + if (cb.cb_first) { + (void) printf(gettext("All pools are formatted " + "using feature flags.\n\n")); + } else { + (void) printf(gettext("\nUse 'zpool upgrade -v' " + "for a list of available legacy versions.\n")); + } + + cb.cb_first = B_TRUE; + ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); + assert(ret == 0); + + if (cb.cb_first) { + (void) printf(gettext("Every feature flags pool has " + "all supported features enabled.\n")); + } else { + (void) printf(gettext("\n")); } } else { ret = for_each_pool(argc, argv, B_FALSE, NULL, diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 56ebf530da..49c86dd18f 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -316,7 +316,8 @@ typedef enum { * requiring administrative attention. There is no corresponding * message ID. */ - ZPOOL_STATUS_VERSION_OLDER, /* older on-disk version */ + ZPOOL_STATUS_VERSION_OLDER, /* older legacy on-disk version */ + ZPOOL_STATUS_FEAT_DISABLED, /* supported features are disabled */ ZPOOL_STATUS_RESILVERING, /* device being resilvered */ ZPOOL_STATUS_OFFLINE_DEV, /* device online */ ZPOOL_STATUS_REMOVED_DEV, /* removed device */ diff --git a/usr/src/lib/libzfs/common/libzfs_status.c b/usr/src/lib/libzfs/common/libzfs_status.c index af0707a620..560bacdc37 100644 --- a/usr/src/lib/libzfs/common/libzfs_status.c +++ b/usr/src/lib/libzfs/common/libzfs_status.c @@ -44,6 +44,7 @@ #include <string.h> #include <unistd.h> #include "libzfs_impl.h" +#include "zfeature_common.h" /* * Message ID table. This must be kept in sync with the ZPOOL_STATUS_* defines @@ -319,6 +320,30 @@ check_status(nvlist_t *config, boolean_t isimport) if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION) return (ZPOOL_STATUS_VERSION_OLDER); + /* + * Usable pool with disabled features + */ + if (version >= SPA_VERSION_FEATURES) { + int i; + nvlist_t *feat; + + if (isimport) { + feat = fnvlist_lookup_nvlist(config, + ZPOOL_CONFIG_LOAD_INFO); + feat = fnvlist_lookup_nvlist(feat, + ZPOOL_CONFIG_ENABLED_FEAT); + } else { + feat = fnvlist_lookup_nvlist(config, + ZPOOL_CONFIG_FEATURE_STATS); + } + + for (i = 0; i < SPA_FEATURES; i++) { + zfeature_info_t *fi = &spa_feature_table[i]; + if (!nvlist_exists(feat, fi->fi_guid)) + return (ZPOOL_STATUS_FEAT_DISABLED); + } + } + return (ZPOOL_STATUS_OK); } diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers index 395bd6261e..15075e3bb5 100644 --- a/usr/src/lib/libzfs/common/mapfile-vers +++ b/usr/src/lib/libzfs/common/mapfile-vers @@ -182,6 +182,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zpool_fru_set; zpool_get_config; zpool_get_errlog; + zpool_get_features; zpool_get_handle; zpool_get_history; zpool_get_name; diff --git a/usr/src/man/man1m/zpool.1m b/usr/src/man/man1m/zpool.1m index a2a9b723cc..b7924bd4f9 100644 --- a/usr/src/man/man1m/zpool.1m +++ b/usr/src/man/man1m/zpool.1m @@ -1692,11 +1692,10 @@ data errors since the last complete pool scrub. .ad .sp .6 .RS 4n -Displays all pools formatted using a different \fBZFS\fR on-disk version. Older -versions can continue to be used, but some features may not be available. These -pools can be upgraded using "\fBzpool upgrade -a\fR". Pools that are formatted -with a more recent version are also displayed, although these pools will be -inaccessible on the system. +Displays pools which do not have all supported features enabled and pools +formatted using a legacy ZFS version number. These pools can continue to be +used, but some features may not be available. Use "\fBzpool upgrade -a\fR" +to enable all features on all pools. .RE .sp @@ -1706,9 +1705,9 @@ inaccessible on the system. .ad .sp .6 .RS 4n -Displays \fBZFS\fR versions supported by the current software. The current -\fBZFS\fR versions and all previous supported versions are displayed, along -with an explanation of the features provided with each version. +Displays legacy \fBZFS\fR versions supported by the current software. See +\fBzfs-features\fR(5) for a description of feature flags features supported +by the current software. .RE .sp @@ -1718,16 +1717,18 @@ with an explanation of the features provided with each version. .ad .sp .6 .RS 4n -Upgrades the given pool to the latest on-disk version. Once this is done, the -pool will no longer be accessible on systems running older versions of the -software. +Enables all supported features on the given pool. Once this is done, the +pool will no longer be accessible on systems that do not support feature +flags. See \fBzfs-features\fR(5) for details on compatability with systems +that support feature flags, but do not support all features enabled on the +pool. .sp .ne 2 .na \fB\fB-a\fR\fR .ad .RS 14n -Upgrades all pools. +Enables all supported features on all pools. .RE .sp @@ -1736,10 +1737,9 @@ Upgrades all pools. \fB\fB-V\fR \fIversion\fR\fR .ad .RS 14n -Upgrade to the specified version. If the \fB-V\fR flag is not specified, the -pool is upgraded to the most recent version. This option can only be used to -increase the version number, and only up to the most recent version supported -by this software. +Upgrade to the specified legacy version. If the \fB-V\fR flag is specified, no +features will be enabled on the pool. This option can only be used to increase +the version number up to the last supported legacy version number. .RE .RE diff --git a/usr/src/man/man5/zpool-features.5 b/usr/src/man/man5/zpool-features.5 index 453e1ad2a4..3c1930c35a 100644 --- a/usr/src/man/man5/zpool-features.5 +++ b/usr/src/man/man5/zpool-features.5 @@ -20,8 +20,9 @@ zpool\-features \- ZFS pool feature descriptions .LP ZFS pool on\-disk format versions are specified via "features" which replace the old on\-disk format numbers (the last supported on\-disk format number is -28). To enable a feature on a pool use the \fBzpool\fR(1M) command to set -the \fBfeature@\fR\fIfeature_name\fR property to \fBenabled\fR. +28). To enable a feature on a pool use the \fBupgrade\fR subcommand of the +\fBzpool\fR(1M) command, or set the \fBfeature@\fR\fIfeature_name\fR property +to \fBenabled\fR. .sp .LP The pool format does not affect file system version compatibility or the ability diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index 828d5e2666..9c4af11134 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -2149,7 +2149,7 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config, if (spa_version(spa) >= SPA_VERSION_FEATURES) { boolean_t missing_feat_read = B_FALSE; - nvlist_t *unsup_feat; + nvlist_t *unsup_feat, *enabled_feat; if (spa_dir_prop(spa, DMU_POOL_FEATURES_FOR_READ, &spa->spa_feat_for_read_obj) != 0) { @@ -2166,27 +2166,32 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config, return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO)); } - VERIFY(nvlist_alloc(&unsup_feat, NV_UNIQUE_NAME, KM_SLEEP) == - 0); + enabled_feat = fnvlist_alloc(); + unsup_feat = fnvlist_alloc(); if (!feature_is_supported(spa->spa_meta_objset, spa->spa_feat_for_read_obj, spa->spa_feat_desc_obj, - unsup_feat)) + unsup_feat, enabled_feat)) missing_feat_read = B_TRUE; if (spa_writeable(spa) || state == SPA_LOAD_TRYIMPORT) { if (!feature_is_supported(spa->spa_meta_objset, spa->spa_feat_for_write_obj, spa->spa_feat_desc_obj, - unsup_feat)) + unsup_feat, enabled_feat)) { missing_feat_write = B_TRUE; + } } + fnvlist_add_nvlist(spa->spa_load_info, + ZPOOL_CONFIG_ENABLED_FEAT, enabled_feat); + if (!nvlist_empty(unsup_feat)) { - VERIFY(nvlist_add_nvlist(spa->spa_load_info, - ZPOOL_CONFIG_UNSUP_FEAT, unsup_feat) == 0); + fnvlist_add_nvlist(spa->spa_load_info, + ZPOOL_CONFIG_UNSUP_FEAT, unsup_feat); } - nvlist_free(unsup_feat); + fnvlist_free(enabled_feat); + fnvlist_free(unsup_feat); if (!missing_feat_read) { fnvlist_add_boolean(spa->spa_load_info, diff --git a/usr/src/uts/common/fs/zfs/sys/zfeature.h b/usr/src/uts/common/fs/zfs/sys/zfeature.h index 9ff1c93df7..481e85b1ba 100644 --- a/usr/src/uts/common/fs/zfs/sys/zfeature.h +++ b/usr/src/uts/common/fs/zfs/sys/zfeature.h @@ -35,7 +35,7 @@ extern "C" { #endif extern boolean_t feature_is_supported(objset_t *os, uint64_t obj, - uint64_t desc_obj, nvlist_t *unsup_feat); + uint64_t desc_obj, nvlist_t *unsup_feat, nvlist_t *enabled_feat); struct spa; extern void spa_feature_create_zap_objects(struct spa *, dmu_tx_t *); diff --git a/usr/src/uts/common/fs/zfs/zfeature.c b/usr/src/uts/common/fs/zfs/zfeature.c index ba722088a4..b9250df4a9 100644 --- a/usr/src/uts/common/fs/zfs/zfeature.c +++ b/usr/src/uts/common/fs/zfs/zfeature.c @@ -173,7 +173,7 @@ typedef enum { */ boolean_t feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj, - nvlist_t *unsup_feat) + nvlist_t *unsup_feat, nvlist_t *enabled_feat) { boolean_t supported; zap_cursor_t zc; @@ -186,11 +186,16 @@ feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj, ASSERT(za.za_integer_length == sizeof (uint64_t) && za.za_num_integers == 1); + if (NULL != enabled_feat) { + fnvlist_add_uint64(enabled_feat, za.za_name, + za.za_first_integer); + } + if (za.za_first_integer != 0 && !zfeature_is_supported(za.za_name)) { supported = B_FALSE; - if (unsup_feat != NULL) { + if (NULL != unsup_feat) { char *desc = ""; char buf[MAXPATHLEN]; diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h index 511fa95898..8639a2b8db 100644 --- a/usr/src/uts/common/sys/fs/zfs.h +++ b/usr/src/uts/common/sys/fs/zfs.h @@ -528,6 +528,7 @@ typedef struct zpool_rewind_policy { #define ZPOOL_CONFIG_LOAD_INFO "load_info" /* not stored on disk */ #define ZPOOL_CONFIG_REWIND_INFO "rewind_info" /* not stored on disk */ #define ZPOOL_CONFIG_UNSUP_FEAT "unsup_feat" /* not stored on disk */ +#define ZPOOL_CONFIG_ENABLED_FEAT "enabled_feat" /* not stored on disk */ #define ZPOOL_CONFIG_CAN_RDONLY "can_rdonly" /* not stored on disk */ #define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read" #define ZPOOL_CONFIG_FEATURE_STATS "feature_stats" /* not stored on disk */ |