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 <mahrens@delphix.com> Reviewed-by: Richard Laager <rlaager@wiktel.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Colm Buckley <colm@tuatha.org> Closes #11468
This commit is contained in:
parent
35ec51796f
commit
658fb8020f
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -31,6 +31,7 @@
|
|||
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2017, Intel Corporation.
|
||||
* Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>
|
||||
* Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
#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__
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
/* 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.
|
||||
|
|
|
@ -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.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,6 +28,7 @@
|
|||
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2017, Intel Corporation.
|
||||
* Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>
|
||||
* Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -44,8 +45,12 @@
|
|||
#include <sys/zfs_ioctl.h>
|
||||
#include <sys/zfs_sysfs.h>
|
||||
#include <sys/vdev_disk.h>
|
||||
#include <sys/types.h>
|
||||
#include <dlfcn.h>
|
||||
#include <libzutil.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -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,
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
.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
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
.\"
|
||||
.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
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
.\"
|
||||
.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
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
.\"
|
||||
.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
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
#include <sys/zio.h>
|
||||
|
@ -71,6 +72,9 @@ zpool_prop_init(void)
|
|||
PROP_DEFAULT, ZFS_TYPE_POOL, "<file> | none", "CACHEFILE");
|
||||
zprop_register_string(ZPOOL_PROP_COMMENT, "comment", NULL,
|
||||
PROP_DEFAULT, ZFS_TYPE_POOL, "<comment-string>", "COMMENT");
|
||||
zprop_register_string(ZPOOL_PROP_COMPATIBILITY, "compatibility",
|
||||
"off", PROP_DEFAULT, ZFS_TYPE_POOL,
|
||||
"<file[,file...]> | off | legacy", "COMPATIBILITY");
|
||||
|
||||
/* readonly number properties */
|
||||
zprop_register_number(ZPOOL_PROP_SIZE, "size", 0, PROP_READONLY,
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
|
|
|
@ -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 <colm@tuatha.org>
|
||||
*/
|
||||
|
||||
#include <sys/spa.h>
|
||||
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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'"
|
|
@ -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"
|
|
@ -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"
|
|
@ -57,6 +57,7 @@ typeset -a properties=(
|
|||
"leaked"
|
||||
"multihost"
|
||||
"autotrim"
|
||||
"compatibility"
|
||||
"feature@async_destroy"
|
||||
"feature@empty_bpobj"
|
||||
"feature@lz4_compress"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
|
@ -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 \
|
||||
|
|
|
@ -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."
|
Loading…
Reference in New Issue