]> git.proxmox.com Git - mirror_zfs.git/commitdiff
JSON: Fix class values for mirrored special vdevs
authorTony Hutter <hutter2@llnl.gov>
Thu, 11 Jul 2024 22:35:40 +0000 (15:35 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 6 Aug 2024 19:47:58 +0000 (12:47 -0700)
This fixes things so mirrored special vdevs report themselves as
"class=special" rather than "class=normal".

This happens due to the way the vdev nvlists are constructed:

mirrored special devices - The 'mirror' vdev has allocation bias as
"special" and it's leaf vdevs are "normal"

single or RAID0 special devices - Leaf vdevs have allocation bias as
"special".

This commit adds in code to check if a leaf's parent is a "special"
vdev to see if it should also report "special".

Reviewed-by: Ameer Hamza <ahamza@ixsystems.com>
Reviewed-by: Umer Saleem <usaleem@ixsystems.com>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #16217

cmd/zpool/zpool_main.c
include/libzfs.h
lib/libzfs/libzfs.abi
lib/libzfs/libzfs_pool.c

index 6f8817c09fd45ef0289240ac8d1a5fd49ca1699c..620746f8e7bbe75f608634f8b99224a307a4a835 100644 (file)
@@ -1154,11 +1154,16 @@ fill_vdev_info(nvlist_t *list, zpool_handle_t *zhp, char *name,
        vdev_stat_t *vs;
        uint_t c;
        nvlist_t *nvdev;
+       nvlist_t *nvdev_parent = NULL;
+       char *_name;
 
        if (strcmp(name, zpool_get_name(zhp)) != 0)
-               nvdev = zpool_find_vdev(zhp, name, NULL, &l2c, NULL);
+               _name = name;
        else
-               nvdev = zpool_find_vdev(zhp, "root-0", NULL, &l2c, NULL);
+               _name = (char *)"root-0";
+
+       nvdev = zpool_find_vdev(zhp, _name, NULL, &l2c, NULL);
+
        fnvlist_add_string(list, "name", name);
        if (addtype)
                fnvlist_add_string(list, "type", "VDEV");
@@ -1203,8 +1208,32 @@ fill_vdev_info(nvlist_t *list, zpool_handle_t *zhp, char *name,
                            ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
                        if (bias != NULL)
                                fnvlist_add_string(list, "class", bias);
-                       else
-                               fnvlist_add_string(list, "class", "normal");
+                       else {
+                               nvdev_parent = NULL;
+                               nvdev_parent = zpool_find_parent_vdev(zhp,
+                                   _name, NULL, NULL, NULL);
+
+                               /*
+                                * With a mirrored special device, the parent
+                                * "mirror" vdev will have
+                                * ZPOOL_CONFIG_ALLOCATION_BIAS set to "special"
+                                * not the leaf vdevs.  If we're a leaf vdev
+                                * in that case we need to look at our parent
+                                * to see if they're "special" to know if we
+                                * are "special" too.
+                                */
+                               if (nvdev_parent) {
+                                       (void) nvlist_lookup_string(
+                                           nvdev_parent,
+                                           ZPOOL_CONFIG_ALLOCATION_BIAS,
+                                           &bias);
+                               }
+                               if (bias != NULL)
+                                       fnvlist_add_string(list, "class", bias);
+                               else
+                                       fnvlist_add_string(list, "class",
+                                           "normal");
+                       }
                }
                if (nvlist_lookup_uint64_array(nvdev, ZPOOL_CONFIG_VDEV_STATS,
                    (uint64_t **)&vs, &c) == 0) {
index cd417a06dd20aa9a75d393b2e8c8421863635863..d3663435c29d1787d52ca987378c4534d765fb5e 100644 (file)
@@ -327,6 +327,8 @@ _LIBZFS_H int zpool_vdev_clear(zpool_handle_t *, uint64_t);
 
 _LIBZFS_H nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
     boolean_t *, boolean_t *);
+_LIBZFS_H nvlist_t *zpool_find_parent_vdev(zpool_handle_t *, const char *,
+    boolean_t *, boolean_t *, boolean_t *);
 _LIBZFS_H nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
     boolean_t *, boolean_t *, boolean_t *);
 _LIBZFS_H int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *,
index 7dc5e607171c27b2c2ff21a4311910d0efde0bb4..51c8dc9647ee688d76d05160faef7197e7b59c6a 100644 (file)
     <elf-symbol name='zpool_feature_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zpool_find_config' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zpool_find_vdev' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='zpool_find_parent_vdev' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zpool_find_vdev_by_physpath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zpool_free_handles' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='zpool_get_all_vdev_props' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
       <parameter type-id='37e3bd22' name='log'/>
       <return type-id='5ce45b60'/>
     </function-decl>
+    <function-decl name='zpool_find_parent_vdev' mangled-name='zpool_find_parent_vdev' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_find_parent_vdev'>
+      <parameter type-id='4c81de99' name='zhp'/>
+      <parameter type-id='80f4b756' name='path'/>
+      <parameter type-id='37e3bd22' name='avail_spare'/>
+      <parameter type-id='37e3bd22' name='l2cache'/>
+      <parameter type-id='37e3bd22' name='log'/>
+      <return type-id='5ce45b60'/>
+    </function-decl>
     <function-decl name='zpool_vdev_path_to_guid' mangled-name='zpool_vdev_path_to_guid' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_vdev_path_to_guid'>
       <parameter type-id='4c81de99' name='zhp'/>
       <parameter type-id='80f4b756' name='path'/>
index 2bf099e0c05b5b6c9fecdd22d27726d1272de281..b9ddd75f0dfc591b4daab1b41f6b156798ea9e2f 100644 (file)
@@ -2863,10 +2863,13 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd)
  * the nvpair name to determine how we should look for the device.
  * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
  * spare; but FALSE if its an INUSE spare.
+ *
+ * If 'return_parent' is set, then return the *parent* of the vdev you're
+ * searching for rather than the vdev itself.
  */
 static nvlist_t *
 vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
-    boolean_t *l2cache, boolean_t *log)
+    boolean_t *l2cache, boolean_t *log, boolean_t return_parent)
 {
        uint_t c, children;
        nvlist_t **child;
@@ -2874,6 +2877,8 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
        uint64_t is_log;
        const char *srchkey;
        nvpair_t *pair = nvlist_next_nvpair(search, NULL);
+       const char *tmp = NULL;
+       boolean_t is_root;
 
        /* Nothing to look for */
        if (search == NULL || pair == NULL)
@@ -2882,6 +2887,12 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
        /* Obtain the key we will use to search */
        srchkey = nvpair_name(pair);
 
+       nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &tmp);
+       if (strcmp(tmp, "root") == 0)
+               is_root = B_TRUE;
+       else
+               is_root = B_FALSE;
+
        switch (nvpair_type(pair)) {
        case DATA_TYPE_UINT64:
                if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) {
@@ -3012,7 +3023,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
 
        for (c = 0; c < children; c++) {
                if ((ret = vdev_to_nvlist_iter(child[c], search,
-                   avail_spare, l2cache, NULL)) != NULL) {
+                   avail_spare, l2cache, NULL, return_parent)) != NULL) {
                        /*
                         * The 'is_log' value is only set for the toplevel
                         * vdev, not the leaf vdevs.  So we always lookup the
@@ -3025,7 +3036,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
                            is_log) {
                                *log = B_TRUE;
                        }
-                       return (ret);
+                       return (ret && return_parent && !is_root ? nv : ret);
                }
        }
 
@@ -3033,9 +3044,11 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
            &child, &children) == 0) {
                for (c = 0; c < children; c++) {
                        if ((ret = vdev_to_nvlist_iter(child[c], search,
-                           avail_spare, l2cache, NULL)) != NULL) {
+                           avail_spare, l2cache, NULL, return_parent))
+                           != NULL) {
                                *avail_spare = B_TRUE;
-                               return (ret);
+                               return (ret && return_parent &&
+                                   !is_root ? nv : ret);
                        }
                }
        }
@@ -3044,9 +3057,11 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
            &child, &children) == 0) {
                for (c = 0; c < children; c++) {
                        if ((ret = vdev_to_nvlist_iter(child[c], search,
-                           avail_spare, l2cache, NULL)) != NULL) {
+                           avail_spare, l2cache, NULL, return_parent))
+                           != NULL) {
                                *l2cache = B_TRUE;
-                               return (ret);
+                               return (ret && return_parent &&
+                                   !is_root ? nv : ret);
                        }
                }
        }
@@ -3081,7 +3096,8 @@ zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
        *l2cache = B_FALSE;
        if (log != NULL)
                *log = B_FALSE;
-       ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
+       ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log,
+           B_FALSE);
        fnvlist_free(search);
 
        return (ret);
@@ -3109,11 +3125,12 @@ zpool_vdev_is_interior(const char *name)
 }
 
 /*
- * Lookup the nvlist for a given vdev.
+ * Lookup the nvlist for a given vdev or vdev's parent (depending on
+ * if 'return_parent' is set).
  */
-nvlist_t *
-zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
-    boolean_t *l2cache, boolean_t *log)
+static nvlist_t *
+__zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
+    boolean_t *l2cache, boolean_t *log, boolean_t return_parent)
 {
        char *end;
        nvlist_t *nvroot, *search, *ret;
@@ -3150,12 +3167,30 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
        *l2cache = B_FALSE;
        if (log != NULL)
                *log = B_FALSE;
-       ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
+       ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log,
+           return_parent);
        fnvlist_free(search);
 
        return (ret);
 }
 
+nvlist_t *
+zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
+    boolean_t *l2cache, boolean_t *log)
+{
+       return (__zpool_find_vdev(zhp, path, avail_spare, l2cache, log,
+           B_FALSE));
+}
+
+/* Given a vdev path, return its parent's nvlist */
+nvlist_t *
+zpool_find_parent_vdev(zpool_handle_t *zhp, const char *path,
+    boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
+{
+       return (__zpool_find_vdev(zhp, path, avail_spare, l2cache, log,
+           B_TRUE));
+}
+
 /*
  * Convert a vdev path to a GUID.  Returns GUID or 0 on error.
  *