Add support for parallel pool exports

Changed spa_export_common() such that it no longer holds the
spa_namespace_lock for the entire duration and instead sets
spa_export_thread to indicate an import is in progress on the
spa.  This allows for an export to a diffent pool to proceed
in parallel while an export is still processing potentially
long operations like spa_unload_log_sm_flush_all().

Calls like spa_lookup() and spa_vdev_enter() that rely on
the spa_namespace_lock to serialize them against a concurrent
export, now wait for any in-progress export thread to complete
before proceeding.

The 'zpool import -a' sub-command also provides multi-threaded
support, using a thread pool to submit the exports in parallel.

Sponsored-By: Klara Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: George Wilson <gwilson@delphix.com>
Signed-off-by: Don Brady <don.brady@klarasystems.com>
Closes #16153
This commit is contained in:
Don Brady
2024-05-02 19:28:10 +00:00
committed by Brian Behlendorf
parent abec7dcd30
commit 975a13259b
12 changed files with 373 additions and 33 deletions
+2 -1
View File
@@ -430,7 +430,8 @@ tags = ['functional', 'cli_root', 'zpool_events']
[tests/functional/cli_root/zpool_export]
tests = ['zpool_export_001_pos', 'zpool_export_002_pos',
'zpool_export_003_neg', 'zpool_export_004_pos']
'zpool_export_003_neg', 'zpool_export_004_pos',
'zpool_export_parallel_pos', 'zpool_export_parallel_admin']
tags = ['functional', 'cli_root', 'zpool_export']
[tests/functional/cli_root/zpool_get]
+2
View File
@@ -1084,6 +1084,8 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_export/zpool_export_002_pos.ksh \
functional/cli_root/zpool_export/zpool_export_003_neg.ksh \
functional/cli_root/zpool_export/zpool_export_004_pos.ksh \
functional/cli_root/zpool_export/zpool_export_parallel_admin.ksh \
functional/cli_root/zpool_export/zpool_export_parallel_pos.ksh \
functional/cli_root/zpool_get/cleanup.ksh \
functional/cli_root/zpool_get/setup.ksh \
functional/cli_root/zpool_get/vdev_get_001_pos.ksh \
@@ -0,0 +1,72 @@
#!/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) 2024 Klara, Inc.
#
. $STF_SUITE/include/libtest.shlib
#
# DESCRIPTION:
# Verify that admin commands cannot race a pool export
#
# STRATEGY:
# 1. Create a pool
# 2. Import the pool with an injected delay in the background
# 3. Execute some admin commands against the pool
#
verify_runnable "global"
DEVICE_DIR=$TEST_BASE_DIR/dev_export-test
function cleanup
{
zinject -c all
poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
[[ -d $DEVICE_DIR ]] && log_must rm -rf $DEVICE_DIR
}
log_assert "admin commands cannot race a pool export"
log_onexit cleanup
[[ ! -d $DEVICE_DIR ]] && log_must mkdir -p $DEVICE_DIR
log_must truncate -s $MINVDEVSIZE ${DEVICE_DIR}/disk0 ${DEVICE_DIR}/disk1
log_must zpool create -f $TESTPOOL1 mirror ${DEVICE_DIR}/disk0 ${DEVICE_DIR}/disk1
log_must zinject -P export -s 10 $TESTPOOL1
log_must zpool export $TESTPOOL1 &
zpool set comment=hello $TESTPOOL1
zpool reguid $TESTPOOL1 &
zpool split $TESTPOOL1 &
log_pass "admin commands cannot race a pool export"
@@ -0,0 +1,129 @@
#!/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) 2024 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
# test uses 8 vdevs
MAX_NUM=8
DEVICE_DIR=$TEST_BASE_DIR/dev_import-test
#
# DESCRIPTION:
# Verify that pool exports can occur in parallel
#
# STRATEGY:
# 1. Create 8 pools
# 2. Inject an export delay using zinject
# 3. Export half of the pools synchronously to baseline sequential cost
# 4. Export the other half asynchronously to demonstrate parallel savings
# 6. Import 4 pools
# 7. Test zpool export -a
#
verify_runnable "global"
#
# override the minimum sized vdevs
#
POOLNAME="test_pool"
function cleanup
{
zinject -c all
for i in {0..$(($MAX_NUM - 1))}; do
poolexists $POOLNAME-$i && destroy_pool $POOLNAME-$i
done
[[ -d $DEVICE_DIR ]] && log_must rm -rf $DEVICE_DIR
}
log_assert "Pool exports can occur in parallel"
log_onexit cleanup
[[ ! -d $DEVICE_DIR ]] && log_must mkdir -p $DEVICE_DIR
#
# Create some pools with export delay injectors
#
for i in {0..$(($MAX_NUM - 1))}; do
log_must truncate -s $MINVDEVSIZE ${DEVICE_DIR}/disk$i
log_must zpool create $POOLNAME-$i $DEVICE_DIR/disk$i
log_must zinject -P export -s 8 $POOLNAME-$i
done
#
# Export half of the pools synchronously
#
SECONDS=0
for i in {0..3}; do
log_must zpool export $POOLNAME-$i
done
sequential_time=$SECONDS
log_note "sequentially exported 4 pools in $sequential_time seconds"
#
# Export half of the pools in parallel
#
SECONDS=0
for i in {4..7}; do
log_must zpool export $POOLNAME-$i &
done
wait
parallel_time=$SECONDS
log_note "asyncronously exported 4 pools in $parallel_time seconds"
log_must test $parallel_time -lt $(($sequential_time / 3))
#
# import 4 pools with export delay injectors
#
for i in {4..7}; do
log_must zpool import -d $DEVICE_DIR/disk$i $POOLNAME-$i
log_must zinject -P export -s 8 $POOLNAME-$i
done
#
# now test zpool export -a
#
SECONDS=0
log_must zpool export -a
parallel_time=$SECONDS
log_note "asyncronously exported 4 pools, using '-a', in $parallel_time seconds"
log_must test $parallel_time -lt $(($sequential_time / 3))
log_pass "Pool exports occur in parallel"