diff options
author | Allan Jude <[email protected]> | 2021-11-30 09:46:25 -0500 |
---|---|---|
committer | GitHub <[email protected]> | 2021-11-30 07:46:25 -0700 |
commit | 2a673e76a928cca4df7794cdcaa02e0be149c4da (patch) | |
tree | 016afa631bb0d98f55b01e93ab80842fe6ffda27 /lib/libzfs | |
parent | 5f64bf7fdeebfbad50e98c6cd0c3a361a9aecabc (diff) |
Vdev Properties Feature
Add properties, similar to pool properties, to each vdev.
This makes use of the existing per-vdev ZAP that was added as
part of device evacuation/removal.
A large number of read-only properties are exposed,
many of the members of struct vdev_t, that provide useful
statistics.
Adds support for read-only "removing" vdev property.
Adds the "allocating" property that defaults to "on" and
can be set to "off" to prevent future allocations from that
top-level vdev.
Supports user-defined vdev properties.
Includes support for properties.vdev in SYSFS.
Co-authored-by: Allan Jude <[email protected]>
Co-authored-by: Mark Maybee <[email protected]>
Reviewed-by: Matthew Ahrens <[email protected]>
Reviewed-by: Mark Maybee <[email protected]>
Signed-off-by: Allan Jude <[email protected]>
Closes #11711
Diffstat (limited to 'lib/libzfs')
-rw-r--r-- | lib/libzfs/libzfs.abi | 199 | ||||
-rw-r--r-- | lib/libzfs/libzfs_pool.c | 459 | ||||
-rw-r--r-- | lib/libzfs/libzfs_util.c | 40 | ||||
-rw-r--r-- | lib/libzfs/os/freebsd/libzfs_compat.c | 4 |
4 files changed, 687 insertions, 15 deletions
diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index ab6d27e91..8a696206a 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -259,6 +259,22 @@ <elf-symbol name='tpool_suspended' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='tpool_wait' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='update_vdev_config_dev_strs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_expand_proplist' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_name_to_prop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_align_right' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_column_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_default_numeric' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_default_string' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_get_table' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_get_type' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_index_to_string' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_random_value' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_readonly' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_string_to_index' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_to_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_user' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='vdev_prop_values' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zfeature_depends_on' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zfeature_is_supported' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zfeature_is_valid_guid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -463,6 +479,7 @@ <elf-symbol name='zpool_find_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'/> <elf-symbol name='zpool_get_bootenv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_get_config' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_get_errlog' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -477,6 +494,8 @@ <elf-symbol name='zpool_get_state' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_get_state_str' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_get_status' 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_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'/> @@ -514,6 +533,7 @@ <elf-symbol name='zpool_prop_to_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prop_unsupported' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prop_values' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zpool_prop_vdev' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_props_refresh' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_read_label' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_refresh_stats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -523,6 +543,7 @@ <elf-symbol name='zpool_search_import' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_set_bootenv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_set_prop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zpool_set_vdev_prop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_skip_pool' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_state_to_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_sync_one' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -557,6 +578,7 @@ <elf-symbol name='zprop_register_number' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zprop_register_string' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zprop_string_to_index' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zprop_valid_char' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zprop_valid_for_type' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zprop_values' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zprop_width' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -2683,6 +2705,73 @@ <parameter type-id='5d0c23fb' name='prop'/> <return type-id='c19b74c3'/> </function-decl> + <function-decl name='vdev_prop_get_table' mangled-name='vdev_prop_get_table' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_get_table'> + <return type-id='76c8174b'/> + </function-decl> + <function-decl name='vdev_prop_init' mangled-name='vdev_prop_init' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_init'> + <return type-id='48b5725f'/> + </function-decl> + <function-decl name='vdev_name_to_prop' mangled-name='vdev_name_to_prop' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_name_to_prop'> + <parameter type-id='80f4b756' name='propname'/> + <return type-id='5aa5c90c'/> + </function-decl> + <function-decl name='vdev_prop_user' mangled-name='vdev_prop_user' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_user'> + <parameter type-id='80f4b756' name='name'/> + <return type-id='c19b74c3'/> + </function-decl> + <function-decl name='vdev_prop_to_name' mangled-name='vdev_prop_to_name' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_to_name'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='80f4b756'/> + </function-decl> + <function-decl name='vdev_prop_get_type' mangled-name='vdev_prop_get_type' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_get_type'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='31429eff'/> + </function-decl> + <function-decl name='vdev_prop_readonly' mangled-name='vdev_prop_readonly' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_readonly'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='c19b74c3'/> + </function-decl> + <function-decl name='vdev_prop_default_string' mangled-name='vdev_prop_default_string' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_default_string'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='80f4b756'/> + </function-decl> + <function-decl name='vdev_prop_default_numeric' mangled-name='vdev_prop_default_numeric' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_default_numeric'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='9c313c2d'/> + </function-decl> + <function-decl name='vdev_prop_string_to_index' mangled-name='vdev_prop_string_to_index' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_string_to_index'> + <parameter type-id='5aa5c90c' name='prop'/> + <parameter type-id='80f4b756' name='string'/> + <parameter type-id='5d6479ae' name='index'/> + <return type-id='95e97e5e'/> + </function-decl> + <function-decl name='vdev_prop_index_to_string' mangled-name='vdev_prop_index_to_string' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_index_to_string'> + <parameter type-id='5aa5c90c' name='prop'/> + <parameter type-id='9c313c2d' name='index'/> + <parameter type-id='7d3cd834' name='string'/> + <return type-id='95e97e5e'/> + </function-decl> + <function-decl name='zpool_prop_vdev' mangled-name='zpool_prop_vdev' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prop_vdev'> + <parameter type-id='80f4b756' name='name'/> + <return type-id='c19b74c3'/> + </function-decl> + <function-decl name='vdev_prop_random_value' mangled-name='vdev_prop_random_value' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_random_value'> + <parameter type-id='5aa5c90c' name='prop'/> + <parameter type-id='9c313c2d' name='seed'/> + <return type-id='9c313c2d'/> + </function-decl> + <function-decl name='vdev_prop_values' mangled-name='vdev_prop_values' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_values'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='80f4b756'/> + </function-decl> + <function-decl name='vdev_prop_column_name' mangled-name='vdev_prop_column_name' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_column_name'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='80f4b756'/> + </function-decl> + <function-decl name='vdev_prop_align_right' mangled-name='vdev_prop_align_right' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_prop_align_right'> + <parameter type-id='5aa5c90c' name='prop'/> + <return type-id='c19b74c3'/> + </function-decl> </abi-instr> <abi-instr address-size='64' path='../../module/zcommon/zprop_common.c' language='LANG_C99'> <function-decl name='zprop_register_impl' mangled-name='zprop_register_impl' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zprop_register_impl'> @@ -2784,6 +2873,10 @@ <parameter type-id='c19b74c3' name='headcheck'/> <return type-id='c19b74c3'/> </function-decl> + <function-decl name='zprop_valid_char' mangled-name='zprop_valid_char' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zprop_valid_char'> + <parameter type-id='a84c031d' name='c'/> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='zprop_width' mangled-name='zprop_width' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zprop_width'> <parameter type-id='95e97e5e' name='prop'/> <parameter type-id='37e3bd22' name='fixed'/> @@ -2886,6 +2979,7 @@ <enumerator name='ZFS_TYPE_VOLUME' value='4'/> <enumerator name='ZFS_TYPE_POOL' value='8'/> <enumerator name='ZFS_TYPE_BOOKMARK' value='16'/> + <enumerator name='ZFS_TYPE_VDEV' value='32'/> </enum-decl> <typedef-decl name='zfs_type_t' type-id='5d8f7321' id='2e45de5d'/> <enum-decl name='dmu_objset_type' id='6b1b19f9'> @@ -4216,6 +4310,53 @@ <enumerator name='ZPOOL_NUM_PROPS' value='33'/> </enum-decl> <typedef-decl name='zpool_prop_t' type-id='af1ba157' id='5d0c23fb'/> + <enum-decl name='vdev_prop_t' naming-typedef-id='5aa5c90c' id='1573bec8'> + <underlying-type type-id='9cac1fee'/> + <enumerator name='VDEV_PROP_INVAL' value='-1'/> + <enumerator name='VDEV_PROP_NAME' value='0'/> + <enumerator name='VDEV_PROP_CAPACITY' value='1'/> + <enumerator name='VDEV_PROP_STATE' value='2'/> + <enumerator name='VDEV_PROP_GUID' value='3'/> + <enumerator name='VDEV_PROP_ASIZE' value='4'/> + <enumerator name='VDEV_PROP_PSIZE' value='5'/> + <enumerator name='VDEV_PROP_ASHIFT' value='6'/> + <enumerator name='VDEV_PROP_SIZE' value='7'/> + <enumerator name='VDEV_PROP_FREE' value='8'/> + <enumerator name='VDEV_PROP_ALLOCATED' value='9'/> + <enumerator name='VDEV_PROP_COMMENT' value='10'/> + <enumerator name='VDEV_PROP_EXPANDSZ' value='11'/> + <enumerator name='VDEV_PROP_FRAGMENTATION' value='12'/> + <enumerator name='VDEV_PROP_BOOTSIZE' value='13'/> + <enumerator name='VDEV_PROP_PARITY' value='14'/> + <enumerator name='VDEV_PROP_PATH' value='15'/> + <enumerator name='VDEV_PROP_DEVID' value='16'/> + <enumerator name='VDEV_PROP_PHYS_PATH' value='17'/> + <enumerator name='VDEV_PROP_ENC_PATH' value='18'/> + <enumerator name='VDEV_PROP_FRU' value='19'/> + <enumerator name='VDEV_PROP_PARENT' value='20'/> + <enumerator name='VDEV_PROP_CHILDREN' value='21'/> + <enumerator name='VDEV_PROP_NUMCHILDREN' value='22'/> + <enumerator name='VDEV_PROP_READ_ERRORS' value='23'/> + <enumerator name='VDEV_PROP_WRITE_ERRORS' value='24'/> + <enumerator name='VDEV_PROP_CHECKSUM_ERRORS' value='25'/> + <enumerator name='VDEV_PROP_INITIALIZE_ERRORS' value='26'/> + <enumerator name='VDEV_PROP_OPS_NULL' value='27'/> + <enumerator name='VDEV_PROP_OPS_READ' value='28'/> + <enumerator name='VDEV_PROP_OPS_WRITE' value='29'/> + <enumerator name='VDEV_PROP_OPS_FREE' value='30'/> + <enumerator name='VDEV_PROP_OPS_CLAIM' value='31'/> + <enumerator name='VDEV_PROP_OPS_TRIM' value='32'/> + <enumerator name='VDEV_PROP_BYTES_NULL' value='33'/> + <enumerator name='VDEV_PROP_BYTES_READ' value='34'/> + <enumerator name='VDEV_PROP_BYTES_WRITE' value='35'/> + <enumerator name='VDEV_PROP_BYTES_FREE' value='36'/> + <enumerator name='VDEV_PROP_BYTES_CLAIM' value='37'/> + <enumerator name='VDEV_PROP_BYTES_TRIM' value='38'/> + <enumerator name='VDEV_PROP_REMOVING' value='39'/> + <enumerator name='VDEV_PROP_ALLOCATING' value='40'/> + <enumerator name='VDEV_NUM_PROPS' value='41'/> + </enum-decl> + <typedef-decl name='vdev_prop_t' type-id='1573bec8' id='5aa5c90c'/> <enum-decl name='vdev_state' id='21566197'> <underlying-type type-id='9cac1fee'/> <enumerator name='VDEV_STATE_UNKNOWN' value='0'/> @@ -4342,9 +4483,16 @@ <function-decl name='zpool_expand_proplist' mangled-name='zpool_expand_proplist' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_expand_proplist'> <parameter type-id='4c81de99' name='zhp'/> <parameter type-id='e4378506' name='plp'/> + <parameter type-id='2e45de5d' name='type'/> <parameter type-id='c19b74c3' name='literal'/> <return type-id='95e97e5e'/> </function-decl> + <function-decl name='vdev_expand_proplist' mangled-name='vdev_expand_proplist' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='vdev_expand_proplist'> + <parameter type-id='4c81de99' name='zhp'/> + <parameter type-id='80f4b756' name='vdevname'/> + <parameter type-id='e4378506' name='plp'/> + <return type-id='95e97e5e'/> + </function-decl> <function-decl name='zpool_prop_get_feature' mangled-name='zpool_prop_get_feature' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prop_get_feature'> <parameter type-id='4c81de99' name='zhp'/> <parameter type-id='80f4b756' name='propname'/> @@ -4680,6 +4828,40 @@ <parameter type-id='b59d7dce' name='rlen'/> <return type-id='901b78d1'/> </function-decl> + <function-decl name='zpool_get_vdev_prop_value' mangled-name='zpool_get_vdev_prop_value' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_get_vdev_prop_value'> + <parameter type-id='5ce45b60' name='nvprop'/> + <parameter type-id='5aa5c90c' name='prop'/> + <parameter type-id='26a90f95' name='prop_name'/> + <parameter type-id='26a90f95' name='buf'/> + <parameter type-id='b59d7dce' name='len'/> + <parameter type-id='debc6aa3' name='srctype'/> + <parameter type-id='c19b74c3' name='literal'/> + <return type-id='95e97e5e'/> + </function-decl> + <function-decl name='zpool_get_vdev_prop' mangled-name='zpool_get_vdev_prop' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_get_vdev_prop'> + <parameter type-id='4c81de99' name='zhp'/> + <parameter type-id='80f4b756' name='vdevname'/> + <parameter type-id='5aa5c90c' name='prop'/> + <parameter type-id='26a90f95' name='prop_name'/> + <parameter type-id='26a90f95' name='buf'/> + <parameter type-id='b59d7dce' name='len'/> + <parameter type-id='debc6aa3' name='srctype'/> + <parameter type-id='c19b74c3' name='literal'/> + <return type-id='95e97e5e'/> + </function-decl> + <function-decl name='zpool_get_all_vdev_props' mangled-name='zpool_get_all_vdev_props' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_get_all_vdev_props'> + <parameter type-id='4c81de99' name='zhp'/> + <parameter type-id='80f4b756' name='vdevname'/> + <parameter type-id='857bb57e' name='outnvl'/> + <return type-id='95e97e5e'/> + </function-decl> + <function-decl name='zpool_set_vdev_prop' mangled-name='zpool_set_vdev_prop' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_set_vdev_prop'> + <parameter type-id='4c81de99' name='zhp'/> + <parameter type-id='80f4b756' name='vdevname'/> + <parameter type-id='80f4b756' name='propname'/> + <parameter type-id='80f4b756' name='propval'/> + <return type-id='95e97e5e'/> + </function-decl> </abi-instr> <abi-instr address-size='64' path='libzfs_sendrecv.c' language='LANG_C99'> <class-decl name='sendflags' size-in-bits='544' is-struct='yes' visibility='default' id='f6aa15be'> @@ -4922,7 +5104,19 @@ <enumerator name='GET_COL_SOURCE' value='5'/> </enum-decl> <typedef-decl name='zfs_get_column_t' type-id='223bdcaa' id='19cefcee'/> - <class-decl name='zprop_get_cbdata' size-in-bits='640' is-struct='yes' visibility='default' id='f3d3c319'> + <class-decl name='vdev_cbdata' size-in-bits='192' is-struct='yes' visibility='default' id='b8006be8'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='cb_name_flags' type-id='95e97e5e' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='cb_names' type-id='9b23c9ad' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='cb_names_count' type-id='f0981eeb' visibility='default'/> + </data-member> + </class-decl> + <typedef-decl name='vdev_cbdata_t' type-id='b8006be8' id='a9679c94'/> + <class-decl name='zprop_get_cbdata' size-in-bits='832' is-struct='yes' visibility='default' id='f3d3c319'> <data-member access='public' layout-offset-in-bits='0'> <var-decl name='cb_sources' type-id='95e97e5e' visibility='default'/> </data-member> @@ -4947,6 +5141,9 @@ <data-member access='public' layout-offset-in-bits='576'> <var-decl name='cb_type' type-id='2e45de5d' visibility='default'/> </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='cb_vdevs' type-id='a9679c94' visibility='default'/> + </data-member> </class-decl> <typedef-decl name='zprop_get_cbdata_t' type-id='f3d3c319' id='f3d87113'/> <typedef-decl name='zprop_func' type-id='2e711a2a' id='1ec3747a'/> diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 8ed96275c..6e302ad4b 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -29,6 +29,7 @@ * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2018, loli10K <[email protected]> * Copyright (c) 2021, Colm Buckley <[email protected]> + * Copyright (c) 2021, Klara Inc. */ #include <errno.h> @@ -61,6 +62,7 @@ static boolean_t zpool_vdev_is_interior(const char *name); typedef struct prop_flags { int create:1; /* Validate property on creation */ int import:1; /* Validate property on import */ + int vdevprop:1; /* Validate property as a VDEV property */ } prop_flags_t; /* @@ -478,6 +480,35 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { const char *propname = nvpair_name(elem); + if (flags.vdevprop && zpool_prop_vdev(propname)) { + vdev_prop_t vprop = vdev_name_to_prop(propname); + + if (vdev_prop_readonly(vprop)) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " + "is readonly"), propname); + (void) zfs_error(hdl, EZFS_PROPREADONLY, + errbuf); + goto error; + } + + if (zprop_parse_value(hdl, elem, vprop, ZFS_TYPE_VDEV, + retprops, &strval, &intval, errbuf) != 0) + goto error; + + continue; + } else if (flags.vdevprop && vdev_prop_user(propname)) { + if (nvlist_add_nvpair(retprops, elem) != 0) { + (void) no_memory(hdl); + goto error; + } + continue; + } else if (flags.vdevprop) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "invalid property: '%s'"), propname); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + } + prop = zpool_name_to_prop(propname); if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) { int err; @@ -806,7 +837,7 @@ zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) int zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp, - boolean_t literal) + zfs_type_t type, boolean_t literal) { libzfs_handle_t *hdl = zhp->zpool_hdl; zprop_list_t *entry; @@ -817,9 +848,12 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp, boolean_t firstexpand = (NULL == *plp); int i; - if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) + if (zprop_expand_list(hdl, plp, type) != 0) return (-1); + if (type == ZFS_TYPE_VDEV) + return (0); + last = plp; while (*last != NULL) last = &(*last)->pl_next; @@ -899,6 +933,77 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp, return (0); } +int +vdev_expand_proplist(zpool_handle_t *zhp, const char *vdevname, + zprop_list_t **plp) +{ + zprop_list_t *entry; + char buf[ZFS_MAXPROPLEN]; + char *strval = NULL; + int err = 0; + nvpair_t *elem = NULL; + nvlist_t *vprops = NULL; + nvlist_t *propval = NULL; + const char *propname; + vdev_prop_t prop; + zprop_list_t **last; + + for (entry = *plp; entry != NULL; entry = entry->pl_next) { + if (entry->pl_fixed) + continue; + + if (zpool_get_vdev_prop(zhp, vdevname, entry->pl_prop, + entry->pl_user_prop, buf, sizeof (buf), NULL, + B_FALSE) == 0) { + if (strlen(buf) > entry->pl_width) + entry->pl_width = strlen(buf); + } + if (entry->pl_prop == VDEV_PROP_NAME && + strlen(vdevname) > entry->pl_width) + entry->pl_width = strlen(vdevname); + } + + /* Handle the all properties case */ + last = plp; + if (*last != NULL && (*last)->pl_all == B_TRUE) { + while (*last != NULL) + last = &(*last)->pl_next; + + err = zpool_get_all_vdev_props(zhp, vdevname, &vprops); + if (err != 0) + return (err); + + while ((elem = nvlist_next_nvpair(vprops, elem)) != NULL) { + propname = nvpair_name(elem); + + /* Skip properties that are not user defined */ + if ((prop = vdev_name_to_prop(propname)) != + VDEV_PROP_USER) + continue; + + if (nvpair_value_nvlist(elem, &propval) != 0) + continue; + + verify(nvlist_lookup_string(propval, ZPROP_VALUE, + &strval) == 0); + + if ((entry = zfs_alloc(zhp->zpool_hdl, + sizeof (zprop_list_t))) == NULL) + return (ENOMEM); + + entry->pl_prop = prop; + entry->pl_user_prop = zfs_strdup(zhp->zpool_hdl, + propname); + entry->pl_width = strlen(strval); + entry->pl_all = B_TRUE; + *last = entry; + last = &entry->pl_next; + } + } + + return (0); +} + /* * Get the state for the given feature on the given ZFS pool. */ @@ -4959,3 +5064,353 @@ zpool_load_compat(const char *compat, boolean_t *features, char *report, strlcpy(report, gettext("compatibility set ok"), rlen); return (ZPOOL_COMPATIBILITY_OK); } + +static int +zpool_vdev_guid(zpool_handle_t *zhp, const char *vdevname, uint64_t *vdev_guid) +{ + nvlist_t *tgt; + boolean_t avail_spare, l2cache; + + verify(zhp != NULL); + if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { + char errbuf[1024]; + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "pool is in an unavailable state")); + return (zfs_error(zhp->zpool_hdl, EZFS_POOLUNAVAIL, errbuf)); + } + + if ((tgt = zpool_find_vdev(zhp, vdevname, &avail_spare, &l2cache, + NULL)) == NULL) { + char errbuf[1024]; + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "can not find %s in %s"), + vdevname, zhp->zpool_name); + return (zfs_error(zhp->zpool_hdl, EZFS_NODEVICE, errbuf)); + } + + verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, vdev_guid) == 0); + return (0); +} + +/* + * Get a vdev property value for 'prop' and return the value in + * a pre-allocated buffer. + */ +int +zpool_get_vdev_prop_value(nvlist_t *nvprop, vdev_prop_t prop, char *prop_name, + char *buf, size_t len, zprop_source_t *srctype, boolean_t literal) +{ + nvlist_t *nv; + uint64_t intval; + char *strval; + zprop_source_t src = ZPROP_SRC_NONE; + + if (prop == VDEV_PROP_USER) { + /* user property, prop_name must contain the property name */ + assert(prop_name != NULL); + if (nvlist_lookup_nvlist(nvprop, prop_name, &nv) == 0) { + verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, + &intval) == 0); + src = intval; + verify(nvlist_lookup_string(nv, ZPROP_VALUE, + &strval) == 0); + } else { + /* user prop not found */ + return (-1); + } + (void) strlcpy(buf, strval, len); + if (srctype) + *srctype = src; + return (0); + } + + if (prop_name == NULL) + prop_name = (char *)vdev_prop_to_name(prop); + + switch (vdev_prop_get_type(prop)) { + case PROP_TYPE_STRING: + if (nvlist_lookup_nvlist(nvprop, prop_name, &nv) == 0) { + verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, + &intval) == 0); + src = intval; + verify(nvlist_lookup_string(nv, ZPROP_VALUE, + &strval) == 0); + } else { + src = ZPROP_SRC_DEFAULT; + if ((strval = (char *)vdev_prop_default_string(prop)) + == NULL) + strval = "-"; + } + (void) strlcpy(buf, strval, len); + break; + + case PROP_TYPE_NUMBER: + if (nvlist_lookup_nvlist(nvprop, prop_name, &nv) == 0) { + verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, + &intval) == 0); + src = intval; + verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, + &intval) == 0); + } else { + src = ZPROP_SRC_DEFAULT; + intval = vdev_prop_default_numeric(prop); + } + + switch (prop) { + case VDEV_PROP_ASIZE: + case VDEV_PROP_PSIZE: + case VDEV_PROP_SIZE: + case VDEV_PROP_ALLOCATED: + case VDEV_PROP_FREE: + case VDEV_PROP_READ_ERRORS: + case VDEV_PROP_WRITE_ERRORS: + case VDEV_PROP_CHECKSUM_ERRORS: + case VDEV_PROP_INITIALIZE_ERRORS: + case VDEV_PROP_OPS_NULL: + case VDEV_PROP_OPS_READ: + case VDEV_PROP_OPS_WRITE: + case VDEV_PROP_OPS_FREE: + case VDEV_PROP_OPS_CLAIM: + case VDEV_PROP_OPS_TRIM: + case VDEV_PROP_BYTES_NULL: + case VDEV_PROP_BYTES_READ: + case VDEV_PROP_BYTES_WRITE: + case VDEV_PROP_BYTES_FREE: + case VDEV_PROP_BYTES_CLAIM: + case VDEV_PROP_BYTES_TRIM: + if (literal) { + (void) snprintf(buf, len, "%llu", + (u_longlong_t)intval); + } else { + (void) zfs_nicenum(intval, buf, len); + } + break; + case VDEV_PROP_EXPANDSZ: + if (intval == 0) { + (void) strlcpy(buf, "-", len); + } else if (literal) { + (void) snprintf(buf, len, "%llu", + (u_longlong_t)intval); + } else { + (void) zfs_nicenum(intval, buf, len); + } + break; + case VDEV_PROP_CAPACITY: + if (literal) { + (void) snprintf(buf, len, "%llu", + (u_longlong_t)intval); + } else { + (void) snprintf(buf, len, "%llu%%", + (u_longlong_t)intval); + } + break; + case VDEV_PROP_FRAGMENTATION: + if (intval == UINT64_MAX) { + (void) strlcpy(buf, "-", len); + } else { + (void) snprintf(buf, len, "%llu%%", + (u_longlong_t)intval); + } + break; + case VDEV_PROP_STATE: + if (literal) { + (void) snprintf(buf, len, "%llu", + (u_longlong_t)intval); + } else { + (void) strlcpy(buf, zpool_state_to_name(intval, + VDEV_AUX_NONE), len); + } + break; + default: + (void) snprintf(buf, len, "%llu", + (u_longlong_t)intval); + } + break; + + case PROP_TYPE_INDEX: + if (nvlist_lookup_nvlist(nvprop, prop_name, &nv) == 0) { + verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, + &intval) == 0); + src = intval; + verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, + &intval) == 0); + } else { + src = ZPROP_SRC_DEFAULT; + intval = vdev_prop_default_numeric(prop); + } + if (vdev_prop_index_to_string(prop, intval, + (const char **)&strval) != 0) + return (-1); + (void) strlcpy(buf, strval, len); + break; + + default: + abort(); + } + + if (srctype) + *srctype = src; + + return (0); +} + +/* + * Get a vdev property value for 'prop_name' and return the value in + * a pre-allocated buffer. + */ +int +zpool_get_vdev_prop(zpool_handle_t *zhp, const char *vdevname, vdev_prop_t prop, + char *prop_name, char *buf, size_t len, zprop_source_t *srctype, + boolean_t literal) +{ + nvlist_t *reqnvl, *reqprops; + nvlist_t *retprops = NULL; + uint64_t vdev_guid; + int ret; + + if ((ret = zpool_vdev_guid(zhp, vdevname, &vdev_guid)) != 0) + return (ret); + + if (nvlist_alloc(&reqnvl, NV_UNIQUE_NAME, 0) != 0) + return (no_memory(zhp->zpool_hdl)); + if (nvlist_alloc(&reqprops, NV_UNIQUE_NAME, 0) != 0) + return (no_memory(zhp->zpool_hdl)); + + fnvlist_add_uint64(reqnvl, ZPOOL_VDEV_PROPS_GET_VDEV, vdev_guid); + + if (prop != VDEV_PROP_USER) { + /* prop_name overrides prop value */ + if (prop_name != NULL) + prop = vdev_name_to_prop(prop_name); + else + prop_name = (char *)vdev_prop_to_name(prop); + assert(prop < VDEV_NUM_PROPS); + } + + assert(prop_name != NULL); + if (nvlist_add_uint64(reqprops, prop_name, prop) != 0) { + nvlist_free(reqnvl); + nvlist_free(reqprops); + return (no_memory(zhp->zpool_hdl)); + } + + fnvlist_add_nvlist(reqnvl, ZPOOL_VDEV_PROPS_GET_PROPS, reqprops); + + ret = lzc_get_vdev_prop(zhp->zpool_name, reqnvl, &retprops); + + if (ret == 0) { + ret = zpool_get_vdev_prop_value(retprops, prop, prop_name, buf, + len, srctype, literal); + } else { + char errbuf[1024]; + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot get vdev property %s from" + " %s in %s"), prop_name, vdevname, zhp->zpool_name); + (void) zpool_standard_error(zhp->zpool_hdl, ret, errbuf); + } + + nvlist_free(reqnvl); + nvlist_free(reqprops); + nvlist_free(retprops); + + return (ret); +} + +/* + * Get all vdev properties + */ +int +zpool_get_all_vdev_props(zpool_handle_t *zhp, const char *vdevname, + nvlist_t **outnvl) +{ + nvlist_t *nvl = NULL; + uint64_t vdev_guid; + int ret; + + if ((ret = zpool_vdev_guid(zhp, vdevname, &vdev_guid)) != 0) + return (ret); + + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) + return (no_memory(zhp->zpool_hdl)); + + fnvlist_add_uint64(nvl, ZPOOL_VDEV_PROPS_GET_VDEV, vdev_guid); + + ret = lzc_get_vdev_prop(zhp->zpool_name, nvl, outnvl); + + nvlist_free(nvl); + + if (ret) { + char errbuf[1024]; + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot get vdev properties for" + " %s in %s"), vdevname, zhp->zpool_name); + (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); + } + + return (ret); +} + +/* + * Set vdev property + */ +int +zpool_set_vdev_prop(zpool_handle_t *zhp, const char *vdevname, + const char *propname, const char *propval) +{ + int ret; + vdev_prop_t vprop; + nvlist_t *nvl = NULL; + nvlist_t *outnvl = NULL; + nvlist_t *props; + nvlist_t *realprops; + prop_flags_t flags = { 0 }; + uint64_t version; + uint64_t vdev_guid; + + if ((ret = zpool_vdev_guid(zhp, vdevname, &vdev_guid)) != 0) + return (ret); + + vprop = vdev_name_to_prop(propname); + + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) + return (no_memory(zhp->zpool_hdl)); + if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) + return (no_memory(zhp->zpool_hdl)); + + fnvlist_add_uint64(nvl, ZPOOL_VDEV_PROPS_SET_VDEV, vdev_guid); + + if (nvlist_add_string(props, propname, propval) != 0) { + nvlist_free(props); + return (no_memory(zhp->zpool_hdl)); + } + + char errbuf[1024]; + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot set property %s for %s on %s"), + propname, vdevname, zhp->zpool_name); + + flags.vdevprop = 1; + version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); + if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, + zhp->zpool_name, props, version, flags, errbuf)) == NULL) { + nvlist_free(props); + nvlist_free(nvl); + return (-1); + } + + nvlist_free(props); + props = realprops; + + fnvlist_add_nvlist(nvl, ZPOOL_VDEV_PROPS_SET_PROPS, props); + + ret = lzc_set_vdev_prop(zhp->zpool_name, nvl, &outnvl); + + nvlist_free(props); + nvlist_free(nvl); + nvlist_free(outnvl); + + if (ret) + (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); + + return (ret); +} diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index c3c009ae3..b3f39afe2 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -296,6 +296,9 @@ libzfs_error_description(libzfs_handle_t *hdl) case EZFS_REBUILDING: return (dgettext(TEXT_DOMAIN, "currently sequentially " "resilvering")); + case EZFS_VDEV_NOTSUP: + return (dgettext(TEXT_DOMAIN, "operation not supported " + "on this type of vdev")); case EZFS_UNKNOWN: return (dgettext(TEXT_DOMAIN, "unknown error")); default: @@ -716,6 +719,9 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) case ZFS_ERR_BADPROP: zfs_verror(hdl, EZFS_BADPROP, fmt, ap); break; + case ZFS_ERR_VDEV_NOTSUP: + zfs_verror(hdl, EZFS_VDEV_NOTSUP, fmt, ap); + break; case ZFS_ERR_IOC_CMD_UNAVAIL: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs " "module does not support this operation. A reboot may " @@ -1034,6 +1040,7 @@ libzfs_init(void) zfs_prop_init(); zpool_prop_init(); zpool_feature_init(); + vdev_prop_init(); libzfs_mnttab_init(hdl); fletcher_4_init(); @@ -1267,7 +1274,8 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type) /* first property is always NAME */ assert(cbp->cb_proplist->pl_prop == - ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : ZFS_PROP_NAME)); + ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : + ((type == ZFS_TYPE_VDEV) ? VDEV_PROP_NAME : ZFS_PROP_NAME))); /* * Go through and calculate the widths for each column. For the @@ -1284,12 +1292,16 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type) if (pl->pl_prop != ZPROP_INVAL) { const char *propname = (type == ZFS_TYPE_POOL) ? zpool_prop_to_name(pl->pl_prop) : - zfs_prop_to_name(pl->pl_prop); + ((type == ZFS_TYPE_VDEV) ? + vdev_prop_to_name(pl->pl_prop) : + zfs_prop_to_name(pl->pl_prop)); + assert(propname != NULL); len = strlen(propname); if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) cbp->cb_colwidths[GET_COL_PROPERTY] = len; } else { + assert(pl->pl_user_prop != NULL); len = strlen(pl->pl_user_prop); if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) cbp->cb_colwidths[GET_COL_PROPERTY] = len; @@ -1314,9 +1326,10 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type) /* * 'NAME' and 'SOURCE' columns */ - if (pl->pl_prop == (type == ZFS_TYPE_POOL ? ZPOOL_PROP_NAME : - ZFS_PROP_NAME) && - pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) { + if (pl->pl_prop == ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : + ((type == ZFS_TYPE_VDEV) ? VDEV_PROP_NAME : + ZFS_PROP_NAME)) && pl->pl_width > + cbp->cb_colwidths[GET_COL_NAME]) { cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width; cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width + strlen(dgettext(TEXT_DOMAIN, "inherited from")); @@ -1597,6 +1610,9 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop, if (type == ZFS_TYPE_POOL) { proptype = zpool_prop_get_type(prop); propname = zpool_prop_to_name(prop); + } else if (type == ZFS_TYPE_VDEV) { + proptype = vdev_prop_get_type(prop); + propname = vdev_prop_to_name(prop); } else { proptype = zfs_prop_get_type(prop); propname = zfs_prop_to_name(prop); @@ -1747,15 +1763,15 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp, prop = ZPROP_INVAL; /* - * When no property table entry can be found, return failure if - * this is a pool property or if this isn't a user-defined - * dataset property, + * Return failure if no property table entry was found and this isn't + * a user-defined property. */ if (prop == ZPROP_INVAL && ((type == ZFS_TYPE_POOL && !zpool_prop_feature(propname) && !zpool_prop_unsupported(propname)) || - (type == ZFS_TYPE_DATASET && !zfs_prop_user(propname) && - !zfs_prop_userquota(propname) && !zfs_prop_written(propname)))) { + ((type == ZFS_TYPE_DATASET) && !zfs_prop_user(propname) && + !zfs_prop_userquota(propname) && !zfs_prop_written(propname)) || + ((type == ZFS_TYPE_VDEV) && !vdev_prop_user(propname)))) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property '%s'"), propname); return (zfs_error(hdl, EZFS_BADPROP, @@ -1938,8 +1954,8 @@ zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, zfs_type_t type) if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL) return (-1); - entry->pl_prop = (type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : - ZFS_PROP_NAME; + entry->pl_prop = ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : + ((type == ZFS_TYPE_VDEV) ? VDEV_PROP_NAME : ZFS_PROP_NAME)); entry->pl_width = zprop_width(entry->pl_prop, &entry->pl_fixed, type); entry->pl_all = B_TRUE; diff --git a/lib/libzfs/os/freebsd/libzfs_compat.c b/lib/libzfs/os/freebsd/libzfs_compat.c index f143f9cb6..e3f17662a 100644 --- a/lib/libzfs/os/freebsd/libzfs_compat.c +++ b/lib/libzfs/os/freebsd/libzfs_compat.c @@ -305,6 +305,10 @@ zfs_jail(zfs_handle_t *zhp, int jailid, int attach) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "bookmarks can not be jailed")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); + case ZFS_TYPE_VDEV: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "vdevs can not be jailed")); + return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case ZFS_TYPE_POOL: case ZFS_TYPE_FILESYSTEM: /* OK */ |