From 658fb8020f0501435516baeea7004575d640649b Mon Sep 17 00:00:00 2001 From: Colm Date: Thu, 18 Feb 2021 05:30:45 +0000 Subject: [PATCH] Add "compatibility" property for zpool feature sets Property to allow sets of features to be specified; for compatibility with specific versions / releases / external systems. Influences the behavior of 'zpool upgrade' and 'zpool create'. Initial man page changes and test cases included. Brief synopsis: zpool create -o compatibility=off|legacy|file[,file...] pool vdev... compatibility = off : disable compatibility mode (enable all features) compatibility = legacy : request that no features be enabled compatibility = file[,file...] : read features from specified files. Only features present in *all* files will be enabled on the resulting pool. Filenames may be absolute, or relative to /etc/zfs/compatibility.d or /usr/share/zfs/compatibility.d (/etc checked first). Only affects zpool create, zpool upgrade and zpool status. ABI changes in libzfs: * New function "zpool_load_compat" to load and parse compat sets. * Add "zpool_compat_status_t" typedef for compatibility parse status. * Add ZPOOL_PROP_COMPATIBILITY to the pool properties enum * Add ZPOOL_STATUS_COMPATIBILITY_ERR to the pool status enum An initial set of base compatibility sets are included in cmd/zpool/compatibility.d, and the Makefile for cmd/zpool is modified to install these in $pkgdatadir/compatibility.d and to create symbolic links to a reasonable set of aliases. Reviewed-by: ericloewe Reviewed-by: Matthew Ahrens Reviewed-by: Richard Laager Reviewed-by: Brian Behlendorf Signed-off-by: Colm Buckley Closes #11468 --- cmd/zpool/Makefile.am | 47 +- cmd/zpool/compatibility.d/compat-2018 | 12 + cmd/zpool/compatibility.d/compat-2019 | 15 + cmd/zpool/compatibility.d/compat-2020 | 15 + cmd/zpool/compatibility.d/compat-2021 | 19 + cmd/zpool/compatibility.d/freebsd-11.0 | 15 + cmd/zpool/compatibility.d/freebsd-11.2 | 18 + cmd/zpool/compatibility.d/freebsd-11.3 | 19 + cmd/zpool/compatibility.d/freenas-9.10.2 | 13 + cmd/zpool/compatibility.d/grub2 | 12 + cmd/zpool/compatibility.d/openzfs-2.0-freebsd | 33 + cmd/zpool/compatibility.d/openzfs-2.0-linux | 34 + cmd/zpool/compatibility.d/openzfsonosx-1.7.0 | 16 + cmd/zpool/compatibility.d/openzfsonosx-1.8.1 | 21 + cmd/zpool/compatibility.d/openzfsonosx-1.9.3 | 27 + cmd/zpool/compatibility.d/zol-0.6.5 | 12 + cmd/zpool/compatibility.d/zol-0.7 | 18 + cmd/zpool/compatibility.d/zol-0.8 | 27 + cmd/zpool/zpool_main.c | 157 +- config/Rules.am | 1 + include/libzfs.h | 16 + include/sys/fs/zfs.h | 19 +- include/sys/spa_impl.h | 2 + lib/libzfs/libzfs.abi | 7189 ++++++++++------- lib/libzfs/libzfs_pool.c | 228 + lib/libzfs/libzfs_status.c | 29 +- lib/libzutil/zutil_import.c | 10 + man/man5/zpool-features.5 | 59 +- man/man8/zpool-create.8 | 16 +- man/man8/zpool-upgrade.8 | 16 +- man/man8/zpoolprops.8 | 19 + module/zcommon/zpool_prop.c | 4 + module/zfs/spa.c | 30 + module/zfs/spa_config.c | 4 + rpm/generic/zfs.spec.in | 6 +- scripts/Makefile.am | 1 + tests/runfiles/common.run | 8 +- tests/zfs-tests/include/default.cfg.in | 1 + .../cli_root/zpool_create/Makefile.am | 3 + .../cli_root/zpool_create/zpool_create.shlib | 81 + .../zpool_create_features_006_pos.ksh | 58 + .../zpool_create_features_007_pos.ksh | 54 + .../zpool_create_features_008_pos.ksh | 54 + .../cli_root/zpool_get/zpool_get.cfg | 1 + .../cli_root/zpool_status/Makefile.am | 3 +- .../zpool_status_features_001_pos.ksh | 63 + .../cli_root/zpool_upgrade/Makefile.am | 3 +- .../zpool_upgrade_features_001_pos.ksh | 67 + 48 files changed, 5621 insertions(+), 2954 deletions(-) create mode 100644 cmd/zpool/compatibility.d/compat-2018 create mode 100644 cmd/zpool/compatibility.d/compat-2019 create mode 100644 cmd/zpool/compatibility.d/compat-2020 create mode 100644 cmd/zpool/compatibility.d/compat-2021 create mode 100644 cmd/zpool/compatibility.d/freebsd-11.0 create mode 100644 cmd/zpool/compatibility.d/freebsd-11.2 create mode 100644 cmd/zpool/compatibility.d/freebsd-11.3 create mode 100644 cmd/zpool/compatibility.d/freenas-9.10.2 create mode 100644 cmd/zpool/compatibility.d/grub2 create mode 100644 cmd/zpool/compatibility.d/openzfs-2.0-freebsd create mode 100644 cmd/zpool/compatibility.d/openzfs-2.0-linux create mode 100644 cmd/zpool/compatibility.d/openzfsonosx-1.7.0 create mode 100644 cmd/zpool/compatibility.d/openzfsonosx-1.8.1 create mode 100644 cmd/zpool/compatibility.d/openzfsonosx-1.9.3 create mode 100644 cmd/zpool/compatibility.d/zol-0.6.5 create mode 100644 cmd/zpool/compatibility.d/zol-0.7 create mode 100644 cmd/zpool/compatibility.d/zol-0.8 create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_006_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_007_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_008_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_features_001_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_features_001_pos.ksh diff --git a/cmd/zpool/Makefile.am b/cmd/zpool/Makefile.am index fb03e99a30..d47051e4fe 100644 --- a/cmd/zpool/Makefile.am +++ b/cmd/zpool/Makefile.am @@ -39,7 +39,7 @@ include $(top_srcdir)/config/CppCheck.am zpoolconfdir = $(sysconfdir)/zfs/zpool.d zpoolexecdir = $(zfsexecdir)/zpool.d -EXTRA_DIST = zpool.d/README +EXTRA_DIST = zpool.d/README compatibility.d dist_zpoolexec_SCRIPTS = \ zpool.d/dm-deps \ @@ -129,6 +129,48 @@ zpoolconfdefaults = \ test_progress \ test_ended +zpoolcompatdir = $(pkgdatadir)/compatibility.d + +dist_zpoolcompat_DATA = \ + compatibility.d/compat-2018 \ + compatibility.d/compat-2019 \ + compatibility.d/compat-2020 \ + compatibility.d/compat-2021 \ + compatibility.d/freebsd-11.0 \ + compatibility.d/freebsd-11.2 \ + compatibility.d/freebsd-11.3 \ + compatibility.d/freenas-9.10.2 \ + compatibility.d/grub2 \ + compatibility.d/openzfsonosx-1.7.0 \ + compatibility.d/openzfsonosx-1.8.1 \ + compatibility.d/openzfsonosx-1.9.3 \ + compatibility.d/openzfs-2.0-freebsd \ + compatibility.d/openzfs-2.0-linux \ + compatibility.d/zol-0.6.5 \ + compatibility.d/zol-0.7 \ + compatibility.d/zol-0.8 + +# canonical <- alias symbolic link pairs +# eg: "2018" is a link to "compat-2018" +zpoolcompatlinks = \ + "compat-2018 2018" \ + "compat-2019 2019" \ + "compat-2020 2020" \ + "compat-2021 2021" \ + "freebsd-11.0 freebsd-11.1" \ + "freebsd-11.0 freenas-11.0" \ + "freebsd-11.2 freenas-11.2" \ + "freebsd-11.3 freebsd-11.4" \ + "freebsd-11.3 freebsd-12.0" \ + "freebsd-11.3 freebsd-12.1" \ + "freebsd-11.3 freebsd-12.2" \ + "freebsd-11.3 freenas-11.3" \ + "freenas-11.0 freenas-11.1" \ + "openzfsonosx-1.9.3 openzfsonosx-1.9.4" \ + "openzfs-2.0-freebsd truenas-12.0" \ + "zol-0.7 ubuntu-18.04" \ + "zol-0.8 ubuntu-20.04" + install-data-hook: $(MKDIR_P) "$(DESTDIR)$(zpoolconfdir)" for f in $(zpoolconfdefaults); do \ @@ -136,3 +178,6 @@ install-data-hook: -L "$(DESTDIR)$(zpoolconfdir)/$${f}" || \ ln -s "$(zpoolexecdir)/$${f}" "$(DESTDIR)$(zpoolconfdir)"; \ done + for l in $(zpoolcompatlinks); do \ + (cd "$(DESTDIR)$(zpoolcompatdir)"; ln -s $${l} ); \ + done diff --git a/cmd/zpool/compatibility.d/compat-2018 b/cmd/zpool/compatibility.d/compat-2018 new file mode 100644 index 0000000000..7be44e1eee --- /dev/null +++ b/cmd/zpool/compatibility.d/compat-2018 @@ -0,0 +1,12 @@ +# Features supported by all Tier 1 platforms as of 2018 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/compat-2019 b/cmd/zpool/compatibility.d/compat-2019 new file mode 100644 index 0000000000..c105cc70c2 --- /dev/null +++ b/cmd/zpool/compatibility.d/compat-2019 @@ -0,0 +1,15 @@ +# Features supported by all Tier 1 platforms as of 2019 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +sha512 +skein +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/compat-2020 b/cmd/zpool/compatibility.d/compat-2020 new file mode 100644 index 0000000000..8d46a571e6 --- /dev/null +++ b/cmd/zpool/compatibility.d/compat-2020 @@ -0,0 +1,15 @@ +# Features supported by all Tier 1 platforms as of 2020 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +sha512 +skein +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/compat-2021 b/cmd/zpool/compatibility.d/compat-2021 new file mode 100644 index 0000000000..f45c82d656 --- /dev/null +++ b/cmd/zpool/compatibility.d/compat-2021 @@ -0,0 +1,19 @@ +# Features supported by all Tier 1 platforms as of 2021 +async_destroy +bookmarks +device_removal +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +obsolete_counts +sha512 +skein +spacemap_histogram +spacemap_v2 +zpool_checkpoint diff --git a/cmd/zpool/compatibility.d/freebsd-11.0 b/cmd/zpool/compatibility.d/freebsd-11.0 new file mode 100644 index 0000000000..8718559ffb --- /dev/null +++ b/cmd/zpool/compatibility.d/freebsd-11.0 @@ -0,0 +1,15 @@ +# Features supported by FreeBSD 11.0 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +sha512 +skein +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/freebsd-11.2 b/cmd/zpool/compatibility.d/freebsd-11.2 new file mode 100644 index 0000000000..14d2d573b2 --- /dev/null +++ b/cmd/zpool/compatibility.d/freebsd-11.2 @@ -0,0 +1,18 @@ +# Features supported by FreeBSD 11.2 +async_destroy +bookmarks +device_removal +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +obsolete_counts +sha512 +skein +spacemap_histogram +zpool_checkpoint diff --git a/cmd/zpool/compatibility.d/freebsd-11.3 b/cmd/zpool/compatibility.d/freebsd-11.3 new file mode 100644 index 0000000000..802cc3630d --- /dev/null +++ b/cmd/zpool/compatibility.d/freebsd-11.3 @@ -0,0 +1,19 @@ +# Features supported by FreeBSD 11.3 +async_destroy +bookmarks +device_removal +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +obsolete_counts +sha512 +skein +spacemap_histogram +spacemap_v2 +zpool_checkpoint diff --git a/cmd/zpool/compatibility.d/freenas-9.10.2 b/cmd/zpool/compatibility.d/freenas-9.10.2 new file mode 100644 index 0000000000..10789c96cc --- /dev/null +++ b/cmd/zpool/compatibility.d/freenas-9.10.2 @@ -0,0 +1,13 @@ +# Features supported by FreeNAS 9.10.2 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/grub2 b/cmd/zpool/compatibility.d/grub2 new file mode 100644 index 0000000000..4e8f213625 --- /dev/null +++ b/cmd/zpool/compatibility.d/grub2 @@ -0,0 +1,12 @@ +# Features which are supported by GRUB2 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/openzfs-2.0-freebsd b/cmd/zpool/compatibility.d/openzfs-2.0-freebsd new file mode 100644 index 0000000000..e7ee2f2476 --- /dev/null +++ b/cmd/zpool/compatibility.d/openzfs-2.0-freebsd @@ -0,0 +1,33 @@ +# Features supported by OpenZFS 2.0 on FreeBSD +allocation_classes +async_destroy +bookmark_v2 +bookmark_written +bookmarks +device_rebuild +device_removal +embedded_data +empty_bpobj +enabled_txg +encryption +extensible_dataset +filesystem_limits +hole_birth +large_blocks +large_dnode +livelist +log_spacemap +lz4_compress +multi_vdev_crash_dump +obsolete_counts +project_quota +redacted_datasets +redaction_bookmarks +resilver_defer +sha512 +skein +spacemap_histogram +spacemap_v2 +userobj_accounting +zpool_checkpoint +zstd_compress diff --git a/cmd/zpool/compatibility.d/openzfs-2.0-linux b/cmd/zpool/compatibility.d/openzfs-2.0-linux new file mode 100644 index 0000000000..ac0f5c8634 --- /dev/null +++ b/cmd/zpool/compatibility.d/openzfs-2.0-linux @@ -0,0 +1,34 @@ +# Features supported by OpenZFS 2.0 on Linux +allocation_classes +async_destroy +bookmark_v2 +bookmark_written +bookmarks +device_rebuild +device_removal +edonr +embedded_data +empty_bpobj +enabled_txg +encryption +extensible_dataset +filesystem_limits +hole_birth +large_blocks +large_dnode +livelist +log_spacemap +lz4_compress +multi_vdev_crash_dump +obsolete_counts +project_quota +redacted_datasets +redaction_bookmarks +resilver_defer +sha512 +skein +spacemap_histogram +spacemap_v2 +userobj_accounting +zpool_checkpoint +zstd_compress diff --git a/cmd/zpool/compatibility.d/openzfsonosx-1.7.0 b/cmd/zpool/compatibility.d/openzfsonosx-1.7.0 new file mode 100644 index 0000000000..4ae87c964c --- /dev/null +++ b/cmd/zpool/compatibility.d/openzfsonosx-1.7.0 @@ -0,0 +1,16 @@ +# Features supported by OpenZFSonOSX 1.7.0 +async_destroy +bookmarks +edonr +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +sha512 +skein +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/openzfsonosx-1.8.1 b/cmd/zpool/compatibility.d/openzfsonosx-1.8.1 new file mode 100644 index 0000000000..162ff32a78 --- /dev/null +++ b/cmd/zpool/compatibility.d/openzfsonosx-1.8.1 @@ -0,0 +1,21 @@ +# Features supported by OpenZFSonOSX 1.8.1 +async_destroy +bookmarks +device_removal +edonr +embedded_data +empty_bpobj +enabled_txg +encryption +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +multi_vdev_crash_dump +obsolete_counts +sha512 +skein +spacemap_histogram +spacemap_v2 +zpool_checkpoint diff --git a/cmd/zpool/compatibility.d/openzfsonosx-1.9.3 b/cmd/zpool/compatibility.d/openzfsonosx-1.9.3 new file mode 100644 index 0000000000..b0b28ec049 --- /dev/null +++ b/cmd/zpool/compatibility.d/openzfsonosx-1.9.3 @@ -0,0 +1,27 @@ +# Features supported by OpenZFSonOSX 1.9.3 +allocation_classes +async_destroy +bookmark_v2 +bookmarks +device_removal +edonr +embedded_data +empty_bpobj +enabled_txg +encryption +extensible_dataset +filesystem_limits +hole_birth +large_blocks +large_dnode +lz4_compress +multi_vdev_crash_dump +obsolete_counts +project_quota +resilver_defer +sha512 +skein +spacemap_histogram +spacemap_v2 +userobj_accounting +zpool_checkpoint diff --git a/cmd/zpool/compatibility.d/zol-0.6.5 b/cmd/zpool/compatibility.d/zol-0.6.5 new file mode 100644 index 0000000000..cb9a94d889 --- /dev/null +++ b/cmd/zpool/compatibility.d/zol-0.6.5 @@ -0,0 +1,12 @@ +# Features supported by ZFSonLinux v0.6.5 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +spacemap_histogram diff --git a/cmd/zpool/compatibility.d/zol-0.7 b/cmd/zpool/compatibility.d/zol-0.7 new file mode 100644 index 0000000000..22a02936df --- /dev/null +++ b/cmd/zpool/compatibility.d/zol-0.7 @@ -0,0 +1,18 @@ +# Features supported by ZFSonLinux v0.7 +async_destroy +bookmarks +edonr +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +large_dnode +lz4_compress +multi_vdev_crash_dump +sha512 +skein +spacemap_histogram +userobj_accounting diff --git a/cmd/zpool/compatibility.d/zol-0.8 b/cmd/zpool/compatibility.d/zol-0.8 new file mode 100644 index 0000000000..762848ef7b --- /dev/null +++ b/cmd/zpool/compatibility.d/zol-0.8 @@ -0,0 +1,27 @@ +# Features supported by ZFSonLinux v0.8 +allocation_classes +async_destroy +bookmark_v2 +bookmarks +device_removal +edonr +embedded_data +empty_bpobj +enabled_txg +encryption +extensible_dataset +filesystem_limits +hole_birth +large_blocks +large_dnode +lz4_compress +multi_vdev_crash_dump +obsolete_counts +project_quota +resilver_defer +sha512 +skein +spacemap_histogram +spacemap_v2 +userobj_accounting +zpool_checkpoint diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index eef12d97f3..29252e6a24 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -31,6 +31,7 @@ * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, loli10K + * Copyright (c) 2021, Colm Buckley */ #include @@ -124,6 +125,9 @@ static int zpool_do_version(int, char **); static int zpool_do_wait(int, char **); +static zpool_compat_status_t zpool_do_load_compat( + const char *, boolean_t *); + /* * These libumem hooks provide a reasonable set of defaults for the allocator's * debugging facilities. @@ -782,6 +786,8 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props, if (poolprop) { const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); + const char *fname = + zpool_prop_to_name(ZPOOL_PROP_COMPATIBILITY); if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL && !zpool_prop_feature(propname)) { @@ -804,6 +810,19 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props, return (2); } + /* + * compatibility property and version should not be specified + * at the same time. + */ + if ((prop == ZPOOL_PROP_COMPATIBILITY && + nvlist_exists(proplist, vname)) || + (prop == ZPOOL_PROP_VERSION && + nvlist_exists(proplist, fname))) { + (void) fprintf(stderr, gettext("'compatibility' and " + "'version' properties cannot be specified " + "together\n")); + return (2); + } if (zpool_prop_feature(propname)) normnm = propname; @@ -1374,13 +1393,15 @@ 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; + boolean_t enable_pool_features = B_TRUE; + int c; nvlist_t *nvroot = NULL; char *poolname; char *tname = NULL; int ret = 1; char *altroot = NULL; + char *compat = NULL; char *mountpoint = NULL; nvlist_t *fsprops = NULL; nvlist_t *props = NULL; @@ -1396,7 +1417,7 @@ zpool_do_create(int argc, char **argv) dryrun = B_TRUE; break; case 'd': - enable_all_pool_feat = B_FALSE; + enable_pool_features = B_FALSE; break; case 'R': altroot = optarg; @@ -1434,11 +1455,14 @@ zpool_do_create(int argc, char **argv) ver = strtoull(propval, &end, 10); if (*end == '\0' && ver < SPA_VERSION_FEATURES) { - enable_all_pool_feat = B_FALSE; + enable_pool_features = B_FALSE; } } if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) altroot = propval; + if (zpool_name_to_prop(optarg) == + ZPOOL_PROP_COMPATIBILITY) + compat = propval; break; case 'O': if ((propval = strchr(optarg, '=')) == NULL) { @@ -1632,10 +1656,26 @@ zpool_do_create(int argc, char **argv) ret = 0; } else { /* - * Hand off to libzfs. + * Load in feature set. + * Note: if compatibility property not given, we'll have + * NULL, which means 'all features'. */ - spa_feature_t i; - for (i = 0; i < SPA_FEATURES; i++) { + boolean_t requested_features[SPA_FEATURES]; + if (zpool_do_load_compat(compat, requested_features) != + ZPOOL_COMPATIBILITY_OK) + goto errout; + + /* + * props contains list of features to enable. + * For each feature: + * - remove it if feature@name=disabled + * - leave it there if feature@name=enabled + * - add it if: + * - enable_pool_features (ie: no '-d' or '-o version') + * - it's supported by the kernel module + * - it's in the requested feature set + */ + for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { char propname[MAXPATHLEN]; char *propval; zfeature_info_t *feat = &spa_feature_table[i]; @@ -1643,18 +1683,14 @@ zpool_do_create(int argc, char **argv) (void) snprintf(propname, sizeof (propname), "feature@%s", feat->fi_uname); - /* - * Only features contained in props will be enabled: - * remove from the nvlist every ZFS_FEATURE_DISABLED - * value and add every missing ZFS_FEATURE_ENABLED if - * enable_all_pool_feat is set. - */ if (!nvlist_lookup_string(props, propname, &propval)) { if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0) (void) nvlist_remove_all(props, propname); - } else if (enable_all_pool_feat && - feat->fi_zfs_mod_supported) { + } else if ( + enable_pool_features && + feat->fi_zfs_mod_supported && + requested_features[i]) { ret = add_prop_list(propname, ZFS_FEATURE_ENABLED, &props, B_TRUE); if (ret != 0) @@ -2674,8 +2710,15 @@ show_import(nvlist_t *config) case ZPOOL_STATUS_FEAT_DISABLED: printf_color(ANSI_BOLD, gettext("status: ")); - printf_color(ANSI_YELLOW, gettext("Some supported features are " - "not enabled on the pool.\n")); + printf_color(ANSI_YELLOW, gettext("Some supported and " + "requested features are not enabled on the pool.\n")); + break; + + case ZPOOL_STATUS_COMPATIBILITY_ERR: + printf_color(ANSI_BOLD, gettext("status: ")); + printf_color(ANSI_YELLOW, gettext("Error reading or parsing " + "the file(s) indicated by the 'compatibility'\n" + "property.\n")); break; case ZPOOL_STATUS_UNSUP_FEAT_READ: @@ -2767,6 +2810,12 @@ show_import(nvlist_t *config) "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_COMPATIBILITY_ERR) { + (void) printf(gettext(" action: The pool can be " + "imported using its name or numeric\n\tidentifier, " + "though the file(s) indicated by its " + "'compatibility'\n\tproperty cannot be parsed at " + "this time.\n")); } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { (void) printf(gettext(" action: The pool can be " "imported using its name or numeric " @@ -7942,7 +7991,8 @@ status_callback(zpool_handle_t *zhp, void *data) if (cbp->cb_explain && (reason == ZPOOL_STATUS_OK || reason == ZPOOL_STATUS_VERSION_OLDER || - reason == ZPOOL_STATUS_FEAT_DISABLED)) { + reason == ZPOOL_STATUS_FEAT_DISABLED || + reason == ZPOOL_STATUS_COMPATIBILITY_ERR)) { if (!cbp->cb_allpools) { (void) printf(gettext("pool '%s' is healthy\n"), zpool_get_name(zhp)); @@ -8117,9 +8167,10 @@ status_callback(zpool_handle_t *zhp, void *data) case ZPOOL_STATUS_FEAT_DISABLED: printf_color(ANSI_BOLD, gettext("status: ")); - printf_color(ANSI_YELLOW, gettext("Some supported features are " - "not enabled on the pool. The pool can\n\tstill be used, " - "but some features are unavailable.\n")); + printf_color(ANSI_YELLOW, gettext("Some supported and " + "requested features are not enabled on the pool.\n\t" + "The pool can still be used, but some features are " + "unavailable.\n")); printf_color(ANSI_BOLD, gettext("action: ")); printf_color(ANSI_YELLOW, gettext("Enable all features using " "'zpool upgrade'. Once this is done,\n\tthe pool may no " @@ -8127,6 +8178,19 @@ status_callback(zpool_handle_t *zhp, void *data) "the features. See zpool-features(5) for details.\n")); break; + case ZPOOL_STATUS_COMPATIBILITY_ERR: + printf_color(ANSI_BOLD, gettext("status: ")); + printf_color(ANSI_YELLOW, gettext("This pool has a " + "compatibility list specified, but it could not be\n\t" + "read/parsed at this time. The pool can still be used, " + "but this\n\tshould be investigated.\n")); + printf_color(ANSI_BOLD, gettext("action: ")); + printf_color(ANSI_YELLOW, gettext("Check the value of the " + "'compatibility' property against the\n\t" + "appropriate file in " ZPOOL_SYSCONF_COMPAT_D " or " + ZPOOL_DATA_COMPAT_D ".\n")); + break; + case ZPOOL_STATUS_UNSUP_FEAT_READ: printf_color(ANSI_BOLD, gettext("status: ")); printf_color(ANSI_YELLOW, gettext("The pool cannot be accessed " @@ -8625,6 +8689,16 @@ upgrade_enable_all(zpool_handle_t *zhp, int *countp) boolean_t firstff = B_TRUE; nvlist_t *enabled = zpool_get_features(zhp); + char compat[ZFS_MAXPROPLEN]; + if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compat, + ZFS_MAXPROPLEN, NULL, B_FALSE) != 0) + compat[0] = '\0'; + + boolean_t requested_features[SPA_FEATURES]; + if (zpool_do_load_compat(compat, requested_features) != + ZPOOL_COMPATIBILITY_OK) + return (-1); + count = 0; for (i = 0; i < SPA_FEATURES; i++) { const char *fname = spa_feature_table[i].fi_uname; @@ -8633,7 +8707,7 @@ upgrade_enable_all(zpool_handle_t *zhp, int *countp) if (!spa_feature_table[i].fi_zfs_mod_supported) continue; - if (!nvlist_exists(enabled, fguid)) { + if (!nvlist_exists(enabled, fguid) && requested_features[i]) { char *propname; verify(-1 != asprintf(&propname, "feature@%s", fname)); ret = zpool_set_prop(zhp, propname, @@ -8855,7 +8929,7 @@ upgrade_one(zpool_handle_t *zhp, void *data) printnl = B_TRUE; } else if (cur_version == SPA_VERSION) { (void) printf(gettext("Pool '%s' already has all " - "supported features enabled.\n"), + "supported and requested features enabled.\n"), zpool_get_name(zhp)); } } @@ -9016,8 +9090,8 @@ zpool_do_upgrade(int argc, char **argv) (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")); + "pool already has all supported and " + "requested features enabled.\n")); } else { (void) printf(gettext("All pools are already " "formatted with version %llu or higher.\n"), @@ -9043,7 +9117,7 @@ zpool_do_upgrade(int argc, char **argv) if (cb.cb_first) { (void) printf(gettext("Every feature flags pool has " - "all supported features enabled.\n")); + "all supported and requested features enabled.\n")); } else { (void) printf(gettext("\n")); } @@ -10347,6 +10421,39 @@ zpool_do_version(int argc, char **argv) return (0); } +/* + * Do zpool_load_compat() and print error message on failure + */ +static zpool_compat_status_t +zpool_do_load_compat(const char *compat, boolean_t *list) +{ + char badword[ZFS_MAXPROPLEN]; + char badfile[MAXPATHLEN]; + zpool_compat_status_t ret; + + switch (ret = zpool_load_compat(compat, list, badword, badfile)) { + case ZPOOL_COMPATIBILITY_OK: + break; + case ZPOOL_COMPATIBILITY_READERR: + (void) fprintf(stderr, gettext("error reading compatibility " + "file '%s'\n"), badfile); + break; + case ZPOOL_COMPATIBILITY_BADFILE: + (void) fprintf(stderr, gettext("compatibility file '%s' " + "too large or not newline-terminated\n"), badfile); + break; + case ZPOOL_COMPATIBILITY_BADWORD: + (void) fprintf(stderr, gettext("unknown feature '%s' in " + "compatibility file '%s'\n"), badword, badfile); + break; + case ZPOOL_COMPATIBILITY_NOFILES: + (void) fprintf(stderr, gettext("no compatibility files " + "specified\n")); + break; + } + return (ret); +} + int main(int argc, char **argv) { diff --git a/config/Rules.am b/config/Rules.am index e9cd134ede..99587eab2b 100644 --- a/config/Rules.am +++ b/config/Rules.am @@ -44,6 +44,7 @@ AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\" AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\" AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\" AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\" +AM_CPPFLAGS += -DPKGDATADIR=\"$(pkgdatadir)\" AM_CPPFLAGS += $(DEBUG_CPPFLAGS) AM_CPPFLAGS += $(CODE_COVERAGE_CPPFLAGS) if BUILD_LINUX diff --git a/include/libzfs.h b/include/libzfs.h index 66cedd0ee0..5f0bc03be1 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -28,6 +28,7 @@ * Copyright 2016 Nexenta Systems, Inc. * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. * Copyright (c) 2019 Datto Inc. + * Copyright (c) 2021, Colm Buckley */ #ifndef _LIBZFS_H @@ -391,6 +392,7 @@ typedef enum { ZPOOL_STATUS_REBUILDING, /* device being rebuilt */ ZPOOL_STATUS_REBUILD_SCRUB, /* recommend scrubbing the pool */ ZPOOL_STATUS_NON_NATIVE_ASHIFT, /* (e.g. 512e dev with ashift of 9) */ + ZPOOL_STATUS_COMPATIBILITY_ERR, /* bad 'compatibility' property */ /* * Finally, the following indicates a healthy pool. @@ -912,6 +914,20 @@ int zfs_smb_acl_rename(libzfs_handle_t *, char *, char *, char *, char *); extern int zpool_enable_datasets(zpool_handle_t *, const char *, int); extern int zpool_disable_datasets(zpool_handle_t *, boolean_t); +/* + * Parse a features file for -o compatibility + */ +typedef enum { + ZPOOL_COMPATIBILITY_OK, + ZPOOL_COMPATIBILITY_READERR, + ZPOOL_COMPATIBILITY_BADFILE, + ZPOOL_COMPATIBILITY_BADWORD, + ZPOOL_COMPATIBILITY_NOFILES +} zpool_compat_status_t; + +extern zpool_compat_status_t zpool_load_compat(const char *, + boolean_t *, char *, char *); + #ifdef __FreeBSD__ /* diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 65515e3829..71d736d5cc 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -27,10 +27,10 @@ * Copyright (c) 2014 Integros [integros.com] * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019 Datto Inc. + * Portions Copyright 2010 Robert Milkowski + * Copyright (c) 2021, Colm Buckley */ -/* Portions Copyright 2010 Robert Milkowski */ - #ifndef _SYS_FS_ZFS_H #define _SYS_FS_ZFS_H @@ -246,6 +246,7 @@ typedef enum { ZPOOL_PROP_CHECKPOINT, ZPOOL_PROP_LOAD_GUID, ZPOOL_PROP_AUTOTRIM, + ZPOOL_PROP_COMPATIBILITY, ZPOOL_NUM_PROPS } zpool_prop_t; @@ -733,6 +734,7 @@ typedef struct zpool_load_policy { #define ZPOOL_CONFIG_ALLOCATION_BIAS "alloc_bias" /* not stored on disk */ #define ZPOOL_CONFIG_EXPANSION_TIME "expansion_time" /* not stored */ #define ZPOOL_CONFIG_REBUILD_STATS "org.openzfs:rebuild_stats" +#define ZPOOL_CONFIG_COMPATIBILITY "compatibility" /* * The persistent vdev state is stored as separate values rather than a single @@ -845,6 +847,19 @@ typedef struct zpool_load_policy { */ #define ZPOOL_CACHE_BOOT "/boot/zfs/zpool.cache" #define ZPOOL_CACHE "/etc/zfs/zpool.cache" +/* + * Settings for zpool compatibility features files + */ +#define ZPOOL_SYSCONF_COMPAT_D SYSCONFDIR "/zfs/compatibility.d" +#define ZPOOL_DATA_COMPAT_D PKGDATADIR "/compatibility.d" +#define ZPOOL_COMPAT_MAXSIZE 16384 + +/* + * Hard-wired compatibility settings + */ +#define ZPOOL_COMPAT_LEGACY "legacy" +#define ZPOOL_COMPAT_OFF "off" + /* * vdev states are ordered from least to most healthy. * A vdev that's CANT_OPEN or below is considered unusable. diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h index 7f15fd030f..bc88cfa15e 100644 --- a/include/sys/spa_impl.h +++ b/include/sys/spa_impl.h @@ -424,6 +424,8 @@ struct spa { int spa_waiters; /* number of waiting threads */ boolean_t spa_waiters_cancel; /* waiters should return */ + char *spa_compatibility; /* compatibility file(s) */ + /* * spa_refcount & spa_config_lock must be the last elements * because zfs_refcount_t changes size based on compilation options. diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 911b6d00c4..6cd8fa9357 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -1,11 +1,7 @@ - - - - @@ -322,6 +318,7 @@ + @@ -424,94 +421,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + - + - + - + - + - + - + - + - - - + + + @@ -611,427 +559,487 @@ - - - - - + + + + + + + + + - - + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - + - + - + - + - + - + - + - + - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - - - - + + + + + + + + + + - + - + - + - + - + - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - + + + + + + + + + - + - + - + - + - + - + - + - + - - - - + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - + + + + + + + + + - - + + - + - + - + - + - + - + - + - + - - - + + @@ -1040,231 +1048,584 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - + + + + + - - - - + + + + - - - + + + - - - - + + + - - - - - + + - - - - + + - - - + + - - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - + + + - - - - + + - - - + + - - - - + + - - - + + + + + + + + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - - - + + + + + + - - - + + + - - - - - + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1279,48 +1640,230 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1328,690 +1871,863 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + + + + + + + + + + - + - + - + - + - + + - + - + - + - + - + - + - + - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2021,337 +2737,480 @@ - - - - - - - - - - - - + + + + + + + + + - - - + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + - + - + - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + - - - - - + + + - - - - - - - - + + + - - - - + + + + - - - + + + + + + - - - - - + + + - - - - + + + + - - - + + + + + - - - + + + + + + - - - + + + + + - - - - + + + + - - - - + + + + + - - - - - + + + + + + + - - - + + + + - - - + + - - - + + - - + + - - + + - - + + - - - + + - - - - + + - - - - + + - - - - + + - - - - - + + - - - + + - - - - + + - - - - - - + + - - - + + - - - - + + - - - - - + + - - - - - - + + - - - - - + + - - - - + + - - - - - + + - - - - - - - + + - - - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + @@ -2362,21 +3221,166 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2399,9 +3403,27 @@ - - - + + + + + + + + + + + + + + + + + + + + + @@ -2411,55 +3433,237 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + + + + + + + - - + + - + - + - + - + - - - + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2493,570 +3697,482 @@ - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + - - - - - - - - - - + + - - - - - - + + - - - - - - + + - - - - + + - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + @@ -3087,66 +4203,106 @@ - + + - - - + + + + - - - - + + + + - - - - + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - - - - - + + + + @@ -3177,36 +4333,54 @@ - - + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - - - + + @@ -3214,562 +4388,697 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + - - - - + + + + + - - - + + + + + + - - - - + + + + - + - - - - - + + + + + - - - - - - - - - - - + + + + - + - - - - - + + + + + - - - - + + + - + - - - - - + + + - - - - - + + + - - - + + + - - - + + - - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - - - + + + - - - - - + + + + + - - - - - + + + + + + - + - - - - + + + + + + + + + + + + + + + + + + + - + - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + + + + + - - + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + - - - - - - + - + - - + + - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - - - + + @@ -3807,130 +5116,125 @@ - - - + + + - - - + + + - - - - - - - - + + + + + + + + + + - - - + + + + - + - + - - - + + + - - + + - - + + - - - + + + - + - - + + - - - - - - - - - - - - - - - - - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3964,9 +5268,16 @@ - - - + + + + + + + + + + @@ -3979,294 +5290,304 @@ - + - - - - - + + + + + - - + + - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - + - - - + - + - + - + - + - - - + + - - + + - + - + - + - + - + - - + - + - - + + + + + + + - + - - + + + + + + + - + - - + + + + + + + - + - - + + + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + - - - - + + + + - - + + - - - - - + + + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + + + + + + + + + + + + + - - - + + + - - - + + - + - + - + - + - + - + - + - + - - - - - - - - - - + + + + + + + + + + + - + - - - + + + - - - - - + + + + + - - - - + + + + - - + + - - - + + + - - + + - - + + - - - - + + + + @@ -4281,599 +5602,647 @@ - - + + - - - - + + + + - - - + + + - - - - + + + + - - - - + + + + - - - - - - - - - - + + + + - - + + - - - - + + + + - - + + - - - - + + + + + + + + + + - + - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - - - + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - + + - + - + - - + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - + + + - - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - + + - + - + - + - + - + - + - + - - + - + - + - + - - + - + - - - + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + - - - + + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + - - - - + + + - - - + + + + - - - + + + + + + + - - - + + + + + + + + + + + + + + + - + + + + + + + - - - - - - - - + + - + - + - + - - - - - + + + + + + + + + + + + + + diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index af374fca36..1934466536 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -28,6 +28,7 @@ * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2018, loli10K + * Copyright (c) 2021, Colm Buckley */ #include @@ -44,8 +45,12 @@ #include #include #include +#include #include #include +#include +#include + #include "zfs_namecheck.h" #include "zfs_prop.h" #include "libzfs_impl.h" @@ -302,6 +307,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, case ZPOOL_PROP_ALTROOT: case ZPOOL_PROP_CACHEFILE: case ZPOOL_PROP_COMMENT: + case ZPOOL_PROP_COMPATIBILITY: if (zhp->zpool_props != NULL || zpool_get_all_props(zhp) == 0) { (void) strlcpy(buf, @@ -462,6 +468,8 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, char *slash, *check; struct stat64 statbuf; zpool_handle_t *zhp; + char badword[ZFS_MAXPROPLEN]; + char badfile[MAXPATHLEN]; if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { (void) no_memory(hdl); @@ -671,6 +679,39 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, *slash = '/'; break; + case ZPOOL_PROP_COMPATIBILITY: + switch (zpool_load_compat(strval, NULL, + badword, badfile)) { + case ZPOOL_COMPATIBILITY_OK: + break; + case ZPOOL_COMPATIBILITY_READERR: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "error reading feature file '%s'"), + badfile); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + case ZPOOL_COMPATIBILITY_BADFILE: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "feature file '%s' too large or not " + "newline-terminated"), + badfile); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + case ZPOOL_COMPATIBILITY_BADWORD: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "unknown feature '%s' in feature " + "file '%s'"), + badword, badfile); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + case ZPOOL_COMPATIBILITY_NOFILES: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "no feature files specified")); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + } + break; + case ZPOOL_PROP_COMMENT: for (check = strval; *check != '\0'; check++) { if (!isprint(*check)) { @@ -4663,3 +4704,190 @@ zpool_get_bootenv(zpool_handle_t *zhp, nvlist_t **nvlp) return (error); } + +/* + * Attempt to read and parse feature file(s) (from "compatibility" property). + * Files contain zpool feature names, comma or whitespace-separated. + * Comments (# character to next newline) are discarded. + * + * Arguments: + * compatibility : string containing feature filenames + * features : either NULL or pointer to array of boolean + * badtoken : either NULL or pointer to char[ZFS_MAXPROPLEN] + * badfile : either NULL or pointer to char[MAXPATHLEN] + * + * compatibility is NULL (unset), "", "off", "legacy", or list of + * comma-separated filenames. filenames should either be absolute, + * or relative to: + * 1) ZPOOL_SYSCONF_COMPAT_D (eg: /etc/zfs/compatibility.d) or + * 2) ZPOOL_DATA_COMPAT_D (eg: /usr/share/zfs/compatibility.d). + * (Unset), "" or "off" => enable all features + * "legacy" => disable all features + * Any feature names read from files which match unames in spa_feature_table + * will have the corresponding boolean set in the features array (if non-NULL). + * If more than one feature set specified, only features present in *all* of + * them will be set. + * + * An unreadable filename will be strlcpy'd to badfile (if non-NULL). + * An unrecognized feature will be strlcpy'd to badtoken (if non-NULL). + * + * Return values: + * ZPOOL_COMPATIBILITY_OK : files read and parsed ok + * ZPOOL_COMPATIBILITY_READERR : file could not be opened / mmap'd + * ZPOOL_COMPATIBILITY_BADFILE : file too big or not a text file + * ZPOOL_COMPATIBILITY_BADWORD : file contains invalid feature name + * ZPOOL_COMPATIBILITY_NOFILES : no file names found + */ +zpool_compat_status_t +zpool_load_compat(const char *compatibility, + boolean_t *features, char *badtoken, char *badfile) +{ + int sdirfd, ddirfd, featfd; + int i; + struct stat fs; + char *fc; /* mmap of file */ + char *ps, *ls, *ws; /* strtok state */ + char *file, *line, *word; + char filenames[ZFS_MAXPROPLEN]; + int filecount = 0; + + /* special cases (unset), "" and "off" => enable all features */ + if (compatibility == NULL || compatibility[0] == '\0' || + strcmp(compatibility, ZPOOL_COMPAT_OFF) == 0) { + if (features != NULL) + for (i = 0; i < SPA_FEATURES; i++) + features[i] = B_TRUE; + return (ZPOOL_COMPATIBILITY_OK); + } + + /* Final special case "legacy" => disable all features */ + if (strcmp(compatibility, ZPOOL_COMPAT_LEGACY) == 0) { + if (features != NULL) + for (i = 0; i < SPA_FEATURES; i++) + features[i] = B_FALSE; + return (ZPOOL_COMPATIBILITY_OK); + } + + /* + * Start with all true; will be ANDed with results from each file + */ + if (features != NULL) + for (i = 0; i < SPA_FEATURES; i++) + features[i] = B_TRUE; + + /* + * We ignore errors from the directory open() + * as they're only needed if the filename is relative + * which will be checked during the openat(). + */ +#ifdef O_PATH + sdirfd = open(ZPOOL_SYSCONF_COMPAT_D, O_DIRECTORY | O_PATH); + ddirfd = open(ZPOOL_DATA_COMPAT_D, O_DIRECTORY | O_PATH); +#else + sdirfd = open(ZPOOL_SYSCONF_COMPAT_D, O_DIRECTORY | O_RDONLY); + ddirfd = open(ZPOOL_DATA_COMPAT_D, O_DIRECTORY | O_RDONLY); +#endif + + (void) strlcpy(filenames, compatibility, ZFS_MAXPROPLEN); + file = strtok_r(filenames, ",", &ps); + while (file != NULL) { + boolean_t features_local[SPA_FEATURES]; + + /* try sysconfdir first, then datadir */ + if ((featfd = openat(sdirfd, file, 0, O_RDONLY)) < 0) + featfd = openat(ddirfd, file, 0, O_RDONLY); + + if (featfd < 0 || fstat(featfd, &fs) < 0) { + (void) close(featfd); + (void) close(sdirfd); + (void) close(ddirfd); + if (badfile != NULL) + (void) strlcpy(badfile, file, MAXPATHLEN); + return (ZPOOL_COMPATIBILITY_READERR); + } + + /* Too big or too small */ + if (fs.st_size < 1 || fs.st_size > ZPOOL_COMPAT_MAXSIZE) { + (void) close(featfd); + (void) close(sdirfd); + (void) close(ddirfd); + if (badfile != NULL) + (void) strlcpy(badfile, file, MAXPATHLEN); + return (ZPOOL_COMPATIBILITY_BADFILE); + } + + /* private mmap() so we can strtok safely */ + fc = (char *)mmap(NULL, fs.st_size, + PROT_READ|PROT_WRITE, MAP_PRIVATE, featfd, 0); + (void) close(featfd); + + if (fc < 0) { + (void) close(sdirfd); + (void) close(ddirfd); + if (badfile != NULL) + (void) strlcpy(badfile, file, MAXPATHLEN); + return (ZPOOL_COMPATIBILITY_READERR); + } + + /* Text file sanity check - last char should be newline */ + if (fc[fs.st_size - 1] != '\n') { + (void) munmap((void *) fc, fs.st_size); + (void) close(sdirfd); + (void) close(ddirfd); + if (badfile != NULL) + (void) strlcpy(badfile, file, MAXPATHLEN); + return (ZPOOL_COMPATIBILITY_BADFILE); + } + + /* replace with NUL to ensure we have a delimiter */ + fc[fs.st_size - 1] = '\0'; + + for (i = 0; i < SPA_FEATURES; i++) + features_local[i] = B_FALSE; + + line = strtok_r(fc, "\n", &ls); + while (line != NULL) { + /* discard comments */ + *(strchrnul(line, '#')) = '\0'; + + word = strtok_r(line, ", \t", &ws); + while (word != NULL) { + /* Find matching feature name */ + for (i = 0; i < SPA_FEATURES; i++) { + zfeature_info_t *fi = + &spa_feature_table[i]; + if (strcmp(word, fi->fi_uname) == 0) { + features_local[i] = B_TRUE; + break; + } + } + if (i == SPA_FEATURES) { + if (badtoken != NULL) + (void) strlcpy(badtoken, word, + ZFS_MAXPROPLEN); + if (badfile != NULL) + (void) strlcpy(badfile, file, + MAXPATHLEN); + (void) munmap((void *) fc, fs.st_size); + (void) close(sdirfd); + (void) close(ddirfd); + return (ZPOOL_COMPATIBILITY_BADWORD); + } + word = strtok_r(NULL, ", \t", &ws); + } + line = strtok_r(NULL, "\n", &ls); + } + (void) munmap((void *) fc, fs.st_size); + if (features != NULL) { + for (i = 0; i < SPA_FEATURES; i++) + features[i] &= features_local[i]; + } + filecount++; + file = strtok_r(NULL, ",", &ps); + } + (void) close(sdirfd); + (void) close(ddirfd); + if (filecount == 0) + return (ZPOOL_COMPATIBILITY_NOFILES); + return (ZPOOL_COMPATIBILITY_OK); +} diff --git a/lib/libzfs/libzfs_status.c b/lib/libzfs/libzfs_status.c index 4359370416..fadae9388a 100644 --- a/lib/libzfs/libzfs_status.c +++ b/lib/libzfs/libzfs_status.c @@ -23,6 +23,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. + * Copyright (c) 2021, Colm Buckley */ /* @@ -87,6 +88,7 @@ static char *zfs_msgid_table[] = { * ZPOOL_STATUS_REMOVED_DEV * ZPOOL_STATUS_REBUILDING * ZPOOL_STATUS_REBUILD_SCRUB + * ZPOOL_STATUS_COMPATIBILITY_ERR * ZPOOL_STATUS_OK */ }; @@ -218,7 +220,8 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t), * only picks the most damaging of all the current errors to report. */ static zpool_status_t -check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) +check_status(nvlist_t *config, boolean_t isimport, + zpool_errata_t *erratap, const char *compat) { nvlist_t *nvroot; vdev_stat_t *vs; @@ -471,9 +474,16 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) ZPOOL_CONFIG_FEATURE_STATS); } + /* check against all features, or limited set? */ + boolean_t pool_features[SPA_FEATURES]; + + if (zpool_load_compat(compat, pool_features, NULL, NULL) != + ZPOOL_COMPATIBILITY_OK) + return (ZPOOL_STATUS_COMPATIBILITY_ERR); for (i = 0; i < SPA_FEATURES; i++) { zfeature_info_t *fi = &spa_feature_table[i]; - if (!nvlist_exists(feat, fi->fi_guid)) + if (pool_features[i] && + !nvlist_exists(feat, fi->fi_guid)) return (ZPOOL_STATUS_FEAT_DISABLED); } } @@ -484,7 +494,18 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) zpool_status_t zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata) { - zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata); + /* + * pass in the desired feature set, as + * it affects check for disabled features + */ + char compatibility[ZFS_MAXPROPLEN]; + if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compatibility, + ZFS_MAXPROPLEN, NULL, B_FALSE) != 0) + compatibility[0] = '\0'; + + zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata, + compatibility); + if (msgid != NULL) { if (ret >= NMSGID) *msgid = NULL; @@ -497,7 +518,7 @@ zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata) zpool_status_t zpool_import_status(nvlist_t *config, char **msgid, zpool_errata_t *errata) { - zpool_status_t ret = check_status(config, B_TRUE, errata); + zpool_status_t ret = check_status(config, B_TRUE, errata, NULL); if (ret >= NMSGID) *msgid = NULL; diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index 823f093f40..b9e08eac6a 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -24,6 +24,7 @@ * Copyright (c) 2012, 2018 by Delphix. All rights reserved. * Copyright 2015 RackTop Systems. * Copyright (c) 2016, Intel Corporation. + * Copyright (c) 2021, Colm Buckley */ /* @@ -552,12 +553,14 @@ get_configs(libpc_handle_t *hdl, pool_list_t *pl, boolean_t active_ok, * pool guid * name * comment (if available) + * compatibility features (if available) * pool state * hostid (if available) * hostname (if available) */ uint64_t state, version; char *comment = NULL; + char *compatibility = NULL; version = fnvlist_lookup_uint64(tmp, ZPOOL_CONFIG_VERSION); @@ -577,6 +580,13 @@ get_configs(libpc_handle_t *hdl, pool_list_t *pl, boolean_t active_ok, fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT, comment); + if (nvlist_lookup_string(tmp, + ZPOOL_CONFIG_COMPATIBILITY, + &compatibility) == 0) + fnvlist_add_string(config, + ZPOOL_CONFIG_COMPATIBILITY, + compatibility); + state = fnvlist_lookup_uint64(tmp, ZPOOL_CONFIG_POOL_STATE); fnvlist_add_uint64(config, diff --git a/man/man5/zpool-features.5 b/man/man5/zpool-features.5 index 2e5ab4c376..c56b31e2d7 100644 --- a/man/man5/zpool-features.5 +++ b/man/man5/zpool-features.5 @@ -16,6 +16,7 @@ .\" Portions Copyright [yyyy] [name of copyright owner] .\" Copyright (c) 2019, Klara Inc. .\" Copyright (c) 2019, Allan Jude +.\" Copyright (c) 2021, Colm Buckley .TH ZPOOL-FEATURES 5 "Aug 24, 2020" OpenZFS .SH NAME zpool\-features \- ZFS pool feature descriptions @@ -26,7 +27,8 @@ 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 \fBupgrade\fR subcommand of the zpool(8) command, or set the \fBfeature@\fR\fIfeature_name\fR property -to \fBenabled\fR. +to \fBenabled\fR. Please also see the \fB"Compatibility feature sets"\fR +section for information on how sets of features may be enabled together. .sp .LP The pool format does not affect file system version compatibility or the ability @@ -140,6 +142,61 @@ read\-only mode. Some features depend on other features being enabled in order to function properly. Enabling a feature will automatically enable any features it depends on. + +.SS "Compatibility feature sets" +.sp +.LP +It is sometimes necessary for a pool to maintain compatibility with a +specific on\-disk format, by enabling and disabling particular features. The +\fBcompatibility\fR feature facilitates this by allowing feature sets to +be read from text files. When set to \fBoff\fR (the default); compatibility +feature sets are disabled (ie: all features are enabled); when set to +\fBlegacy\fR; no features are enabled. When set to a comma\-separated list +of filenames (each filename may either be an absolute path, or relative to +\fB/etc/zfs/compatibility.d\fR or \fB/usr/share/zfs/compatibility.d\fR) +the lists of requested features are read from those files, separated by +whitespace and/or commas. Only features present in all files are enabled. +.LP +Simple sanity checks are applied to the files; they must be between 1 and +16,384 bytes in size, and must end with a newline character. +.LP +The requested features are applied when a pool is created using +\fBzpool create \-o compatibility=...\fR and controls which features are +enabled when using \fBzpool upgrade\fR. \fBzpool status\fR +will not show a warning about disabled features which are not part +of the requested feature set. +.LP +By convention, compatibility files in \fB/usr/share/zfs/compatibility.d\fR +are provided by the distribution package, and include feature sets +supported by important versions of popular distribtions, and feature +sets commonly supported at the start of each year. Compatibility files +in \fB/etc/zfs/compatibility.d\fR, if present, will take precedence over +files with the same name in \fB/usr/share/zfs/compatibility.d\fR. +.LP +Compatibility files may include comments; any text from \fB#\fR to the end +of the line is ignored. +.LP +\fBExample:\fR +.EX +# \fBcat /usr/share/zfs/compatibility.d/grub2\fR +# Features which are supported by GRUB2 +async_destroy +bookmarks +embedded_data +empty_bpobj +enabled_txg +extensible_dataset +filesystem_limits +hole_birth +large_blocks +lz4_compress +spacemap_histogram + +# \fBzpool create \-o compatibility=grub2 bootpool vdev\fR +.EE +.LP +See \fBzpool\-create(8)\fR and \fBzpool\-upgrade(8)\fR for more information +on how these commands are affected by feature sets. .SH FEATURES .sp .LP diff --git a/man/man8/zpool-create.8 b/man/man8/zpool-create.8 index 7406a493e3..fe35ab8db3 100644 --- a/man/man8/zpool-create.8 +++ b/man/man8/zpool-create.8 @@ -26,6 +26,7 @@ .\" Copyright (c) 2018 George Melikov. All Rights Reserved. .\" Copyright 2017 Nexenta Systems, Inc. .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +.\" Copyright (c) 2021, Colm Buckley .\" .Dd August 9, 2019 .Dt ZPOOL-CREATE 8 @@ -40,6 +41,7 @@ .Op Fl m Ar mountpoint .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... .Oo Fl o Ar feature@feature Ns = Ns Ar value Oc +.Op Fl o Ar compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... .Oo Fl O Ar file-system-property Ns = Ns Ar value Oc Ns ... .Op Fl R Ar root .Ar pool vdev Ns ... @@ -52,6 +54,7 @@ .Op Fl m Ar mountpoint .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... .Oo Fl o Ar feature@feature Ns = Ns Ar value Oc Ns ... +.Op Fl o Ar compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... .Oo Fl O Ar file-system-property Ns = Ns Ar value Oc Ns ... .Op Fl R Ar root .Op Fl t Ar tname @@ -135,9 +138,14 @@ This can be overridden with the .Fl m option. .Pp -By default all supported features are enabled on the new pool unless the +By default all supported features are enabled on the new pool. The .Fl d -option is specified. +option or the +.Fl o Ar compatibility +property (eg: +.Fl o Ar compatibility=2020 +) can be used to restrict the features that are enabled, so that the +pool can be imported on other releases of the ZFS software. .Bl -tag -width Ds .It Fl d Do not enable any features on the new pool. @@ -179,6 +187,10 @@ Sets the given pool properties. See the .Xr zpoolprops manual page for a list of valid properties that can be set. +.It Fl o Ar compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... +Specifies compatibility feature sets. See +.Xr zpool-features 5 +for more information about compatibility feature sets. .It Fl o Ar feature@feature Ns = Ns Ar value Sets the given pool feature. See the .Xr zpool-features 5 diff --git a/man/man8/zpool-upgrade.8 b/man/man8/zpool-upgrade.8 index b9d023b22d..face5b138f 100644 --- a/man/man8/zpool-upgrade.8 +++ b/man/man8/zpool-upgrade.8 @@ -26,6 +26,7 @@ .\" Copyright (c) 2018 George Melikov. All Rights Reserved. .\" Copyright 2017 Nexenta Systems, Inc. .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +.\" Copyright (c) 2021, Colm Buckley .\" .Dd August 9, 2019 .Dt ZPOOL-UPGRADE 8 @@ -54,7 +55,11 @@ formatted using a legacy ZFS version number. These pools can continue to be used, but some features may not be available. Use .Nm zpool Cm upgrade Fl a -to enable all features on all pools. +to enable all features on all pools. (If a pool has specified compatibility +feature sets using the +.Fl o Ar compatibility +property, only the features present in all requested compatibility sets will +be enabled on that pool.) .It Xo .Nm zpool .Cm upgrade @@ -70,7 +75,11 @@ for a description of feature flags features supported by the current software. .Op Fl V Ar version .Fl a Ns | Ns Ar pool Ns ... .Xc -Enables all supported features on the given pool. +Enables all supported features on the given pool. (If the pool has specified +compatibility feature sets using the +.Fl o Ar compatibility +property, only the features present in all requested compatibility sets will be +enabled.) Once this is done, the pool will no longer be accessible on systems that do not support feature flags. See @@ -79,7 +88,8 @@ for details on compatibility with systems that support feature flags, but do not support all features enabled on the pool. .Bl -tag -width Ds .It Fl a -Enables all supported features on all pools. +Enables all supported features (from specified compatibility sets, if any) on all +pools. .It Fl V Ar version Upgrade to the specified legacy version. If the diff --git a/man/man8/zpoolprops.8 b/man/man8/zpoolprops.8 index f78acaa465..20e0d74421 100644 --- a/man/man8/zpoolprops.8 +++ b/man/man8/zpoolprops.8 @@ -26,6 +26,7 @@ .\" Copyright (c) 2018 George Melikov. All Rights Reserved. .\" Copyright 2017 Nexenta Systems, Inc. .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +.\" Copyright (c) 2021, Colm Buckley .\" .Dd August 9, 2019 .Dt ZPOOLPROPS 8 @@ -285,6 +286,24 @@ A text string consisting of printable ASCII characters that will be stored such that it is available even if the pool becomes faulted. An administrator can provide additional information about a pool using this property. +.It Sy compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... +Specifies that the pool maintain compatibility with specific feature sets. +When set to +.Sy off +(or unset); compatibility is disabled (all features are enabled); when set to +.Sy legacy Ns ; +no features are enabled. When set to a comma-separated list of +filenames (each filename may either be an absolute path, or relative to +.Pa /etc/zfs/compatibility.d or Pa /usr/share/zfs/compatibility.d Ns ) +the lists of requested features are read from those files, separated by +whitespace and/or commas. Only features present in all files are enabled. + +See +.Xr zpool-features 5 Ns , +.Xr zpool-create 8 +and +.Xr zpool-upgrade 8 +for more information on the operation of compatibility feature sets. .It Sy dedupditto Ns = Ns Ar number This property is deprecated and no longer has any effect. .It Sy delegation Ns = Ns Sy on Ns | Ns Sy off diff --git a/module/zcommon/zpool_prop.c b/module/zcommon/zpool_prop.c index 815fad6df0..6299d371f2 100644 --- a/module/zcommon/zpool_prop.c +++ b/module/zcommon/zpool_prop.c @@ -22,6 +22,7 @@ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2021, Colm Buckley */ #include @@ -71,6 +72,9 @@ zpool_prop_init(void) PROP_DEFAULT, ZFS_TYPE_POOL, " | none", "CACHEFILE"); zprop_register_string(ZPOOL_PROP_COMMENT, "comment", NULL, PROP_DEFAULT, ZFS_TYPE_POOL, "", "COMMENT"); + zprop_register_string(ZPOOL_PROP_COMPATIBILITY, "compatibility", + "off", PROP_DEFAULT, ZFS_TYPE_POOL, + " | off | legacy", "COMPATIBILITY"); /* readonly number properties */ zprop_register_number(ZPOOL_PROP_SIZE, "size", 0, PROP_READONLY, diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 56354a107e..5170c9ca22 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -32,6 +32,7 @@ * Copyright (c) 2017, 2019, Datto Inc. All rights reserved. * Copyright 2017 Joyent, Inc. * Copyright (c) 2017, Intel Corporation. + * Copyright (c) 2021, Colm Buckley */ /* @@ -377,6 +378,11 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp) 0, ZPROP_SRC_LOCAL); } + if (spa->spa_compatibility != NULL) { + spa_prop_add_list(*nvp, ZPOOL_PROP_COMPATIBILITY, + spa->spa_compatibility, 0, ZPROP_SRC_LOCAL); + } + if (spa->spa_root != NULL) spa_prop_add_list(*nvp, ZPOOL_PROP_ALTROOT, spa->spa_root, 0, ZPROP_SRC_LOCAL); @@ -1669,6 +1675,10 @@ spa_unload(spa_t *spa) spa_strfree(spa->spa_comment); spa->spa_comment = NULL; } + if (spa->spa_compatibility != NULL) { + spa_strfree(spa->spa_compatibility); + spa->spa_compatibility = NULL; + } spa_config_exit(spa, SCL_ALL, spa); } @@ -3249,6 +3259,7 @@ spa_ld_parse_config(spa_t *spa, spa_import_type_t type) vdev_t *rvd; uint64_t pool_guid; char *comment; + char *compatibility; /* * Versioning wasn't explicitly added to the label until later, so if @@ -3297,6 +3308,11 @@ spa_ld_parse_config(spa_t *spa, spa_import_type_t type) if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) spa->spa_comment = spa_strdup(comment); + ASSERT(spa->spa_compatibility == NULL); + if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMPATIBILITY, + &compatibility) == 0) + spa->spa_compatibility = spa_strdup(compatibility); + (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, &spa->spa_config_txg); @@ -8668,6 +8684,20 @@ spa_sync_props(void *arg, dmu_tx_t *tx) spa_history_log_internal(spa, "set", tx, "%s=%s", nvpair_name(elem), strval); break; + case ZPOOL_PROP_COMPATIBILITY: + strval = fnvpair_value_string(elem); + if (spa->spa_compatibility != NULL) + spa_strfree(spa->spa_compatibility); + spa->spa_compatibility = spa_strdup(strval); + /* + * Dirty the configuration on vdevs as above. + */ + if (tx->tx_txg != TXG_INITIAL) + vdev_config_dirty(spa->spa_root_vdev); + spa_history_log_internal(spa, "set", tx, + "%s=%s", nvpair_name(elem), strval); + break; + default: /* * Set pool property values in the poolprops mos object. diff --git a/module/zfs/spa_config.c b/module/zfs/spa_config.c index dacba127dc..4a31443132 100644 --- a/module/zfs/spa_config.c +++ b/module/zfs/spa_config.c @@ -24,6 +24,7 @@ * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2011, 2020 by Delphix. All rights reserved. * Copyright 2017 Joyent, Inc. + * Copyright (c) 2021, Colm Buckley */ #include @@ -446,6 +447,9 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats) if (spa->spa_comment != NULL) fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT, spa->spa_comment); + if (spa->spa_compatibility != NULL) + fnvlist_add_string(config, ZPOOL_CONFIG_COMPATIBILITY, + spa->spa_compatibility); hostid = spa_get_hostid(spa); if (hostid != 0) diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in index f1f09f6358..f46a633db6 100644 --- a/rpm/generic/zfs.spec.in +++ b/rpm/generic/zfs.spec.in @@ -457,6 +457,7 @@ systemctl --system daemon-reload >/dev/null || true %{_udevdir}/vdev_id %{_udevdir}/zvol_id %{_udevdir}/rules.d/* +%{_datadir}/%{name}/compatibility.d %if ! 0%{?_systemd} || 0%{?_initramfs} # Files needed for sysvinit and initramfs-tools %{_sysconfdir}/%{name}/zfs-functions @@ -503,7 +504,10 @@ systemctl --system daemon-reload >/dev/null || true %doc AUTHORS COPYRIGHT LICENSE NOTICE README.md %files test -%{_datadir}/%{name} +%{_datadir}/%{name}/zfs-tests +%{_datadir}/%{name}/test-runner +%{_datadir}/%{name}/runfiles +%{_datadir}/%{name}/*.sh %files dracut %doc contrib/dracut/README.dracut.markdown diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 2deece7f41..f59826fe6b 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -34,6 +34,7 @@ export ZEDLET_ETC_DIR=$$CMD_DIR/zed/zed.d export ZEDLET_LIBEXEC_DIR=$$CMD_DIR/zed/zed.d export ZPOOL_SCRIPT_DIR=$$CMD_DIR/zpool/zpool.d export ZPOOL_SCRIPTS_PATH=$$CMD_DIR/zpool/zpool.d +export ZPOOL_COMPAT_DIR=$$CMD_DIR/zpool/compatibility.d export CONTRIB_DIR=@abs_top_builddir@/contrib export LIB_DIR=@abs_top_builddir@/lib export SYSCONF_DIR=@abs_top_builddir@/etc diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 11960629e3..9468ee06de 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -344,7 +344,8 @@ tests = ['zpool_create_001_pos', 'zpool_create_002_pos', 'zpool_create_draid_003_pos', 'zpool_create_draid_004_pos', 'zpool_create_features_001_pos', 'zpool_create_features_002_pos', 'zpool_create_features_003_pos', 'zpool_create_features_004_neg', - 'zpool_create_features_005_pos', + 'zpool_create_features_005_pos', 'zpool_create_features_006_pos', + 'zpool_create_features_007_pos', 'zpool_create_features_008_pos', 'create-o_ashift', 'zpool_create_tempname', 'zpool_create_dryrun_output'] tags = ['functional', 'cli_root', 'zpool_create'] @@ -468,7 +469,8 @@ tests = ['zpool_split_cliargs', 'zpool_split_devices', tags = ['functional', 'cli_root', 'zpool_split'] [tests/functional/cli_root/zpool_status] -tests = ['zpool_status_001_pos', 'zpool_status_002_pos'] +tests = ['zpool_status_001_pos', 'zpool_status_002_pos', + 'zpool_status_features_001_pos'] tags = ['functional', 'cli_root', 'zpool_status'] [tests/functional/cli_root/zpool_sync] @@ -491,7 +493,7 @@ tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_002_pos', 'zpool_upgrade_003_pos', 'zpool_upgrade_004_pos', 'zpool_upgrade_005_neg', 'zpool_upgrade_006_neg', 'zpool_upgrade_007_pos', 'zpool_upgrade_008_pos', - 'zpool_upgrade_009_neg'] + 'zpool_upgrade_009_neg', 'zpool_upgrade_features_001_pos'] tags = ['functional', 'cli_root', 'zpool_upgrade'] [tests/functional/cli_root/zpool_wait] diff --git a/tests/zfs-tests/include/default.cfg.in b/tests/zfs-tests/include/default.cfg.in index 8ec0b96e25..1a9cc5a2bb 100644 --- a/tests/zfs-tests/include/default.cfg.in +++ b/tests/zfs-tests/include/default.cfg.in @@ -37,6 +37,7 @@ export ZEDLET_ETC_DIR=${ZEDLET_ETC_DIR:-@sysconfdir@/zfs/zed.d} export ZEDLET_LIBEXEC_DIR=${ZEDLET_LIBEXEC_DIR:-@zfsexecdir@/zed.d} export ZPOOL_SCRIPT_DIR=${ZPOOL_SCRIPT_DIR:-@sysconfdir@/zfs/zpool.d} +export ZPOOL_COMPAT_DIR=${ZPOOL_COMPAT_DIR:-@datadir@/zfs/compatibility.d} # Define run length constants export RT_LONG="3" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am index ea0cc49b09..5e9e83f0db 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am @@ -36,6 +36,9 @@ dist_pkgdata_SCRIPTS = \ zpool_create_features_003_pos.ksh \ zpool_create_features_004_neg.ksh \ zpool_create_features_005_pos.ksh \ + zpool_create_features_006_pos.ksh \ + zpool_create_features_007_pos.ksh \ + zpool_create_features_008_pos.ksh \ create-o_ashift.ksh \ zpool_create_tempname.ksh \ zpool_create_dryrun_output.ksh diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib index 325f0b0360..c98e495187 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib @@ -107,3 +107,84 @@ function save_dump_dev fi echo $dumpdev } + +# +# Verify a pools enabled features match the provided feature set. +# $1, pool name +# $2, feature set(s) +# +# check_feature_set $TESTPOOL set1 set2 set3 ... +# +function check_feature_set +{ + typeset pool=$1 + typeset feature_set=$2 + shift + + for set in "$@"; do + if test -e "$ZPOOL_COMPAT_DIR/$set"; then + file="$ZPOOL_COMPAT_DIR/$set" + else + log_fail "Missing feature file: $ZPOOL_COMPAT_DIR/$set" + fi + done + + # + # Create a temporary file which contains all features which are + # common to the listed feature sets. This is used for comparison + # below to determine which features should be enabled. + # + typeset tmpfile=$(mktemp) + + while read line; do + typeset flag=1 + + if [[ "$line" == "#*" ]]; then + continue + fi + + for set in "$@"; do + if ! grep -q "$line" $ZPOOL_COMPAT_DIR/$set; then + flag=0 + break; + fi + done + + if [[ $flag -eq 1 ]]; then + echo "$line" >>$tmpfile + fi + done <"$file" + + # + # Verify every enabled feature appears in the merged feature set. + # Verify every disabled feature does not. + # + for feature in $(zpool get all $pool | \ + awk '$2 ~ /feature@/ { print $2 }'); do + state=$(get_pool_prop $feature $pool) + name=$(cut -d'@' -f2 <<<"$feature") + + if [[ "$state" = "enabled" || "$state" = "active" ]]; then + if ! grep -q $name $tmpfile; then + cat $tmpfile + rm -f $tmpfile + log_fail "Enabled feature $name not " \ + "in feature set file" + fi + elif [[ "$state" = "disabled" ]]; then + if grep -q $name $tmpfile; then + cat $tmpfile + rm -f $tmpfile + log_fail "Disabled feature $name is " \ + "in feature set file" + fi + else + rm -f $tmpfile + log_fail "Feature $name in unknown state $state" + fi + done + + log_note "Checked all features" + + rm -f $tmpfile +} diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_006_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_006_pos.ksh new file mode 100755 index 0000000000..fe98434d1b --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_006_pos.ksh @@ -0,0 +1,58 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2021 Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Verify '-o compatibility' reserved values 'off, legacy' +# +# STRATEGY: +# 1. Create a pool with '-o compatibility=off' +# 2. Create a pool with '-o compatibility=legacy' +# 3. Cannot create a pool with '-o compatibility=unknown' +# + +verify_runnable "global" + +function cleanup +{ + datasetexists $TESTPOOL && log_must zpool destroy $TESTPOOL +} + +log_onexit cleanup + +log_assert "verify '-o compatibility' reserved values 'off, legacy'" + +log_must zpool create -f -o compatibility=off $TESTPOOL $DISKS +log_must zpool destroy -f $TESTPOOL + +log_must zpool create -f -o compatibility=legacy $TESTPOOL $DISKS +log_must zpool destroy -f $TESTPOOL + +log_mustnot zpool create -f -o compatibility=unknown $TESTPOOL $DISKS + +log_pass "verify '-o compatibility' reserved values 'off, legacy'" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_007_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_007_pos.ksh new file mode 100755 index 0000000000..8c812911b3 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_007_pos.ksh @@ -0,0 +1,54 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2021 Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib + +# +# DESCRIPTION: +# Verify pools can be created with the expected feature set enabled. +# +# STRATEGY: +# 1. Create a pool with a known feature set. +# 2. Verify only those features are active/enabled. +# + +verify_runnable "global" + +function cleanup +{ + datasetexists $TESTPOOL && log_must zpool destroy $TESTPOOL +} + +log_onexit cleanup + +log_assert "creates a pool with a specified feature set enabled" + +log_must zpool create -f -o compatibility=compat-2020 $TESTPOOL $DISKS +check_feature_set $TESTPOOL compat-2020 +log_must zpool destroy -f $TESTPOOL + +log_pass "creates a pool with a specified feature set enabled" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_008_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_008_pos.ksh new file mode 100755 index 0000000000..0580d444e7 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_008_pos.ksh @@ -0,0 +1,54 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2021 Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib + +# +# DESCRIPTION: +# Verify pools can be created with multiple feature sets. +# +# STRATEGY: +# 1. Create a pool with multiple feature sets. +# 2. Verify only the features common to both sets are enabled. +# + +verify_runnable "global" + +function cleanup +{ + datasetexists $TESTPOOL && log_must zpool destroy $TESTPOOL +} + +log_onexit cleanup + +log_assert "creates a pool with multiple feature sets enabled" + +log_must zpool create -f -o compatibility=freebsd-11.0,zol-0.8 $TESTPOOL $DISKS +check_feature_set $TESTPOOL freebsd-11.0 zol-0.8 +log_must zpool destroy -f $TESTPOOL + +log_pass "creates a pool with multiple feature sets enabled" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg index 3c536ca12e..6075e1f1ab 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg @@ -57,6 +57,7 @@ typeset -a properties=( "leaked" "multihost" "autotrim" + "compatibility" "feature@async_destroy" "feature@empty_bpobj" "feature@lz4_compress" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am index beb59e3d06..5553061c67 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am @@ -3,4 +3,5 @@ dist_pkgdata_SCRIPTS = \ setup.ksh \ cleanup.ksh \ zpool_status_001_pos.ksh \ - zpool_status_002_pos.ksh + zpool_status_002_pos.ksh \ + zpool_status_features_001_pos.ksh diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_features_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_features_001_pos.ksh new file mode 100755 index 0000000000..635125fc0d --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_features_001_pos.ksh @@ -0,0 +1,63 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2021 Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib + +# +# DESCRIPTION: +# Verify zpool status only recommends upgrading the pool when +# the enabled features don't match those in the feature set. +# +# STRATEGY: +# 1. Create a pool with a known feature set. +# 2. Verify there is no `zpool status` notice to upgrade the pool. +# 3. Set the pool compatibility to a newer feature set. +# 4. Verify there is a `zpool status` notice to upgrade the pool. +# + +verify_runnable "global" + +function cleanup +{ + datasetexists $TESTPOOL1 && log_must zpool destroy $TESTPOOL1 + rm -f $FILEDEV +} + +FILEDEV="$TEST_BASE_DIR/filedev.$$" + +log_onexit cleanup + +log_assert "check 'zpool status' upgrade notice" + +log_must truncate -s $MINVDEVSIZE $FILEDEV +log_must zpool create -f -o compatibility=compat-2018 $TESTPOOL1 $FILEDEV +log_mustnot check_pool_status $TESTPOOL1 "status" "features are not enabled" + +log_must zpool set compatibility=compat-2020 $TESTPOOL1 +log_must check_pool_status $TESTPOOL1 "status" "features are not enabled" + +log_pass "check 'zpool status' upgrade notice" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile.am index 18311ed2ca..c7f321a2f6 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile.am @@ -12,7 +12,8 @@ dist_pkgdata_SCRIPTS = \ zpool_upgrade_006_neg.ksh \ zpool_upgrade_007_pos.ksh \ zpool_upgrade_008_pos.ksh \ - zpool_upgrade_009_neg.ksh + zpool_upgrade_009_neg.ksh \ + zpool_upgrade_features_001_pos.ksh dist_pkgdata_DATA = \ zpool_upgrade.cfg \ diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_features_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_features_001_pos.ksh new file mode 100755 index 0000000000..5170d31b46 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_features_001_pos.ksh @@ -0,0 +1,67 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2021 Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib + +# +# DESCRIPTION: +# Verify pools can be upgraded to known feature sets. +# +# STRATEGY: +# 1. Create a pool with a known feature set. +# 2. Verify only those features are active/enabled. +# 3. Upgrade the pool to a newer feature set. +# 4. Verify only those features are active/enabled. +# + +verify_runnable "global" + +function cleanup +{ + datasetexists $TESTPOOL1 && log_must zpool destroy $TESTPOOL1 + rm -f $FILEDEV +} + +FILEDEV="$TEST_BASE_DIR/filedev.$$" + +log_onexit cleanup + +log_assert "verify pools can be upgraded to known feature sets." + +log_must truncate -s $MINVDEVSIZE $FILEDEV +log_must zpool create -f -o compatibility=compat-2018 $TESTPOOL1 $FILEDEV +check_feature_set $TESTPOOL1 compat-2018 +log_mustnot check_pool_status $TESTPOOL1 "status" "features are not enabled" + +log_must zpool set compatibility=compat-2020 $TESTPOOL1 +log_must check_pool_status $TESTPOOL1 "status" "features are not enabled" + +log_must zpool upgrade $TESTPOOL1 +check_feature_set $TESTPOOL1 compat-2020 +log_mustnot check_pool_status $TESTPOOL1 "status" "features are not enabled" + +log_pass "verify pools can be upgraded to known feature sets."