mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
zpool create: report which device caused failure
When zpool create fails because a vdev is already in use, the
error message now identifies the problematic device and the pool
it belongs to, e.g.:
cannot create 'tank': device '/dev/sdb1' is part of
active pool 'rpool'
Implementation follows the ZPOOL_CONFIG_LOAD_INFO pattern used
by zpool import:
- Add spa_create_info to spa_t to capture error info during
vdev_label_init(), before vdev_close() resets vdev state
- When vdev_inuse() detects a conflict, read the on-disk
label to extract the pool name and store it with the
device path
- Return the info wrapped under ZPOOL_CONFIG_CREATE_INFO
through the ioctl zc_nvlist_dst to userspace
- In libzfs, zpool_create_info() unwraps the nvlist and
formats the device-specific error message
Restructure zpool_create() error handling so all switch cases
use break instead of return, eliminating duplicated cleanup
code and using the single create_failed exit path.
Reviewed-by: Tony Hutter <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Christos Longros <[email protected]>
Closes #18213
This commit is contained in:
1 parent
cfae167754
commit
33ed68fc24
11 files changed
+233
-34
No files matched your search
+6
-5
@@ -3038,7 +3038,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
*/
|
||||
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
|
||||
VERIFY3U(ENOENT, ==,
|
||||
spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL));
|
||||
spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL, NULL));
|
||||
fnvlist_free(nvroot);
|
||||
|
||||
/*
|
||||
@@ -3046,7 +3046,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
*/
|
||||
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 2, 1);
|
||||
VERIFY3U(ENOENT, ==,
|
||||
spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL));
|
||||
spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL, NULL));
|
||||
fnvlist_free(nvroot);
|
||||
|
||||
/*
|
||||
@@ -3056,7 +3056,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
(void) pthread_rwlock_rdlock(&ztest_name_lock);
|
||||
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
|
||||
VERIFY3U(EEXIST, ==,
|
||||
spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL));
|
||||
spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL, NULL));
|
||||
fnvlist_free(nvroot);
|
||||
|
||||
/*
|
||||
@@ -3208,7 +3208,7 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
|
||||
props = fnvlist_alloc();
|
||||
fnvlist_add_uint64(props,
|
||||
zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
|
||||
VERIFY0(spa_create(name, nvroot, props, NULL, NULL));
|
||||
VERIFY0(spa_create(name, nvroot, props, NULL, NULL, NULL));
|
||||
fnvlist_free(nvroot);
|
||||
fnvlist_free(props);
|
||||
|
||||
@@ -8686,7 +8686,8 @@ ztest_init(ztest_shared_t *zs)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
VERIFY0(spa_create(ztest_opts.zo_pool, nvroot, props, NULL, NULL));
|
||||
VERIFY0(spa_create(ztest_opts.zo_pool, nvroot, props,
|
||||
NULL, NULL, NULL));
|
||||
fnvlist_free(nvroot);
|
||||
fnvlist_free(props);
|
||||
|
||||
|
||||
@@ -952,6 +952,9 @@ typedef struct zpool_load_policy {
|
||||
#define ZPOOL_CONFIG_BOOTFS "bootfs" /* not stored on disk */
|
||||
#define ZPOOL_CONFIG_MISSING_DEVICES "missing_vdevs" /* not stored on disk */
|
||||
#define ZPOOL_CONFIG_LOAD_INFO "load_info" /* not stored on disk */
|
||||
#define ZPOOL_CONFIG_CREATE_INFO "create_info" /* not stored on disk */
|
||||
#define ZPOOL_CREATE_INFO_VDEV "create_err_vdev"
|
||||
#define ZPOOL_CREATE_INFO_POOL "create_err_pool"
|
||||
#define ZPOOL_CONFIG_REWIND_INFO "rewind_info" /* not stored on disk */
|
||||
#define ZPOOL_CONFIG_UNSUP_FEAT "unsup_feat" /* not stored on disk */
|
||||
#define ZPOOL_CONFIG_ENABLED_FEAT "enabled_feat" /* not stored on disk */
|
||||
|
||||
+1
-1
@@ -777,7 +777,7 @@ extern int spa_open_rewind(const char *pool, spa_t **, const void *tag,
|
||||
extern int spa_get_stats(const char *pool, nvlist_t **config, char *altroot,
|
||||
size_t buflen);
|
||||
extern int spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
|
||||
nvlist_t *zplprops, struct dsl_crypto_params *dcp);
|
||||
nvlist_t *zplprops, struct dsl_crypto_params *dcp, nvlist_t **errinfo);
|
||||
extern int spa_import(char *pool, nvlist_t *config, nvlist_t *props,
|
||||
uint64_t flags);
|
||||
extern nvlist_t *spa_tryimport(nvlist_t *tryconfig);
|
||||
|
||||
@@ -229,6 +229,7 @@ struct spa {
|
||||
nvlist_t *spa_config_syncing; /* currently syncing config */
|
||||
nvlist_t *spa_config_splitting; /* config for splitting */
|
||||
nvlist_t *spa_load_info; /* info and errors from load */
|
||||
nvlist_t *spa_create_info; /* info from create */
|
||||
uint64_t spa_config_txg; /* txg of last config change */
|
||||
uint32_t spa_sync_pass; /* iterate-to-convergence */
|
||||
pool_state_t spa_state; /* pool state */
|
||||
|
||||
+75
-24
@@ -1536,6 +1536,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
|
||||
@@ -1615,16 +1659,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:
|
||||
/*
|
||||
@@ -1634,11 +1671,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:
|
||||
/*
|
||||
@@ -1653,7 +1693,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:
|
||||
/*
|
||||
@@ -1672,12 +1713,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) &&
|
||||
@@ -1685,24 +1728,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:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"one or more devices could not be opened"));
|
||||
return (zfs_error(hdl, EZFS_BADDEV, errbuf));
|
||||
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"));
|
||||
return (zfs_error(hdl, EZFS_BADDEV, errbuf));
|
||||
ret = zfs_error(hdl, EZFS_BADDEV, errbuf);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (zpool_standard_error(hdl, errno, errbuf));
|
||||
ret = zpool_standard_error(hdl, errno, errbuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -1947,6 +1947,10 @@ spa_activate(spa_t *spa, spa_mode_t mode)
|
||||
static void
|
||||
spa_deactivate(spa_t *spa)
|
||||
{
|
||||
if (spa->spa_create_info != NULL) {
|
||||
nvlist_free(spa->spa_create_info);
|
||||
spa->spa_create_info = NULL;
|
||||
}
|
||||
ASSERT(spa->spa_sync_on == B_FALSE);
|
||||
ASSERT0P(spa->spa_dsl_pool);
|
||||
ASSERT0P(spa->spa_root_vdev);
|
||||
@@ -7060,7 +7064,7 @@ spa_create_check_encryption_params(dsl_crypto_params_t *dcp,
|
||||
*/
|
||||
int
|
||||
spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
|
||||
nvlist_t *zplprops, dsl_crypto_params_t *dcp)
|
||||
nvlist_t *zplprops, dsl_crypto_params_t *dcp, nvlist_t **errinfo)
|
||||
{
|
||||
spa_t *spa;
|
||||
const char *altroot = NULL;
|
||||
@@ -7212,6 +7216,10 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
|
||||
spa_config_exit(spa, SCL_ALL, FTAG);
|
||||
|
||||
if (error != 0) {
|
||||
if (errinfo != NULL) {
|
||||
*errinfo = spa->spa_create_info;
|
||||
spa->spa_create_info = NULL;
|
||||
}
|
||||
spa_unload(spa);
|
||||
spa_deactivate(spa);
|
||||
spa_remove(spa);
|
||||
|
||||
+22
-1
@@ -1109,8 +1109,29 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason)
|
||||
* Determine if the vdev is in use.
|
||||
*/
|
||||
if (reason != VDEV_LABEL_REMOVE && reason != VDEV_LABEL_SPLIT &&
|
||||
vdev_inuse(vd, crtxg, reason, &spare_guid, &l2cache_guid))
|
||||
vdev_inuse(vd, crtxg, reason, &spare_guid, &l2cache_guid)) {
|
||||
if (spa->spa_create_info == NULL) {
|
||||
nvlist_t *nv = fnvlist_alloc();
|
||||
nvlist_t *cfg;
|
||||
|
||||
if (vd->vdev_path != NULL)
|
||||
fnvlist_add_string(nv,
|
||||
ZPOOL_CREATE_INFO_VDEV, vd->vdev_path);
|
||||
|
||||
cfg = vdev_label_read_config(vd, -1ULL);
|
||||
if (cfg != NULL) {
|
||||
const char *pname;
|
||||
if (nvlist_lookup_string(cfg,
|
||||
ZPOOL_CONFIG_POOL_NAME, &pname) == 0)
|
||||
fnvlist_add_string(nv,
|
||||
ZPOOL_CREATE_INFO_POOL, pname);
|
||||
nvlist_free(cfg);
|
||||
}
|
||||
|
||||
spa->spa_create_info = nv;
|
||||
}
|
||||
return (SET_ERROR(EBUSY));
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a request to add or replace a spare or l2cache device
|
||||
|
||||
+11
-1
@@ -1660,6 +1660,7 @@ zfs_ioc_pool_create(zfs_cmd_t *zc)
|
||||
dsl_crypto_params_t *dcp = NULL;
|
||||
const char *spa_name = zc->zc_name;
|
||||
boolean_t unload_wkey = B_TRUE;
|
||||
nvlist_t *errinfo = NULL;
|
||||
|
||||
if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
|
||||
zc->zc_iflags, &config)))
|
||||
@@ -1711,7 +1712,16 @@ zfs_ioc_pool_create(zfs_cmd_t *zc)
|
||||
spa_name = tname;
|
||||
}
|
||||
|
||||
error = spa_create(zc->zc_name, config, props, zplprops, dcp);
|
||||
error = spa_create(zc->zc_name, config, props, zplprops, dcp,
|
||||
&errinfo);
|
||||
if (errinfo != NULL) {
|
||||
nvlist_t *outnv = fnvlist_alloc();
|
||||
fnvlist_add_nvlist(outnv,
|
||||
ZPOOL_CONFIG_CREATE_INFO, errinfo);
|
||||
(void) put_nvlist(zc, outnv);
|
||||
nvlist_free(outnv);
|
||||
nvlist_free(errinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the remaining root properties
|
||||
|
||||
@@ -430,7 +430,7 @@ tests = ['zpool_create_001_pos', 'zpool_create_002_pos',
|
||||
'zpool_create_features_005_pos', 'zpool_create_features_006_pos',
|
||||
'zpool_create_features_007_pos', 'zpool_create_features_008_pos',
|
||||
'zpool_create_features_009_pos', 'create-o_ashift',
|
||||
'zpool_create_tempname', 'zpool_create_dryrun_output']
|
||||
'zpool_create_tempname', 'zpool_create_errinfo_001_neg', 'zpool_create_dryrun_output']
|
||||
tags = ['functional', 'cli_root', 'zpool_create']
|
||||
|
||||
[tests/functional/cli_root/zpool_destroy]
|
||||
|
||||
@@ -1098,6 +1098,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/cli_root/zpool_create/zpool_create_features_008_pos.ksh \
|
||||
functional/cli_root/zpool_create/zpool_create_features_009_pos.ksh \
|
||||
functional/cli_root/zpool_create/zpool_create_tempname.ksh \
|
||||
functional/cli_root/zpool_create/zpool_create_errinfo_001_neg.ksh \
|
||||
functional/cli_root/zpool_destroy/zpool_destroy_001_pos.ksh \
|
||||
functional/cli_root/zpool_destroy/zpool_destroy_002_pos.ksh \
|
||||
functional/cli_root/zpool_destroy/zpool_destroy_003_neg.ksh \
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2026, Christos Longros. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# 'zpool create' should report which device is in use when it fails
|
||||
# because a vdev belongs to an active pool.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Create a backing file for two block devices.
|
||||
# 2. Attach two block devices to the same file.
|
||||
# 3. Attempt to create a mirror pool using both devices.
|
||||
# 4. Verify the error message identifies the specific device.
|
||||
# 5. Verify the error message names the active pool.
|
||||
#
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
TESTFILE="$TEST_BASE_DIR/vdev_errinfo"
|
||||
TESTPOOL2="testpool_errinfo"
|
||||
BLKDEV1=""
|
||||
BLKDEV2=""
|
||||
|
||||
function cleanup
|
||||
{
|
||||
destroy_pool $TESTPOOL2
|
||||
destroy_pool $TESTPOOL
|
||||
|
||||
if is_linux; then
|
||||
[[ -n "$BLKDEV1" ]] && losetup -d "$BLKDEV1" 2>/dev/null
|
||||
[[ -n "$BLKDEV2" ]] && losetup -d "$BLKDEV2" 2>/dev/null
|
||||
elif is_freebsd; then
|
||||
[[ -n "$BLKDEV1" ]] && mdconfig -d -u "$BLKDEV1" 2>/dev/null
|
||||
[[ -n "$BLKDEV2" ]] && mdconfig -d -u "$BLKDEV2" 2>/dev/null
|
||||
fi
|
||||
|
||||
rm -f "$TESTFILE"
|
||||
}
|
||||
|
||||
log_assert "'zpool create' reports device-specific errors for in-use vdevs."
|
||||
log_onexit cleanup
|
||||
|
||||
# Create a file to back the block devices
|
||||
log_must truncate -s $MINVDEVSIZE "$TESTFILE"
|
||||
|
||||
# Attach two block devices to the same file (platform-specific)
|
||||
if is_linux; then
|
||||
BLKDEV1=$(losetup -f --show "$TESTFILE")
|
||||
BLKDEV2=$(losetup -f --show "$TESTFILE")
|
||||
elif is_freebsd; then
|
||||
BLKDEV1=/dev/$(mdconfig -a -t vnode -f "$TESTFILE")
|
||||
BLKDEV2=/dev/$(mdconfig -a -t vnode -f "$TESTFILE")
|
||||
else
|
||||
log_unsupported "Platform not supported for this test"
|
||||
fi
|
||||
|
||||
log_note "Using devices: $BLKDEV1 $BLKDEV2"
|
||||
|
||||
# Attempt to create a mirror pool; this should fail because both
|
||||
# devices refer to the same underlying file.
|
||||
log_mustnot zpool create $TESTPOOL2 mirror $BLKDEV1 $BLKDEV2
|
||||
|
||||
# Re-run to capture the error message for content verification
|
||||
errmsg=$(zpool create $TESTPOOL2 mirror $BLKDEV1 $BLKDEV2 2>&1)
|
||||
log_note "zpool create output: $errmsg"
|
||||
|
||||
# Error message should name one of the devices
|
||||
log_must eval "echo '$errmsg' | grep -qE '$BLKDEV1|$BLKDEV2'"
|
||||
|
||||
# Error message should name the active pool
|
||||
if echo "$errmsg" | grep -q "active pool"; then
|
||||
log_note "Error message correctly identifies the active pool"
|
||||
else
|
||||
log_fail "Error message does not mention the active pool: $errmsg"
|
||||
fi
|
||||
|
||||
log_pass "'zpool create' reports device-specific errors for in-use vdevs."
|
||||
Reference in new issue
Block a user