mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
mmp: skip non-writeable vdevs during activity check
The import-time MMP activity check added by c710f8792 writes an
uberblock to each top-level vdev and requires a matching number of
good writes before the pool is claimed. Two vdev types that carry
no writeable device break this:
- A hole vdev (left by removing a log) and an indirect vdev (left
by removing a data device) are counted in the required-write
total but can never be written, so good_writes never reaches
req_writes. The activity check then spuriously fails and the
pool is reported as held by another host with hostid 0.
- mmp_claim_uberblock() also issues a zio_flush() to the root vdev
after the writes. zio_flush() recurses to every leaf, and an
indirect vdev is a childless top-level vdev, so it is issued a
ZIO_TYPE_FLUSH. That trips the ZIO_TYPE_WRITE assertion in
vdev_indirect_io_start() and panics.
Skip hole and indirect vdevs when counting required writes, and skip
non-concrete vdevs in zio_flush() as they have no device to flush.
Add hole, indirect, log, cache, and spare vdevs to the pool used by
the mmp_inactive_import, mmp_exported_import, and mmp_concurrent_import
tests so the activity check exercises these vdev types. The enriched
layout is opt-in, leaving multihost_history on the simple two-device
pool it relies on.
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Michael Heller <[email protected]>
Closes #18823
Closes #18835
This commit is contained in:
1 parent
87e2e40475
commit
1ac3f2786b
6 files changed
+85
-51
No files matched your search
+3
-1
@@ -570,7 +570,9 @@ mmp_claim_uberblock_sync(zio_t *zio, uint64_t *good_writes,
|
||||
for (uint64_t c = 0; c < vd->vdev_children; c++) {
|
||||
vdev_t *cvd = vd->vdev_child[c];
|
||||
|
||||
if (cvd->vdev_islog || cvd->vdev_isspare || cvd->vdev_isl2cache)
|
||||
if (cvd->vdev_islog || cvd->vdev_isspare ||
|
||||
cvd->vdev_isl2cache || cvd->vdev_ishole ||
|
||||
cvd->vdev_ops == &vdev_indirect_ops)
|
||||
continue;
|
||||
|
||||
if (cvd->vdev_top == cvd) {
|
||||
|
||||
@@ -1732,6 +1732,15 @@ zio_flush(zio_t *pio, vdev_t *vd)
|
||||
return;
|
||||
|
||||
if (vd->vdev_children == 0) {
|
||||
/*
|
||||
* A non-concrete vdev (a hole or indirect vdev left behind
|
||||
* by removing a log or data device) has no leaf device to
|
||||
* flush. Skip it; issuing a flush to an indirect vdev would
|
||||
* trip the ZIO_TYPE_WRITE assertion in
|
||||
* vdev_indirect_io_start().
|
||||
*/
|
||||
if (!vdev_is_concrete(vd))
|
||||
return;
|
||||
zio_nowait(zio_create(pio, vd->vdev_spa, 0, NULL, NULL, 0, 0,
|
||||
NULL, NULL, ZIO_TYPE_FLUSH, ZIO_PRIORITY_NOW, flags, vd, 0,
|
||||
NULL, ZIO_STAGE_OPEN, ZIO_FLUSH_PIPELINE));
|
||||
|
||||
@@ -83,10 +83,11 @@ function mmp_clear_hostid
|
||||
rm -f $HOSTID_FILE
|
||||
}
|
||||
|
||||
function mmp_pool_create_simple # pool dir
|
||||
function mmp_pool_create_simple # pool dir enriched
|
||||
{
|
||||
typeset pool=${1:-$MMP_POOL}
|
||||
typeset dir=${2:-$MMP_DIR}
|
||||
typeset enriched=${3:-""}
|
||||
|
||||
log_must mkdir -p $dir
|
||||
log_must rm -f $dir/*
|
||||
@@ -96,6 +97,28 @@ function mmp_pool_create_simple # pool dir
|
||||
log_must mmp_set_hostid $HOSTID1
|
||||
log_must zpool create -f -o cachefile=$MMP_CACHE $pool \
|
||||
mirror $dir/vdev1 $dir/vdev2
|
||||
|
||||
if [[ -n "$enriched" ]]; then
|
||||
#
|
||||
# Add then remove a data vdev to leave an indirect vdev, and
|
||||
# add then remove a log to leave a hole vdev, so the pool
|
||||
# exercises the non-writeable top-level vdev types skipped by
|
||||
# the MMP claim check. Round it out with a log, a cache, and
|
||||
# a spare vdev.
|
||||
#
|
||||
log_must truncate -s $MINVDEVSIZE $dir/vdev3 $dir/vdev4 \
|
||||
$dir/vdev5 $dir/vdev6 $dir/vdev7
|
||||
log_must zpool add -f $pool $dir/vdev3
|
||||
log_must zpool remove $pool $dir/vdev3
|
||||
log_must zpool wait -t remove $pool
|
||||
log_must sync_pool $pool
|
||||
log_must zpool add -f $pool log $dir/vdev4
|
||||
log_must zpool remove $pool $dir/vdev4
|
||||
log_must zpool add -f $pool log $dir/vdev5
|
||||
log_must zpool add -f $pool cache $dir/vdev6
|
||||
log_must zpool add -f $pool spare $dir/vdev7
|
||||
fi
|
||||
|
||||
log_must zpool set multihost=on $pool
|
||||
}
|
||||
|
||||
@@ -148,7 +171,7 @@ function mmp_pool_set_hostid # pool hostid
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $hostid
|
||||
log_must zpool export $pool
|
||||
log_must zpool import $pool
|
||||
log_must zpool import -d $MMP_DIR $pool
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ log_assert "multihost=on concurrent imports"
|
||||
log_onexit cleanup
|
||||
|
||||
# 1. Create a multihost enabled pool with HOSTID1
|
||||
mmp_pool_create_simple $MMP_POOL $MMP_DIR
|
||||
mmp_pool_create_simple $MMP_POOL $MMP_DIR enriched
|
||||
log_must zpool export -F $MMP_POOL
|
||||
|
||||
# 2. zhack imports: $HOSTID1 (matching) and $HOSTID1 (matching)
|
||||
|
||||
@@ -40,34 +40,34 @@ verify_runnable "both"
|
||||
|
||||
function cleanup
|
||||
{
|
||||
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
|
||||
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
||||
log_must mmp_clear_hostid
|
||||
}
|
||||
|
||||
log_assert "multihost=on|off activity checks exported pool"
|
||||
log_onexit cleanup
|
||||
|
||||
# 1. Create a zpool
|
||||
log_must mmp_set_hostid $HOSTID1
|
||||
log_must zpool create -f $TESTPOOL $DISK
|
||||
# 1. Create an enriched zpool (hole, indirect, log, cache, and spare
|
||||
# vdevs) so the activity checks exercise the non-writeable types.
|
||||
mmp_pool_create_simple $MMP_POOL $MMP_DIR enriched
|
||||
|
||||
# 2. Verify multihost=off and hostids match (no activity check)
|
||||
log_note "Verify multihost=off and hostids match (no activity check)"
|
||||
log_must zpool set multihost=off $TESTPOOL
|
||||
log_must zpool set multihost=off $MMP_POOL
|
||||
|
||||
for opt in "" "-f"; do
|
||||
log_must zpool export $TESTPOOL
|
||||
log_must import_no_activity_check $TESTPOOL $opt
|
||||
log_must zpool export $MMP_POOL
|
||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
# 3. Verify multihost=off and hostids differ (no activity check)
|
||||
log_note "Verify multihost=off and hostids differ (no activity check)"
|
||||
for opt in "" "-f"; do
|
||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||
log_must zpool export $TESTPOOL
|
||||
log_must mmp_pool_set_hostid $MMP_POOL $HOSTID1
|
||||
log_must zpool export $MMP_POOL
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $HOSTID2
|
||||
log_must import_no_activity_check $TESTPOOL $opt
|
||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
||||
@@ -75,39 +75,39 @@ log_note "Verify multihost=off and hostid zero allowed (no activity check)"
|
||||
log_must mmp_clear_hostid
|
||||
|
||||
for opt in "" "-f"; do
|
||||
log_must zpool export $TESTPOOL
|
||||
log_must import_no_activity_check $TESTPOOL $opt
|
||||
log_must zpool export $MMP_POOL
|
||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
# 5. Verify multihost=on and hostids match (no activity check)
|
||||
log_note "Verify multihost=on and hostids match (no activity check)"
|
||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||
log_must zpool set multihost=on $TESTPOOL
|
||||
log_must mmp_pool_set_hostid $MMP_POOL $HOSTID1
|
||||
log_must zpool set multihost=on $MMP_POOL
|
||||
|
||||
for opt in "" "-f"; do
|
||||
log_must zpool export $TESTPOOL
|
||||
log_must import_no_activity_check $TESTPOOL $opt
|
||||
log_must zpool export $MMP_POOL
|
||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
# 6. Verify multihost=on and hostids differ (activity check)
|
||||
log_note "Verify multihost=on and hostids differ (activity check)"
|
||||
for opt in "" "-f"; do
|
||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||
log_must zpool export $TESTPOOL
|
||||
log_must mmp_pool_set_hostid $MMP_POOL $HOSTID1
|
||||
log_must zpool export $MMP_POOL
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $HOSTID2
|
||||
log_must import_activity_check $TESTPOOL $opt
|
||||
log_must import_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
# 7. Verify multihost=on and hostid zero fails (no activity check)
|
||||
log_note "Verify multihost=on and hostid zero fails (no activity check)"
|
||||
log_must zpool export $TESTPOOL
|
||||
log_must zpool export $MMP_POOL
|
||||
log_must mmp_clear_hostid
|
||||
|
||||
for opt in "" "-f"; do
|
||||
MMP_IMPORTED_MSG="Set a unique system hostid"
|
||||
log_must check_pool_import $TESTPOOL "" "action" "$MMP_IMPORTED_MSG"
|
||||
log_mustnot import_no_activity_check $TESTPOOL $opt
|
||||
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "action" "$MMP_IMPORTED_MSG"
|
||||
log_mustnot import_no_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
log_pass "multihost=on|off exported pool activity checks passed"
|
||||
@@ -42,7 +42,7 @@ verify_runnable "both"
|
||||
|
||||
function cleanup
|
||||
{
|
||||
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
|
||||
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
||||
log_must mmp_clear_hostid
|
||||
log_must set_tunable64 MULTIHOST_INTERVAL $MMP_INTERVAL_DEFAULT
|
||||
}
|
||||
@@ -50,63 +50,63 @@ function cleanup
|
||||
log_assert "multihost=on|off inactive pool activity checks"
|
||||
log_onexit cleanup
|
||||
|
||||
# 1. Create a zpool
|
||||
log_must mmp_set_hostid $HOSTID1
|
||||
log_must zpool create -f $TESTPOOL $DISK
|
||||
# 1. Create an enriched zpool (hole, indirect, log, cache, and spare
|
||||
# vdevs) so the activity checks exercise the non-writeable types.
|
||||
mmp_pool_create_simple $MMP_POOL $MMP_DIR enriched
|
||||
|
||||
# 2. Verify multihost=off and hostids match (no activity check)
|
||||
log_note "Verify multihost=off and hostids match (no activity check)"
|
||||
log_must zpool set multihost=off $TESTPOOL
|
||||
log_must zpool set multihost=off $MMP_POOL
|
||||
|
||||
for opt in "" "-f"; do
|
||||
log_must zpool export -F $TESTPOOL
|
||||
log_must import_no_activity_check $TESTPOOL $opt
|
||||
log_must zpool export -F $MMP_POOL
|
||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
# 3. Verify multihost=off and hostids differ (no activity check)
|
||||
log_note "Verify multihost=off and hostids differ (no activity check)"
|
||||
log_must zpool export -F $TESTPOOL
|
||||
log_must zpool export -F $MMP_POOL
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $HOSTID2
|
||||
log_mustnot import_no_activity_check $TESTPOOL ""
|
||||
log_must import_no_activity_check $TESTPOOL "-f"
|
||||
log_mustnot import_no_activity_check $MMP_POOL "-d $MMP_DIR"
|
||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR -f"
|
||||
|
||||
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
||||
log_note "Verify multihost=off and hostid zero allowed (no activity check)"
|
||||
log_must zpool export -F $TESTPOOL
|
||||
log_must zpool export -F $MMP_POOL
|
||||
log_must mmp_clear_hostid
|
||||
log_mustnot import_no_activity_check $TESTPOOL ""
|
||||
log_must import_no_activity_check $TESTPOOL "-f"
|
||||
log_mustnot import_no_activity_check $MMP_POOL "-d $MMP_DIR"
|
||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR -f"
|
||||
|
||||
# 5. Verify multihost=on and hostids match (activity check)
|
||||
log_note "Verify multihost=on and hostids match (activity check)"
|
||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||
log_must zpool set multihost=on $TESTPOOL
|
||||
log_must mmp_pool_set_hostid $MMP_POOL $HOSTID1
|
||||
log_must zpool set multihost=on $MMP_POOL
|
||||
|
||||
for opt in "" "-f"; do
|
||||
log_must zpool export -F $TESTPOOL
|
||||
log_must import_activity_check $TESTPOOL $opt
|
||||
log_must zpool export -F $MMP_POOL
|
||||
log_must import_activity_check $MMP_POOL "-d $MMP_DIR $opt"
|
||||
done
|
||||
|
||||
# 6. Verify multihost=on and hostids differ (activity check)
|
||||
log_note "Verify multihost=on and hostids differ (activity check)"
|
||||
log_must zpool export -F $TESTPOOL
|
||||
log_must zpool export -F $MMP_POOL
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $HOSTID2
|
||||
log_mustnot import_activity_check $TESTPOOL ""
|
||||
log_must import_activity_check $TESTPOOL "-f"
|
||||
log_mustnot import_activity_check $MMP_POOL "-d $MMP_DIR"
|
||||
log_must import_activity_check $MMP_POOL "-d $MMP_DIR -f"
|
||||
|
||||
# 7. Verify mmp_write and mmp_fail are set correctly
|
||||
log_note "Verify mmp_write and mmp_fail are set correctly"
|
||||
log_must zpool export -F $TESTPOOL
|
||||
log_must verify_mmp_write_fail_present ${DISK[0]}
|
||||
log_must zpool export -F $MMP_POOL
|
||||
log_must verify_mmp_write_fail_present $MMP_DIR/vdev1
|
||||
|
||||
# 8. Verify multihost=on and hostid zero fails (no activity check)
|
||||
log_note "Verify multihost=on and hostid zero fails (no activity check)"
|
||||
log_must mmp_clear_hostid
|
||||
MMP_IMPORTED_MSG="Set a unique system hostid"
|
||||
log_must check_pool_import $TESTPOOL "-f" "action" "$MMP_IMPORTED_MSG"
|
||||
log_mustnot import_no_activity_check $TESTPOOL "-f"
|
||||
log_must check_pool_import $MMP_POOL "-d $MMP_DIR -f" "action" "$MMP_IMPORTED_MSG"
|
||||
log_mustnot import_no_activity_check $MMP_POOL "-d $MMP_DIR -f"
|
||||
|
||||
# 9. Verify activity check duration based on mmp_write and mmp_fail
|
||||
# Specify a short test via tunables but import pool imported while
|
||||
@@ -115,6 +115,6 @@ log_note "Verify activity check duration based on mmp_write and mmp_fail"
|
||||
log_must set_tunable64 MULTIHOST_INTERVAL $MMP_INTERVAL_MIN
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $HOSTID1
|
||||
log_must import_activity_check $TESTPOOL "-f"
|
||||
log_must import_activity_check $MMP_POOL "-d $MMP_DIR -f"
|
||||
|
||||
log_pass "multihost=on|off inactive pool activity checks passed"
|
||||
Reference in new issue
Block a user