aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/lib/libzfs/libzfs_pool.c')
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_pool.c315
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)