diff options
Diffstat (limited to 'sys/contrib/openzfs/lib/libzfs/libzfs_pool.c')
| -rw-r--r-- | sys/contrib/openzfs/lib/libzfs/libzfs_pool.c | 315 |
1 files changed, 280 insertions, 35 deletions
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c b/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c index 756d701e2d97..f82211699f54 100644 --- a/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c +++ b/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c @@ -370,8 +370,47 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, zfs_fallthrough; case ZPOOL_PROP_SIZE: + case ZPOOL_PROP_NORMAL_SIZE: + case ZPOOL_PROP_SPECIAL_SIZE: + case ZPOOL_PROP_DEDUP_SIZE: + case ZPOOL_PROP_LOG_SIZE: + case ZPOOL_PROP_ELOG_SIZE: + case ZPOOL_PROP_SELOG_SIZE: case ZPOOL_PROP_ALLOCATED: + case ZPOOL_PROP_NORMAL_ALLOCATED: + case ZPOOL_PROP_SPECIAL_ALLOCATED: + case ZPOOL_PROP_DEDUP_ALLOCATED: + case ZPOOL_PROP_LOG_ALLOCATED: + case ZPOOL_PROP_ELOG_ALLOCATED: + case ZPOOL_PROP_SELOG_ALLOCATED: + case ZPOOL_PROP_AVAILABLE: + case ZPOOL_PROP_NORMAL_AVAILABLE: + case ZPOOL_PROP_SPECIAL_AVAILABLE: + case ZPOOL_PROP_DEDUP_AVAILABLE: + case ZPOOL_PROP_LOG_AVAILABLE: + case ZPOOL_PROP_ELOG_AVAILABLE: + case ZPOOL_PROP_SELOG_AVAILABLE: case ZPOOL_PROP_FREE: + case ZPOOL_PROP_NORMAL_FREE: + case ZPOOL_PROP_SPECIAL_FREE: + case ZPOOL_PROP_DEDUP_FREE: + case ZPOOL_PROP_LOG_FREE: + case ZPOOL_PROP_ELOG_FREE: + case ZPOOL_PROP_SELOG_FREE: + case ZPOOL_PROP_USABLE: + case ZPOOL_PROP_NORMAL_USABLE: + case ZPOOL_PROP_SPECIAL_USABLE: + case ZPOOL_PROP_DEDUP_USABLE: + case ZPOOL_PROP_LOG_USABLE: + case ZPOOL_PROP_ELOG_USABLE: + case ZPOOL_PROP_SELOG_USABLE: + case ZPOOL_PROP_USED: + case ZPOOL_PROP_NORMAL_USED: + case ZPOOL_PROP_SPECIAL_USED: + case ZPOOL_PROP_DEDUP_USED: + case ZPOOL_PROP_LOG_USED: + case ZPOOL_PROP_ELOG_USED: + case ZPOOL_PROP_SELOG_USED: case ZPOOL_PROP_FREEING: case ZPOOL_PROP_LEAKED: case ZPOOL_PROP_ASHIFT: @@ -380,6 +419,8 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, case ZPOOL_PROP_BCLONESAVED: case ZPOOL_PROP_BCLONEUSED: case ZPOOL_PROP_DEDUP_TABLE_SIZE: + case ZPOOL_PROP_DEDUPUSED: + case ZPOOL_PROP_DEDUPSAVED: case ZPOOL_PROP_DEDUPCACHED: if (literal) (void) snprintf(buf, len, "%llu", @@ -389,6 +430,12 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, break; case ZPOOL_PROP_EXPANDSZ: + case ZPOOL_PROP_NORMAL_EXPANDSZ: + case ZPOOL_PROP_SPECIAL_EXPANDSZ: + case ZPOOL_PROP_DEDUP_EXPANDSZ: + case ZPOOL_PROP_LOG_EXPANDSZ: + case ZPOOL_PROP_ELOG_EXPANDSZ: + case ZPOOL_PROP_SELOG_EXPANDSZ: case ZPOOL_PROP_CHECKPOINT: if (intval == 0) { (void) strlcpy(buf, "-", len); @@ -401,6 +448,12 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, break; case ZPOOL_PROP_CAPACITY: + case ZPOOL_PROP_NORMAL_CAPACITY: + case ZPOOL_PROP_SPECIAL_CAPACITY: + case ZPOOL_PROP_DEDUP_CAPACITY: + case ZPOOL_PROP_LOG_CAPACITY: + case ZPOOL_PROP_ELOG_CAPACITY: + case ZPOOL_PROP_SELOG_CAPACITY: if (literal) { (void) snprintf(buf, len, "%llu", (u_longlong_t)intval); @@ -411,7 +464,13 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, break; case ZPOOL_PROP_FRAGMENTATION: - if (intval == UINT64_MAX) { + case ZPOOL_PROP_NORMAL_FRAGMENTATION: + case ZPOOL_PROP_SPECIAL_FRAGMENTATION: + case ZPOOL_PROP_DEDUP_FRAGMENTATION: + case ZPOOL_PROP_LOG_FRAGMENTATION: + case ZPOOL_PROP_ELOG_FRAGMENTATION: + case ZPOOL_PROP_SELOG_FRAGMENTATION: + if (intval == ZFS_FRAG_INVALID) { (void) strlcpy(buf, "-", len); } else if (literal) { (void) snprintf(buf, len, "%llu", @@ -581,7 +640,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, prop = zpool_name_to_prop(propname); if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) { int err; - char *fname = strchr(propname, '@') + 1; + const char *fname = strchr(propname, '@') + 1; err = zfeature_lookup_name(fname, NULL); if (err != 0) { @@ -1451,11 +1510,17 @@ zpool_has_draid_vdev(nvlist_t *nvroot) */ static char * zpool_draid_name(char *name, int len, uint64_t data, uint64_t parity, - uint64_t spares, uint64_t children) + uint64_t spares, uint64_t children, uint64_t width) { - snprintf(name, len, "%s%llu:%llud:%lluc:%llus", - VDEV_TYPE_DRAID, (u_longlong_t)parity, (u_longlong_t)data, - (u_longlong_t)children, (u_longlong_t)spares); + if (children < width) + snprintf(name, len, "%s%llu:%llud:%lluc:%lluw:%llus", + VDEV_TYPE_DRAID, (u_longlong_t)parity, (u_longlong_t)data, + (u_longlong_t)children, (u_longlong_t)width, + (u_longlong_t)spares); + else + snprintf(name, len, "%s%llu:%llud:%lluc:%llus", + VDEV_TYPE_DRAID, (u_longlong_t)parity, (u_longlong_t)data, + (u_longlong_t)children, (u_longlong_t)spares); return (name); } @@ -1477,6 +1542,50 @@ zpool_is_draid_spare(const char *name) return (B_FALSE); } + +/* + * Extract device-specific error information from a failed pool creation. + * If the kernel returned ZPOOL_CONFIG_CREATE_INFO in the ioctl output, + * set an appropriate error aux message identifying the problematic device. + */ +static int +zpool_create_info(libzfs_handle_t *hdl, zfs_cmd_t *zc) +{ + nvlist_t *outnv = NULL; + nvlist_t *info = NULL; + const char *vdev = NULL; + const char *pname = NULL; + + if (zc->zc_nvlist_dst_size == 0) + return (ENOENT); + + if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst, + zc->zc_nvlist_dst_size, &outnv, 0) != 0 || outnv == NULL) + return (EINVAL); + + if (nvlist_lookup_nvlist(outnv, ZPOOL_CONFIG_CREATE_INFO, &info) != 0) { + nvlist_free(outnv); + return (EINVAL); + } + + if (nvlist_lookup_string(info, ZPOOL_CREATE_INFO_VDEV, &vdev) != 0) { + nvlist_free(outnv); + return (EINVAL); + } + + if (nvlist_lookup_string(info, ZPOOL_CREATE_INFO_POOL, &pname) == 0) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "device '%s' is part of active pool '%s'"), + vdev, pname); + } else { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "device '%s' is in use"), vdev); + } + + nvlist_free(outnv); + return (0); +} + /* * Create the named pool, using the provided vdev list. It is assumed * that the consumer has already validated the contents of the nvlist, so we @@ -1556,16 +1665,9 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, zcmd_write_src_nvlist(hdl, &zc, zc_props); (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); + zcmd_alloc_dst_nvlist(hdl, &zc, 4096); if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { - - zcmd_free_nvlists(&zc); - nvlist_free(zc_props); - nvlist_free(zc_fsprops); - nvlist_free(hidden_args); - if (wkeydata != NULL) - free(wkeydata); - switch (errno) { case EBUSY: /* @@ -1575,11 +1677,14 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, * label. This can also happen under if the device is * part of an active md or lvm device. */ - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "one or more vdevs refer to the same device, or " - "one of\nthe devices is part of an active md or " - "lvm device")); - return (zfs_error(hdl, EZFS_BADDEV, errbuf)); + if (zpool_create_info(hdl, &zc) != 0) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "one or more vdevs refer to the same " + "device, or one of\nthe devices is " + "part of an active md or lvm device")); + } + ret = zfs_error(hdl, EZFS_BADDEV, errbuf); + break; case ERANGE: /* @@ -1594,7 +1699,8 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "record size invalid")); - return (zfs_error(hdl, EZFS_BADPROP, errbuf)); + ret = zfs_error(hdl, EZFS_BADPROP, errbuf); + break; case EOVERFLOW: /* @@ -1613,12 +1719,14 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, "one or more devices is less than the " "minimum size (%s)"), buf); } - return (zfs_error(hdl, EZFS_BADDEV, errbuf)); + ret = zfs_error(hdl, EZFS_BADDEV, errbuf); + break; case ENOSPC: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "one or more devices is out of space")); - return (zfs_error(hdl, EZFS_BADDEV, errbuf)); + ret = zfs_error(hdl, EZFS_BADDEV, errbuf); + break; case EINVAL: if (zpool_has_draid_vdev(nvroot) && @@ -1626,14 +1734,32 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dRAID vdevs are unsupported by the " "kernel")); - return (zfs_error(hdl, EZFS_BADDEV, errbuf)); + ret = zfs_error(hdl, EZFS_BADDEV, errbuf); } else { - return (zpool_standard_error(hdl, errno, - errbuf)); + ret = zpool_standard_error(hdl, errno, errbuf); + } + break; + + case ENXIO: + if (zpool_create_info(hdl, &zc) == 0) { + ret = zfs_error(hdl, EZFS_BADDEV, errbuf); + } else { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "one or more devices could not be " + "opened")); + ret = zfs_error(hdl, EZFS_BADDEV, errbuf); } + break; + + case EDOM: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "block size out of range or does not match")); + ret = zfs_error(hdl, EZFS_BADDEV, errbuf); + break; default: - return (zpool_standard_error(hdl, errno, errbuf)); + ret = zpool_standard_error(hdl, errno, errbuf); + break; } } @@ -1905,12 +2031,21 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce, return (0); } +/* + * Export the pool from the system. Setting force overrides the + * active-shared-spare check. The caller must unmount all datasets + * in the pool first. + */ int zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str) { return (zpool_export_common(zhp, force, B_FALSE, log_str)); } +/* + * Force-export the pool: bypasses the active-shared-spare check, and skips + * writing the exported-state labels and updating the cachefile. + */ int zpool_export_force(zpool_handle_t *zhp, const char *log_str) { @@ -2048,7 +2183,9 @@ zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, no_info: (void) strlcat(buf, dgettext(TEXT_DOMAIN, - "Destroy and re-create the pool from\n\ta backup source.\n"), size); + "Ensure all pool devices are present and accessible, then " + "retry the import.\n\tIf the problem persists, destroy and " + "re-create the pool from a backup source.\n"), size); } /* @@ -2209,6 +2346,11 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, zpool_get_load_policy(config, &policy); + if (getenv("ZFS_LOAD_INFO_DEBUG") && nv != NULL && + nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0) { + dump_nvlist(nvinfo, 4); + } + if (error) { char desc[1024]; char aux[256]; @@ -2441,6 +2583,10 @@ xlate_init_err(int err) return (err); } +/* + * Start (or cancel/suspend/uninit) the initialize operation on every + * leaf vdev of the pool. + */ int zpool_initialize_one(zpool_handle_t *zhp, void *data) { @@ -2552,6 +2698,10 @@ out: return (err == 0 ? 0 : -1); } +/* + * Start (or cancel/suspend/uninit) the initialize operation on the listed + * vdevs. Returns once the new state is committed. + */ int zpool_initialize(zpool_handle_t *zhp, pool_initialize_func_t cmd_type, nvlist_t *vds) @@ -2559,6 +2709,9 @@ zpool_initialize(zpool_handle_t *zhp, pool_initialize_func_t cmd_type, return (zpool_initialize_impl(zhp, cmd_type, vds, B_FALSE)); } +/* + * Like zpool_initialize(), but waits for each listed vdev to finish. + */ int zpool_initialize_wait(zpool_handle_t *zhp, pool_initialize_func_t cmd_type, nvlist_t *vds) @@ -2613,6 +2766,10 @@ zpool_collect_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *res) } } +/* + * Start (or cancel/suspend) the trim operation on every leaf vdev of + * the pool. + */ int zpool_trim_one(zpool_handle_t *zhp, void *data) { @@ -2792,8 +2949,11 @@ zpool_scan_range(zpool_handle_t *zhp, pool_scan_func_t func, nvlist_t *args = fnvlist_alloc(); fnvlist_add_uint64(args, "scan_type", (uint64_t)func); fnvlist_add_uint64(args, "scan_command", (uint64_t)cmd); - fnvlist_add_uint64(args, "scan_date_start", (uint64_t)date_start); - fnvlist_add_uint64(args, "scan_date_end", (uint64_t)date_end); + if (date_start != 0 || date_end != 0) { + fnvlist_add_uint64(args, "scan_date_start", + (uint64_t)date_start); + fnvlist_add_uint64(args, "scan_date_end", (uint64_t)date_end); + } err = lzc_scrub(ZFS_IOC_POOL_SCRUB, zhp->zpool_name, args, NULL); fnvlist_free(args); @@ -3257,6 +3417,11 @@ __zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, return (ret); } +/* + * Look up a vdev in the pool by path, name, or guid. Returns the + * vdev's configuration nvlist, or NULL on no match. Also, fills + * in avail_spare, l2cache, and log if they are non-NULL. + */ nvlist_t * zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) @@ -3492,10 +3657,53 @@ zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) zfs_cmd_t zc = {"\0"}; char errbuf[ERRBUFLEN]; libzfs_handle_t *hdl = zhp->zpool_hdl; + nvlist_t *vdev_nv; + boolean_t avail_spare, l2cache; + char *vdev_name; + char guid_str[21]; /* 64-bit num + '\0' */ + boolean_t is_draid_spare = B_FALSE; + const char *vdev_type; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot fault %llu"), (u_longlong_t)guid); + snprintf(guid_str, sizeof (guid_str), "%llu", (u_longlong_t)guid); + if ((vdev_nv = zpool_find_vdev(zhp, guid_str, &avail_spare, + &l2cache, NULL)) == NULL) + return (zfs_error(hdl, EZFS_NODEVICE, errbuf)); + + vdev_name = zpool_vdev_name(hdl, zhp, vdev_nv, 0); + if (vdev_name != NULL) { + /* + * We have the actual vdev name, so use that instead of the GUID + * in any error messages. + */ + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot fault %s"), vdev_name); + free(vdev_name); + } + + /* + * Spares (traditional or draid) cannot be faulted by libzfs, except: + * + * - Any spare type that exceeds it's errors can be faulted (aux = + * VDEV_AUX_ERR_EXCEEDED). This is only used by zed. + * + * - Traditional spares that are active can be force faulted. + */ + if (nvlist_lookup_string(vdev_nv, ZPOOL_CONFIG_TYPE, &vdev_type) == 0) + if (strcmp(vdev_type, VDEV_TYPE_DRAID_SPARE) == 0) + is_draid_spare = B_TRUE; + + /* + * If vdev is a spare that is not being used, or is a dRAID spare (in + * use or not), then don't allow it to be force-faulted. However, an + * in-use dRAID spare can be faulted by ZED if see too many errors + * (aux = VDEV_AUX_ERR_EXCEEDED). + */ + if (avail_spare || (is_draid_spare && aux != VDEV_AUX_ERR_EXCEEDED)) + return (zfs_error(hdl, EZFS_ISSPARE, errbuf)); + (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); zc.zc_guid = guid; zc.zc_cookie = VDEV_STATE_FAULTED; @@ -4336,7 +4544,8 @@ zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) zc.zc_cookie = policy.zlp_rewind; zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size * 2); - zcmd_write_src_nvlist(hdl, &zc, rewindnvl); + if (rewindnvl != NULL) + zcmd_write_src_nvlist(hdl, &zc, rewindnvl); while ((error = zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc)) != 0 && errno == ENOMEM) @@ -4457,7 +4666,10 @@ zpool_reopen_one(zpool_handle_t *zhp, void *data) return (0); } -/* call into libzfs_core to execute the sync IOCTL per pool */ +/* + * Block until every buffered write for the pool has reached the + * underlying disks. + */ int zpool_sync_one(zpool_handle_t *zhp, void *data) { @@ -4570,12 +4782,12 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, * If it's a dRAID device, we add parity, groups, and spares. */ if (strcmp(path, VDEV_TYPE_DRAID) == 0) { - uint64_t ndata, nparity, nspares; + uint64_t ndata, nparity, nspares, children; nvlist_t **child; - uint_t children; + uint_t width; verify(nvlist_lookup_nvlist_array(nv, - ZPOOL_CONFIG_CHILDREN, &child, &children) == 0); + ZPOOL_CONFIG_CHILDREN, &child, &width) == 0); nparity = fnvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY); ndata = fnvlist_lookup_uint64(nv, @@ -4583,8 +4795,12 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, nspares = fnvlist_lookup_uint64(nv, ZPOOL_CONFIG_DRAID_NSPARES); + if (nvlist_lookup_uint64(nv, + ZPOOL_CONFIG_DRAID_NCHILDREN, &children) != 0) + children = width; + path = zpool_draid_name(buf, sizeof (buf), ndata, - nparity, nspares, children); + nparity, nspares, children, width); } /* @@ -4729,6 +4945,10 @@ zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) return (0); } +/* + * Format the program name and its command-line arguments into a single + * space-separated string. + */ void zfs_save_arguments(int argc, char **argv, char *string, int len) { @@ -4741,6 +4961,10 @@ zfs_save_arguments(int argc, char **argv, char *string, int len) } } +/* + * Append a message to the pool's command-history log, retrievable via + * "zpool history". + */ int zpool_log_history(libzfs_handle_t *hdl, const char *message) { @@ -5036,6 +5260,11 @@ zpool_obj_to_path_impl(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, free(mntpnt); } +/* + * Translate a (dataset object id, file object id) pair into a readable + * path. If the dataset is mounted the result is an absolute filesystem + * path; otherwise it is `dataset:path`. + */ void zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, char *pathname, size_t len) @@ -5043,6 +5272,10 @@ zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, zpool_obj_to_path_impl(zhp, dsobj, obj, pathname, len, B_FALSE); } +/* + * Translate a (dataset object id, file object id) pair into a + * `dataset:path` string. + */ void zpool_obj_to_path_ds(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, char *pathname, size_t len) @@ -5097,6 +5330,10 @@ zpool_wait_status(zpool_handle_t *zhp, zpool_wait_activity_t activity, return (error); } +/* + * Store a boot configuration map in the bootenv area of each leaf + * vdev's labels. + */ int zpool_set_bootenv(zpool_handle_t *zhp, const nvlist_t *envmap) { @@ -5110,6 +5347,9 @@ zpool_set_bootenv(zpool_handle_t *zhp, const nvlist_t *envmap) return (error); } +/* + * Read the boot configuration map from each leaf vdev's bootenv area. + */ int zpool_get_bootenv(zpool_handle_t *zhp, nvlist_t **nvlp) { @@ -5508,6 +5748,8 @@ zpool_get_vdev_prop_value(nvlist_t *nvprop, vdev_prop_t prop, char *prop_name, case VDEV_PROP_IO_T: case VDEV_PROP_SLOW_IO_N: case VDEV_PROP_SLOW_IO_T: + case VDEV_PROP_FDOMAIN: + case VDEV_PROP_FGROUP: if (intval == UINT64_MAX) { (void) strlcpy(buf, "-", len); } else { @@ -5555,6 +5797,9 @@ zpool_get_vdev_prop_value(nvlist_t *nvprop, vdev_prop_t prop, char *prop_name, return (ENOENT); if (prop == VDEV_PROP_SIT_OUT) return (ENOENT); + /* Only valid for top-level vdevs */ + if (prop == VDEV_PROP_ALLOC_BIAS) + return (ENOENT); } if (vdev_prop_index_to_string(prop, intval, (const char **)&strval) != 0) |
