]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Create zap for root vdev
authorrob-wing <98866084+rob-wing@users.noreply.github.com>
Thu, 20 Apr 2023 17:07:56 +0000 (09:07 -0800)
committerGitHub <noreply@github.com>
Thu, 20 Apr 2023 17:07:56 +0000 (10:07 -0700)
And add it to the AVZ, this is not backwards compatible with older pools
due to an assertion in spa_sync() that verifies the number of ZAPs of
all vdevs matches the number of ZAPs in the AVZ.

Granted, the assertion only applies to #DEBUG builds - still, a feature
flag is introduced to avoid the assertion, com.klarasystems:vdev_zaps_v2

Notably, this allows to get/set properties on the root vdev:

    % zpool set user:prop=value <pool> root-0

Before this commit, it was already possible to get/set properties on
top-level vdevs with the syntax <type>-<vdev_id> (e.g. mirror-0):

    % zpool set user:prop=value <pool> mirror-0

This syntax also applies to the root vdev as it is is of type 'root'
with a vdev_id of 0, root-0. The keyword 'root' as an alias for
'root-0'.

The following tests have been added:

    - zpool get all properties from root vdev
    - zpool set a property on root vdev
    - verify root vdev ZAP is created

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Wing <rob.wing@klarasystems.com>
Sponsored-by: Seagate Technology
Submitted-by: Klara, Inc.
Closes #14405

27 files changed:
cmd/zdb/zdb.c
cmd/zpool/zpool_main.c
include/sys/fs/zfs.h
include/sys/vdev_impl.h
include/zfeature_common.h
lib/libzfs/libzfs.abi
lib/libzfs/libzfs_pool.c
lib/libzutil/zutil_import.c
man/man7/zpool-features.7
module/zcommon/zfeature_common.c
module/zfs/spa.c
module/zfs/vdev.c
module/zfs/vdev_label.c
tests/runfiles/common.run
tests/zfs-tests/tests/Makefile.am
tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg [new file with mode: 0644]
tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get_001_pos.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
tests/zfs-tests/tests/functional/cli_root/zpool_set/vdev_set_001_pos.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh
tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh

index e87826f7467bb3f48a026ed8f4a0d891d2ca0da9..c93ed4399afd80b5039b8a29fcfcbe5e3f8498e8 100644 (file)
@@ -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);
index 27e805943443c8453154dcd4fd3a53e41dc864c9..4965cba5269262f4b945ebb55cb09bf17e3969f3 100644 (file)
@@ -10002,32 +10002,32 @@ get_callback_vdev(zpool_handle_t *zhp, char *vdevname, void *data)
 }
 
 static int
-get_callback_vdev_width_cb(void *zhp_data, nvlist_t *nv, void *data)
+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;
 
-       /* Adjust the column widths for the vdev properties */
-       ret = vdev_expand_proplist(zhp, vdevname, &cbp->cb_proplist);
-
-       return (ret);
-}
+       /*
+        * 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);
 
-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);
-       int ret;
+       (void) vdev_expand_proplist(zhp, vdevname, &cbp->cb_proplist);
 
-       /* Display the properties */
        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);
 }
 
index 25babd4ea8cffb08f73c62865260dfed8b9eec19..0734ff12280e0cd49cc9fab32973959ecc1e4bf6 100644 (file)
@@ -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"
index 7cfffe3b4eeddacf8bb25ad7a015fa9e7cf3cb23..ea3043c82a399fcbaa69a03d45da4886a96b9287 100644 (file)
@@ -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.
index ef915a70952ec4da497cc8477093f17292d9cf60..7066c699e2036ea42be64f73c62077dfed70f6d2 100644 (file)
@@ -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;
 
index 41e74fd8db19c2b5847b5875d5c7922fe32bee2d..f9aed4e0d57e7bfddf87fe472e7354a9f9636845 100644 (file)
     <elf-symbol name='fletcher_4_superscalar_ops' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='libzfs_config_ops' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
-    <elf-symbol name='spa_feature_table' size='2128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='spa_feature_table' size='2184' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zfs_deleg_perm_tab' size='512' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
       <enumerator name='SPA_FEATURE_HEAD_ERRLOG' value='35'/>
       <enumerator name='SPA_FEATURE_BLAKE3' value='36'/>
       <enumerator name='SPA_FEATURE_BLOCK_CLONING' value='37'/>
-      <enumerator name='SPA_FEATURES' value='38'/>
+      <enumerator name='SPA_FEATURE_AVZ_V2' value='38'/>
+      <enumerator name='SPA_FEATURES' value='39'/>
     </enum-decl>
     <typedef-decl name='spa_feature_t' type-id='33ecb627' id='d6618c78'/>
     <qualified-type-def type-id='22cce67b' const='yes' id='d2816df0'/>
     </function-decl>
   </abi-instr>
   <abi-instr address-size='64' path='module/zcommon/zfeature_common.c' language='LANG_C99'>
-    <array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='17024' id='9944fffc'>
-      <subrange length='38' type-id='7359adad' id='aa4ccdac'/>
+    <array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='17472' id='dd432c71'>
+      <subrange length='39' type-id='7359adad' id='ae4a9561'/>
     </array-type-def>
     <enum-decl name='zfeature_flags' id='6db816a4'>
       <underlying-type type-id='9cac1fee'/>
     <pointer-type-def type-id='611586a1' size-in-bits='64' id='2e243169'/>
     <qualified-type-def type-id='eaa32e2f' const='yes' id='83be723c'/>
     <pointer-type-def type-id='83be723c' size-in-bits='64' id='7acd98a2'/>
-    <var-decl name='spa_feature_table' type-id='9944fffc' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
+    <var-decl name='spa_feature_table' type-id='dd432c71' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
     <var-decl name='zfeature_checks_disable' type-id='c19b74c3' mangled-name='zfeature_checks_disable' visibility='default' elf-symbol-id='zfeature_checks_disable'/>
     <function-decl name='opendir' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
index f9b7cc004d6b8660f035156b26a3b0a15d082a2c..ae4c861590fdc98aa0d2206f8ea5b647dbb82ebe 100644 (file)
@@ -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);
 
index 65f462e42cd0a7779e90c09a23d79d2bb56d29a4..19d8a4742813be80c57ba19898980d16b85e1172 100644 (file)
@@ -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);
        }
 
index 4cd7526858a3e37aa0ca44819f92d595b8c30240..efe9e833996a7d6cbd4fd710a1b7eb418c0607f8 100644 (file)
@@ -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
index 6fe1da8ed46f22fc176dadb5f8c600fc3275a4af..4c9b7ed72a0f2b21b96d3558cbcb01bf7730efe3 100644 (file)
@@ -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);
 }
 
index e76700a9caa3c7ed104393ddf0610d951cc50849..67601211d6c280c428cbaf072807d86870f012be 100644 (file)
@@ -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));
index 241be8fd856c23e9bb67f3687e715d6863269ea6..4bfd95861e02659a75c1be04b1b7ffd5a8ae0788 100644 (file)
@@ -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;
index f61be65a2c727c0b7fdf0382d9e1fcbc02f36aeb..85c7134ca4c4b54b0bcb7548a68802d1e2fdee2a 100644 (file)
@@ -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);
index 4233c0285c4b3da19b794af514bff284c3718a29..cc4ce03677cb6e374368f995f3e44dbd0dd4ed1f 100644 (file)
@@ -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]
index a470573616af4ecd44b6c7beca7ee1dd86bc1789..e671a3f6b02bbd504e823b0e824981220b529bec 100644 (file)
@@ -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 (file)
index 0000000..71a64d4
--- /dev/null
@@ -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 (executable)
index 0000000..bca2337
--- /dev/null
@@ -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 <pool> 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"
index 097cd52e47776210ee9bf93a4aeb3cc3bc1ec368..160a0ca2e6db19574f1639da9772e04fcb193990 100644 (file)
@@ -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 (executable)
index 0000000..a1f3efb
--- /dev/null
@@ -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"
index ad5bd9e7f81bbe9c0be916acb20292800571ce3d..c68a5b2c4c8350ab0441bd7927952a5d61e25ab5 100644 (file)
@@ -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
index b67cc6d973e6a2911f5988228a5180acece90da0..bdc8dcd468ae47e13abbc3d6ea0c02ba524ec3ab 100755 (executable)
@@ -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"
index c571973b080b5d1c1df43c66ce02adf0c61d2618..35c4f64fa463eb323323d9dde32676668d174ffe 100755 (executable)
@@ -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"
index 015729576a7d89358509765fae4793f192099721..bb6875c339c3c6652a95cb6b93ae7bda36ffb607 100755 (executable)
@@ -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"
index 3d0f55d5a9a7e1228fce40c1f5da17f4c1671225..e82e398c6d27e4d853eba275b2c43d6ea02830ca 100755 (executable)
@@ -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
index 1d82218bf283daeb26d4432d46d4cda8efe22003..4b9b45e149d70cc3ee2b774a437f40210fe22ca8 100755 (executable)
@@ -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
index ce94336c7c5d2084943fd452529de9cc39aa63a9..2ac493b8b0d2d39a6c65b8aff0a35a7ba282fe65 100755 (executable)
@@ -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"
index c7f12c633706ef06d3cfae41109ad558f799e272..c7a4a62de436f86111b9b0bfecd822c9ee8a3981 100755 (executable)
@@ -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)