diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c
index e87826f74..c93ed4399 100644
--- a/cmd/zdb/zdb.c
+++ b/cmd/zdb/zdb.c
@@ -7630,6 +7630,9 @@ mos_leak_vdev(vdev_t *vd)
mos_obj_refd(space_map_object(ms->ms_sm));
}
+ if (vd->vdev_root_zap != 0)
+ mos_obj_refd(vd->vdev_root_zap);
+
if (vd->vdev_top_zap != 0) {
mos_obj_refd(vd->vdev_top_zap);
mos_leak_vdev_top_zap(vd);
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index 27e805943..4965cba52 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -10001,33 +10001,33 @@ get_callback_vdev(zpool_handle_t *zhp, char *vdevname, void *data)
return (0);
}
-static int
-get_callback_vdev_width_cb(void *zhp_data, nvlist_t *nv, void *data)
-{
- zpool_handle_t *zhp = zhp_data;
- zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
- char *vdevname = zpool_vdev_name(g_zfs, zhp, nv,
- cbp->cb_vdevs.cb_name_flags);
- int ret;
-
- /* Adjust the column widths for the vdev properties */
- ret = vdev_expand_proplist(zhp, vdevname, &cbp->cb_proplist);
-
- return (ret);
-}
-
static int
get_callback_vdev_cb(void *zhp_data, nvlist_t *nv, void *data)
{
zpool_handle_t *zhp = zhp_data;
zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
- char *vdevname = zpool_vdev_name(g_zfs, zhp, nv,
- cbp->cb_vdevs.cb_name_flags);
+ char *vdevname;
+ const char *type;
int ret;
- /* Display the properties */
+ /*
+ * zpool_vdev_name() transforms the root vdev name (i.e., root-0) to the
+ * pool name for display purposes, which is not desired. Fallback to
+ * zpool_vdev_name() when not dealing with the root vdev.
+ */
+ type = fnvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE);
+ if (zhp != NULL && strcmp(type, "root") == 0)
+ vdevname = strdup("root-0");
+ else
+ vdevname = zpool_vdev_name(g_zfs, zhp, nv,
+ cbp->cb_vdevs.cb_name_flags);
+
+ (void) vdev_expand_proplist(zhp, vdevname, &cbp->cb_proplist);
+
ret = get_callback_vdev(zhp, vdevname, data);
+ free(vdevname);
+
return (ret);
}
@@ -10042,7 +10042,6 @@ get_callback(zpool_handle_t *zhp, void *data)
if (cbp->cb_type == ZFS_TYPE_VDEV) {
if (strcmp(cbp->cb_vdevs.cb_names[0], "all-vdevs") == 0) {
- for_each_vdev(zhp, get_callback_vdev_width_cb, data);
for_each_vdev(zhp, get_callback_vdev_cb, data);
} else {
/* Adjust column widths for vdev properties */
@@ -10119,6 +10118,7 @@ zpool_do_get(int argc, char **argv)
int ret;
int c, i;
char *propstr = NULL;
+ char *vdev = NULL;
cb.cb_first = B_TRUE;
@@ -10216,10 +10216,17 @@ found:
} else if (are_all_pools(1, argv)) {
/* The first arg is a pool name */
if ((argc == 2 && strcmp(argv[1], "all-vdevs") == 0) ||
+ (argc == 2 && strcmp(argv[1], "root") == 0) ||
are_vdevs_in_pool(argc - 1, argv + 1, argv[0],
&cb.cb_vdevs)) {
+
+ if (strcmp(argv[1], "root") == 0)
+ vdev = strdup("root-0");
+ else
+ vdev = strdup(argv[1]);
+
/* ... and the rest are vdev names */
- cb.cb_vdevs.cb_names = argv + 1;
+ cb.cb_vdevs.cb_names = &vdev;
cb.cb_vdevs.cb_names_count = argc - 1;
cb.cb_type = ZFS_TYPE_VDEV;
argc = 1; /* One pool to process */
@@ -10264,6 +10271,9 @@ found:
else
zprop_free_list(cb.cb_proplist);
+ if (vdev != NULL)
+ free(vdev);
+
return (ret);
}
@@ -10365,6 +10375,7 @@ zpool_do_set(int argc, char **argv)
{
set_cbdata_t cb = { 0 };
int error;
+ char *vdev = NULL;
current_prop_type = ZFS_TYPE_POOL;
if (argc > 1 && argv[1][0] == '-') {
@@ -10413,13 +10424,20 @@ zpool_do_set(int argc, char **argv)
/* argv[1], when supplied, is vdev name */
if (argc == 2) {
- if (!are_vdevs_in_pool(1, argv + 1, argv[0], &cb.cb_vdevs)) {
+
+ if (strcmp(argv[1], "root") == 0)
+ vdev = strdup("root-0");
+ else
+ vdev = strdup(argv[1]);
+
+ if (!are_vdevs_in_pool(1, &vdev, argv[0], &cb.cb_vdevs)) {
(void) fprintf(stderr, gettext(
"cannot find '%s' in '%s': device not in pool\n"),
- argv[1], argv[0]);
+ vdev, argv[0]);
+ free(vdev);
return (EINVAL);
}
- cb.cb_vdevs.cb_names = argv + 1;
+ cb.cb_vdevs.cb_names = &vdev;
cb.cb_vdevs.cb_names_count = 1;
cb.cb_type = ZFS_TYPE_VDEV;
}
@@ -10427,6 +10445,9 @@ zpool_do_set(int argc, char **argv)
error = for_each_pool(1, argv, B_TRUE, NULL, ZFS_TYPE_POOL,
B_FALSE, set_callback, &cb);
+ if (vdev != NULL)
+ free(vdev);
+
return (error);
}
diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h
index 25babd4ea..0734ff122 100644
--- a/include/sys/fs/zfs.h
+++ b/include/sys/fs/zfs.h
@@ -816,6 +816,7 @@ typedef struct zpool_load_policy {
#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read"
#define ZPOOL_CONFIG_FEATURE_STATS "feature_stats" /* not stored on disk */
#define ZPOOL_CONFIG_ERRATA "errata" /* not stored on disk */
+#define ZPOOL_CONFIG_VDEV_ROOT_ZAP "com.klarasystems:vdev_zap_root"
#define ZPOOL_CONFIG_VDEV_TOP_ZAP "com.delphix:vdev_zap_top"
#define ZPOOL_CONFIG_VDEV_LEAF_ZAP "com.delphix:vdev_zap_leaf"
#define ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS "com.delphix:has_per_vdev_zaps"
diff --git a/include/sys/vdev_impl.h b/include/sys/vdev_impl.h
index 7cfffe3b4..ea3043c82 100644
--- a/include/sys/vdev_impl.h
+++ b/include/sys/vdev_impl.h
@@ -277,6 +277,7 @@ struct vdev {
kthread_t *vdev_open_thread; /* thread opening children */
kthread_t *vdev_validate_thread; /* thread validating children */
uint64_t vdev_crtxg; /* txg when top-level was added */
+ uint64_t vdev_root_zap;
/*
* Top-level vdev state.
diff --git a/include/zfeature_common.h b/include/zfeature_common.h
index ef915a709..7066c699e 100644
--- a/include/zfeature_common.h
+++ b/include/zfeature_common.h
@@ -79,6 +79,7 @@ typedef enum spa_feature {
SPA_FEATURE_HEAD_ERRLOG,
SPA_FEATURE_BLAKE3,
SPA_FEATURE_BLOCK_CLONING,
+ SPA_FEATURE_AVZ_V2,
SPA_FEATURES
} spa_feature_t;
diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi
index 41e74fd8d..f9aed4e0d 100644
--- a/lib/libzfs/libzfs.abi
+++ b/lib/libzfs/libzfs.abi
@@ -595,7 +595,7 @@
-
+
@@ -5808,7 +5808,8 @@
-
+
+
@@ -8694,8 +8695,8 @@
-
-
+
+
@@ -8772,7 +8773,7 @@
-
+
diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c
index f9b7cc004..ae4c86159 100644
--- a/lib/libzfs/libzfs_pool.c
+++ b/lib/libzfs/libzfs_pool.c
@@ -2859,6 +2859,7 @@ zpool_vdev_is_interior(const char *name)
strncmp(name, VDEV_TYPE_SPARE, strlen(VDEV_TYPE_SPARE)) == 0 ||
strncmp(name,
VDEV_TYPE_REPLACING, strlen(VDEV_TYPE_REPLACING)) == 0 ||
+ strncmp(name, VDEV_TYPE_ROOT, strlen(VDEV_TYPE_ROOT)) == 0 ||
strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
return (B_TRUE);
diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c
index 65f462e42..19d8a4742 100644
--- a/lib/libzutil/zutil_import.c
+++ b/lib/libzutil/zutil_import.c
@@ -1927,9 +1927,8 @@ for_each_vdev_cb(void *zhp, nvlist_t *nv, pool_vdev_iter_f func,
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
return (ret);
- /* Don't run our function on root or indirect vdevs */
- if ((strcmp(type, VDEV_TYPE_ROOT) != 0) &&
- (strcmp(type, VDEV_TYPE_INDIRECT) != 0)) {
+ /* Don't run our function on indirect vdevs */
+ if (strcmp(type, VDEV_TYPE_INDIRECT) != 0) {
ret |= func(zhp, nv, data);
}
diff --git a/man/man7/zpool-features.7 b/man/man7/zpool-features.7
index 4cd752685..efe9e8339 100644
--- a/man/man7/zpool-features.7
+++ b/man/man7/zpool-features.7
@@ -858,6 +858,22 @@ by user and group.
\*[instant-never]
\*[remount-upgrade]
.
+.feature com.klarasystems vdev_zaps_v2 no
+This feature creates a ZAP object for the root vdev.
+.Pp
+This feature becomes active after the next
+.Nm zpool Cm import
+or
+.Nm zpool reguid .
+.
+Properties can be retrieved or set on the root vdev using
+.Nm zpool Cm get
+and
+.Nm zpool Cm set
+with
+.Sy root
+as the vdev name which is an alias for
+.Sy root-0 .
.feature org.openzfs zilsaxattr yes extensible_dataset
This feature enables
.Sy xattr Ns = Ns Sy sa
diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c
index 6fe1da8ed..4c9b7ed72 100644
--- a/module/zcommon/zfeature_common.c
+++ b/module/zcommon/zfeature_common.c
@@ -731,6 +731,12 @@ zpool_feature_init(void)
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
sfeatures);
+ zfeature_register(SPA_FEATURE_AVZ_V2,
+ "com.klarasystems:vdev_zaps_v2", "vdev_zaps_v2",
+ "Support for root vdev ZAP.",
+ ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
+
zfs_mod_list_supported_free(sfeatures);
}
diff --git a/module/zfs/spa.c b/module/zfs/spa.c
index e76700a9c..67601211d 100644
--- a/module/zfs/spa.c
+++ b/module/zfs/spa.c
@@ -3044,6 +3044,12 @@ vdev_count_verify_zaps(vdev_t *vd)
spa_t *spa = vd->vdev_spa;
uint64_t total = 0;
+ if (spa_feature_is_active(vd->vdev_spa, SPA_FEATURE_AVZ_V2) &&
+ vd->vdev_root_zap != 0) {
+ total++;
+ ASSERT0(zap_lookup_int(spa->spa_meta_objset,
+ spa->spa_all_vdev_zaps, vd->vdev_root_zap));
+ }
if (vd->vdev_top_zap != 0) {
total++;
ASSERT0(zap_lookup_int(spa->spa_meta_objset,
@@ -8626,6 +8632,11 @@ spa_avz_build(vdev_t *vd, uint64_t avz, dmu_tx_t *tx)
{
spa_t *spa = vd->vdev_spa;
+ if (vd->vdev_root_zap != 0 &&
+ spa_feature_is_active(spa, SPA_FEATURE_AVZ_V2)) {
+ VERIFY0(zap_add_int(spa->spa_meta_objset, avz,
+ vd->vdev_root_zap, tx));
+ }
if (vd->vdev_top_zap != 0) {
VERIFY0(zap_add_int(spa->spa_meta_objset, avz,
vd->vdev_top_zap, tx));
diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c
index 241be8fd8..4bfd95861 100644
--- a/module/zfs/vdev.c
+++ b/module/zfs/vdev.c
@@ -397,7 +397,9 @@ vdev_prop_get_int(vdev_t *vd, vdev_prop_t prop, uint64_t *value)
uint64_t objid;
int err;
- if (vd->vdev_top_zap != 0) {
+ if (vd->vdev_root_zap != 0) {
+ objid = vd->vdev_root_zap;
+ } else if (vd->vdev_top_zap != 0) {
objid = vd->vdev_top_zap;
} else if (vd->vdev_leaf_zap != 0) {
objid = vd->vdev_leaf_zap;
@@ -898,6 +900,14 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_CREATE_TXG,
&vd->vdev_crtxg);
+ if (vd->vdev_ops == &vdev_root_ops &&
+ (alloctype == VDEV_ALLOC_LOAD ||
+ alloctype == VDEV_ALLOC_SPLIT ||
+ alloctype == VDEV_ALLOC_ROOTPOOL)) {
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_VDEV_ROOT_ZAP,
+ &vd->vdev_root_zap);
+ }
+
/*
* If we're a top-level vdev, try to load the allocation parameters.
*/
@@ -3347,6 +3357,12 @@ vdev_construct_zaps(vdev_t *vd, dmu_tx_t *tx)
vdev_zap_allocation_data(vd, tx);
}
}
+ if (vd->vdev_ops == &vdev_root_ops && vd->vdev_root_zap == 0 &&
+ spa_feature_is_enabled(vd->vdev_spa, SPA_FEATURE_AVZ_V2)) {
+ if (!spa_feature_is_active(vd->vdev_spa, SPA_FEATURE_AVZ_V2))
+ spa_feature_incr(vd->vdev_spa, SPA_FEATURE_AVZ_V2, tx);
+ vd->vdev_root_zap = vdev_create_link_zap(vd, tx);
+ }
for (uint64_t i = 0; i < vd->vdev_children; i++) {
vdev_construct_zaps(vd->vdev_child[i], tx);
@@ -5683,12 +5699,17 @@ vdev_props_set_sync(void *arg, dmu_tx_t *tx)
/*
* Set vdev property values in the vdev props mos object.
*/
- if (vd->vdev_top_zap != 0) {
+ if (vd->vdev_root_zap != 0) {
+ objid = vd->vdev_root_zap;
+ } else if (vd->vdev_top_zap != 0) {
objid = vd->vdev_top_zap;
} else if (vd->vdev_leaf_zap != 0) {
objid = vd->vdev_leaf_zap;
} else {
- panic("vdev not top or leaf");
+ /*
+ * XXX: implement vdev_props_set_check()
+ */
+ panic("vdev not root/top/leaf");
}
switch (prop = vdev_name_to_prop(propname)) {
@@ -5891,7 +5912,9 @@ vdev_prop_get(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl)
nvlist_lookup_nvlist(innvl, ZPOOL_VDEV_PROPS_GET_PROPS, &nvprops);
- if (vd->vdev_top_zap != 0) {
+ if (vd->vdev_root_zap != 0) {
+ objid = vd->vdev_root_zap;
+ } else if (vd->vdev_top_zap != 0) {
objid = vd->vdev_top_zap;
} else if (vd->vdev_leaf_zap != 0) {
objid = vd->vdev_leaf_zap;
diff --git a/module/zfs/vdev_label.c b/module/zfs/vdev_label.c
index f61be65a2..85c7134ca 100644
--- a/module/zfs/vdev_label.c
+++ b/module/zfs/vdev_label.c
@@ -573,6 +573,12 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats,
vd->vdev_top_zap);
}
+ if (vd->vdev_ops == &vdev_root_ops && vd->vdev_root_zap != 0 &&
+ spa_feature_is_active(vd->vdev_spa, SPA_FEATURE_AVZ_V2)) {
+ fnvlist_add_uint64(nv, ZPOOL_CONFIG_VDEV_ROOT_ZAP,
+ vd->vdev_root_zap);
+ }
+
if (vd->vdev_resilver_deferred) {
ASSERT(vd->vdev_ops->vdev_op_leaf);
ASSERT(spa->spa_resilver_deferred);
diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run
index 4233c0285..cc4ce0367 100644
--- a/tests/runfiles/common.run
+++ b/tests/runfiles/common.run
@@ -394,7 +394,7 @@ tags = ['functional', 'cli_root', 'zpool_export']
[tests/functional/cli_root/zpool_get]
tests = ['zpool_get_001_pos', 'zpool_get_002_pos', 'zpool_get_003_pos',
- 'zpool_get_004_neg', 'zpool_get_005_pos']
+ 'zpool_get_004_neg', 'zpool_get_005_pos', 'vdev_get_001_pos']
tags = ['functional', 'cli_root', 'zpool_get']
[tests/functional/cli_root/zpool_history]
@@ -482,7 +482,7 @@ tags = ['functional', 'cli_root', 'zpool_scrub']
[tests/functional/cli_root/zpool_set]
tests = ['zpool_set_001_pos', 'zpool_set_002_neg', 'zpool_set_003_neg',
- 'zpool_set_ashift', 'zpool_set_features']
+ 'zpool_set_ashift', 'zpool_set_features', 'vdev_set_001_pos']
tags = ['functional', 'cli_root', 'zpool_set']
[tests/functional/cli_root/zpool_split]
diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am
index a47057361..e671a3f6b 100644
--- a/tests/zfs-tests/tests/Makefile.am
+++ b/tests/zfs-tests/tests/Makefile.am
@@ -178,6 +178,7 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \
functional/cli_root/zpool_expand/zpool_expand.cfg \
functional/cli_root/zpool_export/zpool_export.cfg \
functional/cli_root/zpool_export/zpool_export.kshlib \
+ functional/cli_root/zpool_get/vdev_get.cfg \
functional/cli_root/zpool_get/zpool_get.cfg \
functional/cli_root/zpool_get/zpool_get_parsable.cfg \
functional/cli_root/zpool_import/blockfiles/cryptv0.dat.bz2 \
@@ -1032,6 +1033,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_export/zpool_export_004_pos.ksh \
functional/cli_root/zpool_get/cleanup.ksh \
functional/cli_root/zpool_get/setup.ksh \
+ functional/cli_root/zpool_get/vdev_get_001_pos.ksh \
functional/cli_root/zpool_get/zpool_get_001_pos.ksh \
functional/cli_root/zpool_get/zpool_get_002_pos.ksh \
functional/cli_root/zpool_get/zpool_get_003_pos.ksh \
@@ -1146,6 +1148,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_set/cleanup.ksh \
functional/cli_root/zpool_set/setup.ksh \
functional/cli_root/zpool/setup.ksh \
+ functional/cli_root/zpool_set/vdev_set_001_pos.ksh \
functional/cli_root/zpool_set/zpool_set_001_pos.ksh \
functional/cli_root/zpool_set/zpool_set_002_neg.ksh \
functional/cli_root/zpool_set/zpool_set_003_neg.ksh \
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg b/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg
new file mode 100644
index 000000000..71a64d4fa
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg
@@ -0,0 +1,73 @@
+#
+# 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 https://opensource.org/licenses/CDDL-1.0.
+# 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) 2022, Klara Inc.
+#
+
+# Set the expected properties of a vdev
+typeset -a properties=(
+ capacity
+ state
+ guid
+ asize
+ psize
+ ashift
+ size
+ free
+ allocated
+ comment
+ expandsize
+ fragmentation
+ bootsize
+ parity
+ path
+ devid
+ physpath
+ encpath
+ fru
+ parent
+ children
+ numchildren
+ read_errors
+ write_errors
+ checksum_errors
+ initialize_errors
+ null_ops
+ read_ops
+ write_ops
+ free_ops
+ claim_ops
+ trim_ops
+ null_bytes
+ read_bytes
+ write_bytes
+ free_bytes
+ claim_bytes
+ trim_bytes
+ removing
+ allocating
+ failfast
+ checksum_n
+ checksum_t
+ io_n
+ io_t
+)
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get_001_pos.ksh
new file mode 100755
index 000000000..bca233786
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get_001_pos.ksh
@@ -0,0 +1,62 @@
+#!/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 https://opensource.org/licenses/CDDL-1.0.
+# 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) 2022, Klara Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_get/vdev_get.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool get root works as expected
+#
+# STRATEGY:
+#
+# 1. use zpool get to retrieve properties from root vdev
+# 2. verify expected properties match detected properties
+#
+
+log_assert "zpool get all on root vdev"
+
+EXPECT="$(zpool get -H all ${TESTPOOL} root | wc -l)"
+if [ $? -ne 0 ]; then
+ log_fail "cannot retrieve properties from root vdev"
+fi
+
+i=0;
+while [ $i -lt "${#properties[@]}" ]
+do
+ log_must zpool get -H "${properties[$i]}" "$TESTPOOL" root
+ i=$(($i+1))
+done
+
+EXPECT=$((EXPECT))
+if [ $i -gt $EXPECT ]; then
+ log_fail "found vdev properties not in vdev_get.cfg: $i/$EXPECT."
+elif [ $i -lt $EXPECT ]; then
+ log_fail "expected properties not found in vdev_get.cfg: $i/$EXPECT."
+fi
+
+log_pass "zpool get all on root vdev"
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 097cd52e4..160a0ca2e 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
@@ -104,5 +104,6 @@ if is_linux || is_freebsd; then
"feature@head_errlog"
"feature@blake3"
"feature@block_cloning"
+ "feature@vdev_zaps_v2"
)
fi
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_set/vdev_set_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_set/vdev_set_001_pos.ksh
new file mode 100755
index 000000000..a1f3efb90
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_set/vdev_set_001_pos.ksh
@@ -0,0 +1,52 @@
+#!/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 https://opensource.org/licenses/CDDL-1.0.
+# 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) 2022, Klara Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# zpool set comment property on root vdev
+#
+# STRATEGY:
+# 1. set a property on root vdev
+# 2. verify the property is set
+#
+
+log_assert "zpool set comment property on root vdev"
+
+log_must zpool set comment="openzfs" ${TESTPOOL} root
+
+COMMENT="$(zpool get -H -o value comment ${TESTPOOL} root)"
+if [ $? -ne 0 ]; then
+ log_fail "cant retrieve comment property from root vdev"
+fi
+
+if [ "$COMMENT" != "openzfs" ]; then
+ log_fail "unexpected value for comment property: $COMMENT != \"openzfs\""
+fi
+
+log_pass "zpool set comment property on root vdev"
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib
index ad5bd9e7f..c68a5b2c4 100644
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib
@@ -34,6 +34,10 @@ function get_top_vd_zap # dsk conf
{
get_conf_section "$1" "$2" | awk '/com.delphix:vdev_zap_top: [0-9]+/ {print $2}'
}
+function get_root_vd_zap # conf
+{
+ awk '/com.klarasystems:vdev_zap_root: [0-9]+/ {print $2}' "$1"
+}
function assert_has_sentinel # conf
{
@@ -54,6 +58,15 @@ function assert_zap_common # pool vd lvl zapobj
fi
}
+function assert_root_zap # pool conf
+{
+ typeset pool=$1
+ typeset conf=$2
+
+ root_zap=$(get_root_vd_zap $conf)
+ assert_zap_common $pool "root vdev" "root" $root_zap
+}
+
function assert_top_zap # pool vd conf
{
typeset pool=$1
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh
index b67cc6d97..bdc8dcd46 100755
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh
@@ -21,7 +21,7 @@
#
# Strategy:
# 1. Create a pool with one disk.
-# 2. Verify that the disk has a top and leaf ZAP in its config and the MOS.
+# 2. Verify that the disk has a root, top and leaf ZAP in its config and the MOS.
#
. $STF_SUITE/include/libtest.shlib
@@ -35,6 +35,7 @@ log_must zpool create -f $TESTPOOL $DISK
conf="$TESTDIR/vz001"
log_must eval "zdb -PC $TESTPOOL > $conf"
+assert_root_zap $TESTPOOL "$conf"
assert_top_zap $TESTPOOL $DISK "$conf"
assert_leaf_zap $TESTPOOL $DISK "$conf"
assert_has_sentinel "$conf"
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh
index c571973b0..35c4f64fa 100755
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh
@@ -36,6 +36,7 @@ conf="$TESTDIR/vz002"
log_must eval "zdb -PC $TESTPOOL > $conf"
assert_has_sentinel "$conf"
+assert_root_zap $TESTPOOL "$conf"
for DISK in $DISKS; do
assert_top_zap $TESTPOOL $DISK "$conf"
assert_leaf_zap $TESTPOOL $DISK "$conf"
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh
index 015729576..bb6875c33 100755
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh
@@ -37,6 +37,7 @@ conf="$TESTDIR/vz003"
log_must eval "zdb -PC $TESTPOOL > $conf"
assert_has_sentinel "$conf"
+assert_root_zap $TESTPOOL "$conf"
assert_top_zap $TESTPOOL "type: 'mirror'" "$conf"
for DISK in $DISKS; do
assert_leaf_zap $TESTPOOL $DISK "$conf"
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
index 3d0f55d5a..e82e398c6 100755
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
@@ -40,6 +40,7 @@ log_must zpool create -f $TESTPOOL $DISK
conf="$TESTDIR/vz004"
log_must eval "zdb -PC $TESTPOOL > $conf"
assert_has_sentinel "$conf"
+assert_root_zap $TESTPOOL "$conf"
orig_top=$(get_top_vd_zap $DISK $conf)
orig_leaf=$(get_leaf_vd_zap $DISK $conf)
assert_zap_common $TESTPOOL $DISK "top" $orig_top
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh
index 1d82218bf..4b9b45e14 100755
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh
@@ -37,6 +37,7 @@ log_must zpool create -f $TESTPOOL $DISK
conf="$TESTDIR/vz005"
log_must eval "zdb -PC $TESTPOOL > $conf"
assert_has_sentinel "$conf"
+assert_root_zap $TESTPOOL "$conf"
orig_top=$(get_top_vd_zap $DISK $conf)
orig_leaf=$(get_leaf_vd_zap $DISK $conf)
assert_zap_common $TESTPOOL $DISK "top" $orig_top
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh
index ce94336c7..2ac493b8b 100755
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh
@@ -39,6 +39,7 @@ conf="$TESTDIR/vz006"
log_must eval "zdb -PC $TESTPOOL > $conf"
assert_has_sentinel "$conf"
+assert_root_zap $TESTPOOL "$conf"
orig_top=$(get_top_vd_zap ${DISK_ARR[1]} $conf)
assert_zap_common $TESTPOOL ${DISK_ARR[1]} "top" $orig_top
assert_leaf_zap $TESTPOOL ${DISK_ARR[1]} "$conf"
diff --git a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh
index c7f12c633..c7a4a62de 100755
--- a/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh
+++ b/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh
@@ -39,6 +39,7 @@ conf="$TESTDIR/vz007"
log_must eval "zdb -PC $TESTPOOL > $conf"
assert_has_sentinel "$conf"
+assert_root_zap $TESTPOOL "$conf"
orig_top=$(get_top_vd_zap "type: 'mirror'" $conf)
orig_leaf0=$(get_leaf_vd_zap ${DISK_ARR[0]} $conf)
orig_leaf1=$(get_leaf_vd_zap ${DISK_ARR[1]} $conf)