Skip to content

Commit

Permalink
parallel import negative test
Browse files Browse the repository at this point in the history
also make pool name in spa_tryimport() unique.

Signed-off-by: Don Brady <[email protected]>
  • Loading branch information
don-brady committed Dec 18, 2023
1 parent 12805b0 commit cbe28b0
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 37 deletions.
3 changes: 2 additions & 1 deletion module/zfs/spa.c
Original file line number Diff line number Diff line change
Expand Up @@ -6497,7 +6497,8 @@ spa_tryimport(nvlist_t *tryconfig)
* Create and initialize the spa structure.
*/
char *name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
(void) snprintf(name, MAXPATHLEN, "%s%s", TRYIMPORT_NAME, poolname);
(void) snprintf(name, MAXPATHLEN, "%s-%s-%llx",
TRYIMPORT_NAME, poolname, (u_longlong_t)curthread);

mutex_enter(&spa_namespace_lock);
spa = spa_add(name, tryconfig, NULL);
Expand Down
2 changes: 1 addition & 1 deletion tests/runfiles/common.run
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ tests = ['zpool_import_001_pos', 'zpool_import_002_pos',
'import_paths_changed',
'import_rewind_config_changed',
'import_rewind_device_replaced',
'zpool_import_status', 'zpool_import_parallel']
'zpool_import_status', 'zpool_import_parallel_pos', 'zpool_import_parallel_neg']
tags = ['functional', 'cli_root', 'zpool_import']
timeout = 1200

Expand Down
3 changes: 2 additions & 1 deletion tests/zfs-tests/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,8 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_import/zpool_import_missing_003_pos.ksh \
functional/cli_root/zpool_import/zpool_import_rename_001_pos.ksh \
functional/cli_root/zpool_import/zpool_import_status.ksh \
functional/cli_root/zpool_import/zpool_import_parallel.ksh \
functional/cli_root/zpool_import/zpool_import_parallel_pos.ksh \
functional/cli_root/zpool_import/zpool_import_parallel_neg.ksh \
functional/cli_root/zpool_initialize/cleanup.ksh \
functional/cli_root/zpool_initialize/zpool_initialize_attach_detach_add_remove.ksh \
functional/cli_root/zpool_initialize/zpool_initialize_fault_export_import_online.ksh \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,40 @@ function get_last_txg_synced

zdb -u $pool | awk '$1 == "txg" { print $3 }' | sort -n | tail -n 1
}

#
# create a pool and export it with dirty zil data
#
function create_dirty_exported_pool
{
typeset pool=$1
typeset vdev=$2

log_must zpool create $pool $vdev
log_must zfs create -o recordsize=8k $pool/fs

#
# This dd command works around an issue where ZIL records aren't created
# after freezing the pool unless a ZIL header already exists. Create a file
# synchronously to force ZFS to write one out.
#
log_must dd if=/dev/zero of=/$pool/fs/sync conv=fsync bs=1 count=1

#
# Freeze the pool to retain the intent log records
#
log_must zpool freeze $pool

# fill_fs [destdir] [dirnum] [filenum] [bytes] [num_writes] [data]
log_must fill_fs /$pool/fs 1 750 100 1000 Z

log_must zpool list -v $pool

#
# Unmount filesystem and export the pool
#
# The zfs intent logs contain records to replay.
#
log_must zfs unmount /$pool/fs
log_must zpool export $pool
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#!/bin/ksh -p
#
# 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 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#

#
# Copyright (c) 2023 Klara, Inc.
#

. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.kshlib

#
# DESCRIPTION:
# Verify that pool imports by same name only have one winner
#
# STRATEGY:
# 1. Create 4 single disk pools with the same name
# 2. Generate some ZIL records (for a longer import)
# 3. Export the pools
# 4. Import the pools in parallel
# 5. Repeat with using matching guids
#

verify_runnable "global"

POOLNAME="import_pool"
DEV_DIR_PREFIX="$DEVICE_DIR/$POOLNAME"
VDEVSIZE=$((512 * 1024 * 1024))

log_assert "parallel pool imports by same name only have one winner"

# each pool has its own device directory
for i in {0..3}; do
log_must mkdir -p ${DEV_DIR_PREFIX}$i
log_must truncate -s $VDEVSIZE ${DEV_DIR_PREFIX}$i/${DEVICE_FILE}$i
done

function cleanup
{
log_must set_tunable64 KEEP_LOG_SPACEMAPS_AT_EXPORT 0
log_must set_tunable64 METASLAB_DEBUG_LOAD 0

destroy_pool $POOLNAME
for i in {0..3}; do
destroy_pool $POOLNAME-$i
done

log_must rm -rf $DEV_DIR_PREFIX*
}

log_onexit cleanup

log_must set_tunable64 KEEP_LOG_SPACEMAPS_AT_EXPORT 1
log_must set_tunable64 METASLAB_DEBUG_LOAD 1

function import_pool
{
typeset dir=$1
typeset pool=$2
typeset newname=$3

errmsg=$(zpool import -N -d $dir -f $pool $newname 2>&1 > /dev/null)
if [[ $? -eq 0 ]]; then
touch $dir/imported
elif [[ $errmsg == *"cannot import"* ]]; then
touch $dir/failed
fi
}

#
# create four dirty exported pools with the same name
#
for i in {0..3}; do
create_dirty_exported_pool \
$POOLNAME ${DEV_DIR_PREFIX}$i/${DEVICE_FILE}$i
done

#
# import the pools in parallel, expecting only one winner
#
for i in {0..3}; do
import_pool ${DEV_DIR_PREFIX}$i $POOLNAME &
done
wait

# check the result of background imports
typeset num_imports=0
typeset num_cannot=0
for i in {0..3}; do
if [[ -f ${DEV_DIR_PREFIX}$i/imported ]]; then
((num_imports += 1))
fi
if [[ -f ${DEV_DIR_PREFIX}$i/failed ]]; then
((num_cannot += 1))
loser=$i
fi
done
[[ $num_imports -eq "1" ]] || log_fail "expecting an import"
[[ $num_cannot -eq "3" ]] || \
log_fail "expecting 3 pool exists errors, found $num_cannot"

log_note "$num_imports imported and $num_cannot failed (expected)"
log_must zpool export $POOLNAME

#
# Repeat but this time import using pools with the same guid
#

#
# grab the guid of the loser (which will still have dirty ZIL)
#
zpool import -o readonly=on -N -d ${DEV_DIR_PREFIX}$loser -f $POOLNAME
pool_guid=$(zpool get -H -o value guid $POOLNAME)
log_must zpool export $POOLNAME
log_note "using pool $loser with guid $pool_guid"

#
# clone the loser pool so we end up with 4 dirty pools
# with the same guid
#
for i in {0..3}; do
if [[ $i -ne $loser ]]; then
cp ${DEV_DIR_PREFIX}$loser/${DEVICE_FILE}$loser \
${DEV_DIR_PREFIX}$i/${DEVICE_FILE}$i
fi
rm -f ${DEV_DIR_PREFIX}$i/imported
rm -f ${DEV_DIR_PREFIX}$i/failed
done

#
# import the pools in parallel by guid
#
for i in {0..3}; do
import_pool ${DEV_DIR_PREFIX}$i $pool_guid ${POOLNAME}-$i &
done
wait

# check the result of background imports
num_imports=0
num_cannot=0
for i in {0..3}; do
if [[ -f ${DEV_DIR_PREFIX}$i/imported ]]; then
((num_imports += 1))
fi
if [[ -f ${DEV_DIR_PREFIX}$i/failed ]]; then
((num_cannot += 1))
fi
done
[[ $num_imports -eq "1" ]] || log_fail "expecting an import"
[[ $num_cannot -eq "3" ]] || \
log_fail "expecting 3 pool exists errors, found $num_cannot"

log_note "$num_imports imported by guid and $num_cannot failed (expected)"

log_pass "parallel pool imports by same name only have one winner"
Original file line number Diff line number Diff line change
Expand Up @@ -78,46 +78,14 @@ log_onexit cleanup
log_must set_tunable64 KEEP_LOG_SPACEMAPS_AT_EXPORT 1
log_must set_tunable64 METASLAB_DEBUG_LOAD 1

function create_dirty_pool
{
typeset pool=$1
typeset vdev=$2

log_must zpool create $pool $vdev
log_must zfs create -o recordsize=8k $pool/fs

#
# This dd command works around an issue where ZIL records aren't created
# after freezing the pool unless a ZIL header already exists. Create a file
# synchronously to force ZFS to write one out.
#
log_must dd if=/dev/zero of=/$pool/fs/sync conv=fsync bs=1 count=1

#
# Freeze the pool to retain the intent log records
#
log_must zpool freeze $pool

# fill_fs [destdir] [dirnum] [filenum] [bytes] [num_writes] [data]
log_must fill_fs /$pool/fs 1 750 100 1000 Z

log_must zpool list -v $pool

#
# Unmount filesystem and export the pool
#
# The zfs intent logs contain records to replay.
#
log_must zfs unmount /$pool/fs
log_must zpool export $pool
}

#
# create some dirty (non-empty ZIL) exported pools
#
SECONDS=0
for i in {0..$(($MAX_NUM - 1))}; do
log_must create_dirty_pool $POOLNAME-$i $DEVICE_DIR/${DEVICE_FILE}$i &
log_must create_dirty_exported_pool \
$POOLNAME-$i $DEVICE_DIR/${DEVICE_FILE}$i &
done
wait
log_note "created $MAX_NUM dirty pools in $SECONDS seconds"
Expand Down

0 comments on commit cbe28b0

Please sign in to comment.