Fix multihost stale cache file import
When the multihost property is enabled it should be impossible to import an active pool even using the force (-f) option. This patch prevents a forced import from succeeding when importing with a stale cache file. The root cause of the problem is that the kernel modules trusted the hostid provided in configuration. This is always correct when the configuration is generated by scanning for the pool. However, when using an existing cache file the hostid could be stale which would result in the activity check being skipped. Resolve the issue by always using the hostid read from the label configuration where the best uberblock was found. Reviewed-by: Olaf Faaland <faaland1@llnl.gov> Reviewed-by: Tony Hutter <hutter2@llnl.gov> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #6933 Closes #6971
This commit is contained in:
parent
e2d936e0f8
commit
bbffb59efc
|
@ -2330,7 +2330,8 @@ vdev_count_verify_zaps(vdev_t *vd)
|
|||
* Determine whether the activity check is required.
|
||||
*/
|
||||
static boolean_t
|
||||
spa_activity_check_required(spa_t *spa, uberblock_t *ub, nvlist_t *config)
|
||||
spa_activity_check_required(spa_t *spa, uberblock_t *ub, nvlist_t *label,
|
||||
nvlist_t *config)
|
||||
{
|
||||
uint64_t state = 0;
|
||||
uint64_t hostid = 0;
|
||||
|
@ -2347,7 +2348,6 @@ spa_activity_check_required(spa_t *spa, uberblock_t *ub, nvlist_t *config)
|
|||
}
|
||||
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &state);
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
|
||||
|
||||
/*
|
||||
* Disable the MMP activity check - This is used by zdb which
|
||||
|
@ -2373,8 +2373,12 @@ spa_activity_check_required(spa_t *spa, uberblock_t *ub, nvlist_t *config)
|
|||
|
||||
/*
|
||||
* Allow the activity check to be skipped when importing the pool
|
||||
* on the same host which last imported it.
|
||||
* on the same host which last imported it. Since the hostid from
|
||||
* configuration may be stale use the one read from the label.
|
||||
*/
|
||||
if (nvlist_exists(label, ZPOOL_CONFIG_HOSTID))
|
||||
hostid = fnvlist_lookup_uint64(label, ZPOOL_CONFIG_HOSTID);
|
||||
|
||||
if (hostid == spa_get_hostid())
|
||||
return (B_FALSE);
|
||||
|
||||
|
@ -2639,7 +2643,7 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
|
|||
* pool is truly inactive and can be safely imported. Prevent
|
||||
* hosts which don't have a hostid set from importing the pool.
|
||||
*/
|
||||
activity_check = spa_activity_check_required(spa, ub, config);
|
||||
activity_check = spa_activity_check_required(spa, ub, label, config);
|
||||
if (activity_check) {
|
||||
if (ub->ub_mmp_magic == MMP_MAGIC && ub->ub_mmp_delay &&
|
||||
spa_get_hostid() == 0) {
|
||||
|
|
|
@ -30,6 +30,8 @@ export TXG_TIMEOUT_DEFAULT=5
|
|||
|
||||
export MMP_POOL=mmppool
|
||||
export MMP_DIR=$TEST_BASE_DIR/mmp
|
||||
export MMP_CACHE=$MMP_DIR/zpool.cache
|
||||
export MMP_ZTEST_LOG=$MMP_DIR/ztest.log
|
||||
export MMP_HISTORY=100
|
||||
export MMP_HISTORY_OFF=0
|
||||
|
||||
|
|
|
@ -97,21 +97,24 @@ function mmp_pool_create # pool dir
|
|||
{
|
||||
typeset pool=${1:-$MMP_POOL}
|
||||
typeset dir=${2:-$MMP_DIR}
|
||||
typeset opts="-T120 -M -k0 -f $dir -E -p $pool"
|
||||
typeset opts="-VVVVV -T120 -M -k0 -f $dir -E -p $pool"
|
||||
|
||||
log_must mkdir -p $dir
|
||||
log_must rm -f $dir/*
|
||||
log_must truncate -s $MINVDEVSIZE $dir/vdev1 $dir/vdev2
|
||||
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $HOSTID1
|
||||
log_must zpool create -f $pool mirror $dir/vdev1 $dir/vdev2
|
||||
log_must zpool create -f -o cachefile=$MMP_CACHE $pool \
|
||||
mirror $dir/vdev1 $dir/vdev2
|
||||
log_must zpool set multihost=on $pool
|
||||
log_must mv $MMP_CACHE ${MMP_CACHE}.stale
|
||||
log_must zpool export $pool
|
||||
log_must mmp_clear_hostid
|
||||
log_must mmp_set_hostid $HOSTID2
|
||||
|
||||
log_note "Starting ztest in the background as hostid $HOSTID1"
|
||||
log_must eval "ZFS_HOSTID=$HOSTID1 ztest $opts >/dev/null 2>&1 &"
|
||||
log_must eval "ZFS_HOSTID=$HOSTID1 ztest $opts >$MMP_ZTEST_LOG 2>&1 &"
|
||||
|
||||
while ! is_pool_imported "$pool" "-d $dir"; do
|
||||
log_must pgrep ztest
|
||||
|
@ -134,7 +137,7 @@ function mmp_pool_destroy # pool dir
|
|||
destroy_pool $pool
|
||||
fi
|
||||
|
||||
rm -Rf $dir
|
||||
log_must rm -f $dir/*
|
||||
mmp_clear_hostid
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ verify_runnable "both"
|
|||
|
||||
function cleanup
|
||||
{
|
||||
mmp_pool_destroy $MMP_DIR $MMP_POOL
|
||||
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
||||
log_must set_tunable64 zfs_multihost_interval $MMP_INTERVAL_DEFAULT
|
||||
log_must mmp_clear_hostid
|
||||
}
|
||||
|
@ -60,11 +60,19 @@ log_must is_pool_imported $MMP_POOL "-d $MMP_DIR"
|
|||
|
||||
# 3. Verify 'zpool import [-f] $MMP_POOL' cannot import the pool.
|
||||
MMP_IMPORTED_MSG="Cannot import '$MMP_POOL': pool is imported"
|
||||
|
||||
log_must try_pool_import $MMP_POOL "-d $MMP_DIR" "$MMP_IMPORTED_MSG"
|
||||
for i in {1..10}; do
|
||||
log_must try_pool_import $MMP_POOL "-f -d $MMP_DIR" "$MMP_IMPORTED_MSG"
|
||||
done
|
||||
|
||||
log_must try_pool_import $MMP_POOL "-c ${MMP_CACHE}.stale" "$MMP_IMPORTED_MSG"
|
||||
|
||||
for i in {1..10}; do
|
||||
log_must try_pool_import $MMP_POOL "-f -c ${MMP_CACHE}.stale" \
|
||||
"$MMP_IMPORTED_MSG"
|
||||
done
|
||||
|
||||
# 4. Kill ztest to make pool eligible for import. Poll with 'zpool status'.
|
||||
ZTESTPID=$(pgrep ztest)
|
||||
if [ -n "$ZTESTPID" ]; then
|
||||
|
|
Loading…
Reference in New Issue