diff options
author | Tony Hutter <[email protected]> | 2023-12-21 10:53:16 -0800 |
---|---|---|
committer | Tony Hutter <[email protected]> | 2024-01-29 15:12:06 -0800 |
commit | 69142125d75b7405e0f1cf141dbe7913448daedf (patch) | |
tree | 26de02691ede11de6ea1fe6e772920a309d450dc /lib | |
parent | 59112ca27d94edd793dbfda6ed5d2fc7a97dddaa (diff) |
zpool: Add slot power control, print power status
Add `zpool` flags to control the slot power to drives. This assumes
your SAS or NVMe enclosure supports slot power control via sysfs.
The new `--power` flag is added to `zpool offline|online|clear`:
zpool offline --power <pool> <device> Turn off device slot power
zpool online --power <pool> <device> Turn on device slot power
zpool clear --power <pool> [device] Turn on device slot power
If the ZPOOL_AUTO_POWER_ON_SLOT env var is set, then the '--power'
option is automatically implied for `zpool online` and `zpool clear`
and does not need to be passed.
zpool status also gets a --power option to print the slot power status.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Mart Frauenlob <[email protected]>
Signed-off-by: Tony Hutter <[email protected]>
Closes #15662
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libzfs/libzfs.abi | 97 | ||||
-rw-r--r-- | lib/libzfs/libzfs_pool.c | 49 | ||||
-rw-r--r-- | lib/libzutil/os/linux/zutil_import_os.c | 40 | ||||
-rw-r--r-- | lib/libzutil/zutil_import.c | 98 | ||||
-rw-r--r-- | lib/libzutil/zutil_pool.c | 31 |
5 files changed, 283 insertions, 32 deletions
diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 3c975397e..9bb8f6a47 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -179,6 +179,7 @@ <elf-symbol name='fletcher_4_native' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='fletcher_4_native_varsize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='fletcher_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='fsleep' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='get_dataset_depth' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='get_system_hostid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='getexecname' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -466,6 +467,7 @@ <elf-symbol name='zpool_disable_datasets_os' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_disable_volume_os' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_discard_checkpoint' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zpool_disk_wait' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_dump_ddt' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_enable_datasets' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_events_clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -497,6 +499,7 @@ <elf-symbol name='zpool_get_userprop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_get_vdev_prop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_get_vdev_prop_value' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zpool_getenv_int' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_history_unpack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_import' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_import_props' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -567,6 +570,7 @@ <elf-symbol name='zpool_vdev_remove_wanted' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_vdev_script_alloc_env' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_vdev_script_free_env' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zpool_vdev_set_removed_state' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_vdev_split' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_wait' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_wait_status' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -1402,8 +1406,6 @@ <qualified-type-def type-id='0897719a' const='yes' id='c4a7b189'/> <pointer-type-def type-id='c4a7b189' size-in-bits='64' id='36fca399'/> <qualified-type-def type-id='36fca399' restrict='yes' id='37e4897b'/> - <qualified-type-def type-id='a9c79a1f' const='yes' id='cd087e36'/> - <pointer-type-def type-id='cd087e36' size-in-bits='64' id='e05e8614'/> <qualified-type-def type-id='e05e8614' restrict='yes' id='0be2e71c'/> <pointer-type-def type-id='8037c762' size-in-bits='64' id='d74a6869'/> <qualified-type-def type-id='7292109c' restrict='yes' id='6942f6a4'/> @@ -6355,6 +6357,12 @@ <parameter type-id='9d774e0b' name='aux'/> <return type-id='95e97e5e'/> </function-decl> + <function-decl name='zpool_vdev_set_removed_state' mangled-name='zpool_vdev_set_removed_state' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_vdev_set_removed_state'> + <parameter type-id='4c81de99' name='zhp'/> + <parameter type-id='9c313c2d' name='guid'/> + <parameter type-id='9d774e0b' name='aux'/> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='zpool_vdev_attach' mangled-name='zpool_vdev_attach' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_vdev_attach'> <parameter type-id='4c81de99' name='zhp'/> <parameter type-id='80f4b756' name='old_disk'/> @@ -7588,6 +7596,12 @@ <qualified-type-def type-id='d33f11cb' restrict='yes' id='5c53ba29'/> <pointer-type-def type-id='ffa52b96' size-in-bits='64' id='76c8174b'/> <pointer-type-def type-id='f3d87113' size-in-bits='64' id='0d2a0670'/> + <function-decl name='zpool_label_disk' mangled-name='zpool_label_disk' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_label_disk'> + <parameter type-id='b0382bb3'/> + <parameter type-id='4c81de99'/> + <parameter type-id='80f4b756'/> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='zfs_version_kernel' mangled-name='zfs_version_kernel' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_version_kernel'> <return type-id='26a90f95'/> </function-decl> @@ -7597,6 +7611,10 @@ <function-decl name='libzfs_core_fini' visibility='default' binding='global' size-in-bits='64'> <return type-id='48b5725f'/> </function-decl> + <function-decl name='zfs_get_underlying_path' mangled-name='zfs_get_underlying_path' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_get_underlying_path'> + <parameter type-id='80f4b756'/> + <return type-id='26a90f95'/> + </function-decl> <function-decl name='zpool_prop_unsupported' mangled-name='zpool_prop_unsupported' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prop_unsupported'> <parameter type-id='80f4b756'/> <return type-id='c19b74c3'/> @@ -7714,6 +7732,11 @@ <parameter type-id='b59d7dce'/> <return type-id='95e97e5e'/> </function-decl> + <function-decl name='access' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='80f4b756'/> + <parameter type-id='95e97e5e'/> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='dup2' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='95e97e5e'/> <parameter type-id='95e97e5e'/> @@ -7881,6 +7904,37 @@ <parameter is-variadic='yes'/> <return type-id='95e97e5e'/> </function-decl> + <function-decl name='zpool_vdev_script_alloc_env' mangled-name='zpool_vdev_script_alloc_env' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_vdev_script_alloc_env'> + <parameter type-id='80f4b756' name='pool_name'/> + <parameter type-id='80f4b756' name='vdev_path'/> + <parameter type-id='80f4b756' name='vdev_upath'/> + <parameter type-id='80f4b756' name='vdev_enc_sysfs_path'/> + <parameter type-id='80f4b756' name='opt_key'/> + <parameter type-id='80f4b756' name='opt_val'/> + <return type-id='9b23c9ad'/> + </function-decl> + <function-decl name='zpool_vdev_script_free_env' mangled-name='zpool_vdev_script_free_env' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_vdev_script_free_env'> + <parameter type-id='9b23c9ad' name='env'/> + <return type-id='48b5725f'/> + </function-decl> + <function-decl name='zpool_prepare_disk' mangled-name='zpool_prepare_disk' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prepare_disk'> + <parameter type-id='4c81de99' name='zhp'/> + <parameter type-id='5ce45b60' name='vdev_nv'/> + <parameter type-id='80f4b756' name='prepare_str'/> + <parameter type-id='c0563f85' name='lines'/> + <parameter type-id='7292109c' name='lines_cnt'/> + <return type-id='95e97e5e'/> + </function-decl> + <function-decl name='zpool_prepare_and_label_disk' mangled-name='zpool_prepare_and_label_disk' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prepare_and_label_disk'> + <parameter type-id='b0382bb3' name='hdl'/> + <parameter type-id='4c81de99' name='zhp'/> + <parameter type-id='80f4b756' name='name'/> + <parameter type-id='5ce45b60' name='vdev_nv'/> + <parameter type-id='80f4b756' name='prepare_str'/> + <parameter type-id='c0563f85' name='lines'/> + <parameter type-id='7292109c' name='lines_cnt'/> + <return type-id='95e97e5e'/> + </function-decl> </abi-instr> <abi-instr address-size='64' path='lib/libzfs/os/linux/libzfs_mount_os.c' language='LANG_C99'> <pointer-type-def type-id='7359adad' size-in-bits='64' id='1d2c2b85'/> @@ -8070,12 +8124,6 @@ <parameter type-id='95e97e5e'/> <return type-id='95e97e5e'/> </function-decl> - <function-decl name='zpool_label_disk' mangled-name='zpool_label_disk' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_label_disk'> - <parameter type-id='b0382bb3' name='hdl'/> - <parameter type-id='4c81de99' name='zhp'/> - <parameter type-id='80f4b756' name='name'/> - <return type-id='95e97e5e'/> - </function-decl> </abi-instr> <abi-instr address-size='64' path='lib/libzfs/os/linux/libzfs_util_os.c' language='LANG_C99'> <class-decl name='itimerspec' size-in-bits='256' is-struct='yes' visibility='default' id='acbdbcc6'> @@ -8102,11 +8150,6 @@ <pointer-type-def type-id='4ba62af7' size-in-bits='64' id='f39579e7'/> <pointer-type-def type-id='acbdbcc6' size-in-bits='64' id='116842ac'/> <pointer-type-def type-id='b440e872' size-in-bits='64' id='3ac36db0'/> - <function-decl name='access' visibility='default' binding='global' size-in-bits='64'> - <parameter type-id='80f4b756'/> - <parameter type-id='95e97e5e'/> - <return type-id='95e97e5e'/> - </function-decl> <function-decl name='__poll_chk' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='3ac36db0'/> <parameter type-id='555eef66'/> @@ -8191,10 +8234,6 @@ <parameter type-id='80f4b756' name='dev_name'/> <return type-id='c19b74c3'/> </function-decl> - <function-decl name='zfs_get_underlying_path' mangled-name='zfs_get_underlying_path' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_get_underlying_path'> - <parameter type-id='80f4b756' name='dev_name'/> - <return type-id='26a90f95'/> - </function-decl> <function-decl name='is_mpath_whole_disk' mangled-name='is_mpath_whole_disk' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='is_mpath_whole_disk'> <parameter type-id='80f4b756' name='path'/> <return type-id='c19b74c3'/> @@ -8330,6 +8369,10 @@ <parameter type-id='b59d7dce' name='buflen'/> <return type-id='95e97e5e'/> </function-decl> + <function-decl name='zpool_disk_wait' mangled-name='zpool_disk_wait' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_disk_wait'> + <parameter type-id='80f4b756' name='path'/> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='update_vdev_config_dev_sysfs_path' mangled-name='update_vdev_config_dev_sysfs_path' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='update_vdev_config_dev_sysfs_path'> <parameter type-id='5ce45b60' name='nv'/> <parameter type-id='80f4b756' name='path'/> @@ -8355,6 +8398,9 @@ <parameter type-id='95e97e5e'/> <return type-id='95e97e5e'/> </function-decl> + <function-decl name='clearenv' visibility='default' binding='global' size-in-bits='64'> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='zfs_setproctitle_init' mangled-name='zfs_setproctitle_init' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_setproctitle_init'> <parameter type-id='95e97e5e' name='argc'/> <parameter type-id='9b23c9ad' name='argv'/> @@ -8628,6 +8674,7 @@ <array-type-def dimensions='1' type-id='853fd5dc' size-in-bits='32768' id='b505fc2f'> <subrange length='64' type-id='7359adad' id='b10be967'/> </array-type-def> + <type-decl name='float' size-in-bits='32' id='a6c45d85'/> <class-decl name='ddt_stat' size-in-bits='512' is-struct='yes' visibility='default' id='65242dfe'> <data-member access='public' layout-offset-in-bits='0'> <var-decl name='dds_blocks' type-id='9c313c2d' visibility='default'/> @@ -8665,11 +8712,27 @@ <pointer-type-def type-id='ec92d602' size-in-bits='64' id='932720f8'/> <qualified-type-def type-id='853fd5dc' const='yes' id='764c298c'/> <pointer-type-def type-id='764c298c' size-in-bits='64' id='dfe59052'/> + <qualified-type-def type-id='a9c79a1f' const='yes' id='cd087e36'/> + <pointer-type-def type-id='cd087e36' size-in-bits='64' id='e05e8614'/> + <function-decl name='nanosleep' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='e05e8614'/> + <parameter type-id='3d83ba87'/> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='zpool_dump_ddt' mangled-name='zpool_dump_ddt' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_dump_ddt'> <parameter type-id='dfe59052' name='dds_total'/> <parameter type-id='932720f8' name='ddh'/> <return type-id='48b5725f'/> </function-decl> + <function-decl name='fsleep' mangled-name='fsleep' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='fsleep'> + <parameter type-id='a6c45d85' name='sec'/> + <return type-id='48b5725f'/> + </function-decl> + <function-decl name='zpool_getenv_int' mangled-name='zpool_getenv_int' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_getenv_int'> + <parameter type-id='80f4b756' name='env'/> + <parameter type-id='95e97e5e' name='default_val'/> + <return type-id='95e97e5e'/> + </function-decl> </abi-instr> <abi-instr address-size='64' path='module/avl/avl.c' language='LANG_C99'> <function-decl name='avl_last' mangled-name='avl_last' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='avl_last'> diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 4ebd112f4..2f9ccbc2a 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -3036,6 +3036,9 @@ zpool_vdev_is_interior(const char *name) return (B_FALSE); } +/* + * Lookup the nvlist for a given vdev. + */ nvlist_t * zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) @@ -3043,6 +3046,7 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, char *end; nvlist_t *nvroot, *search, *ret; uint64_t guid; + boolean_t __avail_spare, __l2cache, __log; search = fnvlist_alloc(); @@ -3058,6 +3062,18 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, nvroot = fnvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE); + /* + * User can pass NULL for avail_spare, l2cache, and log, but + * we still need to provide variables to vdev_to_nvlist_iter(), so + * just point them to junk variables here. + */ + if (!avail_spare) + avail_spare = &__avail_spare; + if (!l2cache) + l2cache = &__l2cache; + if (!log) + log = &__log; + *avail_spare = B_FALSE; *l2cache = B_FALSE; if (log != NULL) @@ -3313,21 +3329,23 @@ zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) } /* - * Mark the given vdev degraded. + * Generic set vdev state function */ -int -zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) +static int +zpool_vdev_set_state(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux, + vdev_state_t state) { zfs_cmd_t zc = {"\0"}; char errbuf[ERRBUFLEN]; libzfs_handle_t *hdl = zhp->zpool_hdl; (void) snprintf(errbuf, sizeof (errbuf), - dgettext(TEXT_DOMAIN, "cannot degrade %llu"), (u_longlong_t)guid); + dgettext(TEXT_DOMAIN, "cannot set %s %llu"), + zpool_state_to_name(state, aux), (u_longlong_t)guid); (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); zc.zc_guid = guid; - zc.zc_cookie = VDEV_STATE_DEGRADED; + zc.zc_cookie = state; zc.zc_obj = aux; if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) @@ -3337,6 +3355,27 @@ zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) } /* + * Mark the given vdev degraded. + */ +int +zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) +{ + return (zpool_vdev_set_state(zhp, guid, aux, VDEV_STATE_DEGRADED)); +} + +/* + * Mark the given vdev as in a removed state (as if the device does not exist). + * + * This is different than zpool_vdev_remove() which does a removal of a device + * from the pool (but the device does exist). + */ +int +zpool_vdev_set_removed_state(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) +{ + return (zpool_vdev_set_state(zhp, guid, aux, VDEV_STATE_REMOVED)); +} + +/* * Returns TRUE if the given nvlist is a vdev that was originally swapped in as * a hot spare. */ diff --git a/lib/libzutil/os/linux/zutil_import_os.c b/lib/libzutil/os/linux/zutil_import_os.c index fbfae4f7e..bb91dec5a 100644 --- a/lib/libzutil/os/linux/zutil_import_os.c +++ b/lib/libzutil/os/linux/zutil_import_os.c @@ -170,25 +170,17 @@ zpool_open_func(void *arg) if (rn->rn_labelpaths) { const char *path = NULL; const char *devid = NULL; - const char *env = NULL; rdsk_node_t *slice; avl_index_t where; - int timeout; int error; if (label_paths(rn->rn_hdl, rn->rn_config, &path, &devid)) return; - env = getenv("ZPOOL_IMPORT_UDEV_TIMEOUT_MS"); - if ((env == NULL) || sscanf(env, "%d", &timeout) != 1 || - timeout < 0) { - timeout = DISK_LABEL_WAIT; - } - /* * Allow devlinks to stabilize so all paths are available. */ - zpool_label_disk_wait(rn->rn_name, timeout); + zpool_disk_wait(rn->rn_name); if (path != NULL) { slice = zutil_alloc(hdl, sizeof (rdsk_node_t)); @@ -683,6 +675,20 @@ zpool_label_disk_wait(const char *path, int timeout_ms) } /* + * Simplified version of zpool_label_disk_wait() where we wait for a device + * to appear using the default timeouts. + */ +int +zpool_disk_wait(const char *path) +{ + int timeout; + timeout = zpool_getenv_int("ZPOOL_IMPORT_UDEV_TIMEOUT_MS", + DISK_LABEL_WAIT); + + return (zpool_label_disk_wait(path, timeout)); +} + +/* * Encode the persistent devices strings * used for the vdev disk label */ @@ -767,6 +773,10 @@ no_dev: * in the nvlist * (if applicable). Like: * vdev_enc_sysfs_path: '/sys/class/enclosure/11:0:1:0/SLOT 4' * + * If an old path was in the nvlist, and the rescan can not find a new path, + * then keep the old path, since the disk may have been removed. + * + * path: The vdev path (value from ZPOOL_CONFIG_PATH) * key: The nvlist_t name (like ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH) */ void @@ -774,6 +784,9 @@ update_vdev_config_dev_sysfs_path(nvlist_t *nv, const char *path, const char *key) { char *upath, *spath; + const char *oldpath = NULL; + + (void) nvlist_lookup_string(nv, key, &oldpath); /* Add enclosure sysfs path (if disk is in an enclosure). */ upath = zfs_get_underlying_path(path); @@ -782,7 +795,14 @@ update_vdev_config_dev_sysfs_path(nvlist_t *nv, const char *path, if (spath) { (void) nvlist_add_string(nv, key, spath); } else { - (void) nvlist_remove_all(nv, key); + /* + * We couldn't dynamically scan the disk's enclosure sysfs path. + * This could be because the disk went away. If there's an old + * enclosure sysfs path in the nvlist, then keep using it. + */ + if (!oldpath) { + (void) nvlist_remove_all(nv, key); + } } free(upath); diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index f7ef69a1d..eb9131190 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -1922,6 +1922,104 @@ zpool_find_config(libpc_handle_t *hdl, const char *target, nvlist_t **configp, return (0); } +/* Return if a vdev is a leaf vdev. Note: draid spares are leaf vdevs. */ +static boolean_t +vdev_is_leaf(nvlist_t *nv) +{ + uint_t children = 0; + nvlist_t **child; + + (void) nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, + &child, &children); + + return (children == 0); +} + +/* Return if a vdev is a leaf vdev and a real device (disk or file) */ +static boolean_t +vdev_is_real_leaf(nvlist_t *nv) +{ + const char *type = NULL; + if (!vdev_is_leaf(nv)) + return (B_FALSE); + + (void) nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type); + if ((strcmp(type, VDEV_TYPE_DISK) == 0) || + (strcmp(type, VDEV_TYPE_FILE) == 0)) { + return (B_TRUE); + } + + return (B_FALSE); +} + +/* + * This function is called by our FOR_EACH_VDEV() macros. + * + * state: State machine status (stored inside of a (nvlist_t *)) + * nv: The current vdev nvlist_t we are iterating over. + * last_nv: The previous vdev nvlist_t we returned to the user in + * the last iteration of FOR_EACH_VDEV(). We use it + * to find the next vdev nvlist_t we should return. + * real_leaves_only: Only return leaf vdevs. + * + * Returns 1 if we found the next vdev nvlist_t for this iteration. 0 if + * we're still searching for it. + */ +static int +__for_each_vdev_macro_helper_func(void *state, nvlist_t *nv, void *last_nv, + boolean_t real_leaves_only) +{ + enum {FIRST_NV = 0, NEXT_IS_MATCH = 1, STOP_LOOKING = 2}; + + /* The very first entry in the NV list is a special case */ + if (*((nvlist_t **)state) == (nvlist_t *)FIRST_NV) { + if (real_leaves_only && !vdev_is_real_leaf(nv)) + return (0); + + *((nvlist_t **)last_nv) = nv; + *((nvlist_t **)state) = (nvlist_t *)STOP_LOOKING; + return (1); + } + + /* + * We came across our last_nv, meaning the next one is the one we + * want + */ + if (nv == *((nvlist_t **)last_nv)) { + /* Next iteration of this function will return the nvlist_t */ + *((nvlist_t **)state) = (nvlist_t *)NEXT_IS_MATCH; + return (0); + } + + /* + * We marked NEXT_IS_MATCH on the previous iteration, so this is the one + * we want. + */ + if (*(nvlist_t **)state == (nvlist_t *)NEXT_IS_MATCH) { + if (real_leaves_only && !vdev_is_real_leaf(nv)) + return (0); + + *((nvlist_t **)last_nv) = nv; + *((nvlist_t **)state) = (nvlist_t *)STOP_LOOKING; + return (1); + } + + return (0); +} + +int +for_each_vdev_macro_helper_func(void *state, nvlist_t *nv, void *last_nv) +{ + return (__for_each_vdev_macro_helper_func(state, nv, last_nv, B_FALSE)); +} + +int +for_each_real_leaf_vdev_macro_helper_func(void *state, nvlist_t *nv, + void *last_nv) +{ + return (__for_each_vdev_macro_helper_func(state, nv, last_nv, B_TRUE)); +} + /* * Internal function for iterating over the vdevs. * diff --git a/lib/libzutil/zutil_pool.c b/lib/libzutil/zutil_pool.c index 288a0033c..86460de3f 100644 --- a/lib/libzutil/zutil_pool.c +++ b/lib/libzutil/zutil_pool.c @@ -28,6 +28,7 @@ #include <string.h> #include <sys/nvpair.h> #include <sys/fs/zfs.h> +#include <math.h> #include <libzutil.h> @@ -144,3 +145,33 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, *leftover = bytes_read; return (0); } + +/* + * Floating point sleep(). Allows you to pass in a floating point value for + * seconds. + */ +void +fsleep(float sec) +{ + struct timespec req; + req.tv_sec = floor(sec); + req.tv_nsec = (sec - (float)req.tv_sec) * NANOSEC; + nanosleep(&req, NULL); +} + +/* + * Get environment variable 'env' and return it as an integer. + * If 'env' is not set, then return 'default_val' instead. + */ +int +zpool_getenv_int(const char *env, int default_val) +{ + char *str; + int val; + str = getenv(env); + if ((str == NULL) || sscanf(str, "%d", &val) != 1 || + val < 0) { + val = default_val; + } + return (val); +} |