forked from openzfs/zfs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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. Signed-off-by: Don Brady <[email protected]>
- Loading branch information
Showing
12 changed files
with
373 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
* Copyright (c) 2017, Intel Corporation. | ||
* Copyright (c) 2021, Colm Buckley <[email protected]> | ||
* Copyright (c) 2023 Hewlett Packard Enterprise Development LP. | ||
* Copyright (c) 2024, Klara Inc. | ||
*/ | ||
|
||
/* | ||
|
@@ -1991,7 +1992,8 @@ spa_destroy_aux_threads(spa_t *spa) | |
static void | ||
spa_unload(spa_t *spa) | ||
{ | ||
ASSERT(MUTEX_HELD(&spa_namespace_lock)); | ||
ASSERT(MUTEX_HELD(&spa_namespace_lock) || | ||
spa->spa_export_thread == curthread); | ||
ASSERT(spa_state(spa) != POOL_STATE_UNINITIALIZED); | ||
|
||
spa_import_progress_remove(spa_guid(spa)); | ||
|
@@ -6955,7 +6957,7 @@ static int | |
spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, | ||
boolean_t force, boolean_t hardforce) | ||
{ | ||
int error; | ||
int error = 0; | ||
spa_t *spa; | ||
hrtime_t export_start = gethrtime(); | ||
|
||
|
@@ -6979,8 +6981,8 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, | |
spa->spa_is_exporting = B_TRUE; | ||
|
||
/* | ||
* Put a hold on the pool, drop the namespace lock, stop async tasks, | ||
* reacquire the namespace lock, and see if we can export. | ||
* Put a hold on the pool, drop the namespace lock, stop async tasks | ||
* and see if we can export. | ||
*/ | ||
spa_open_ref(spa, FTAG); | ||
mutex_exit(&spa_namespace_lock); | ||
|
@@ -6990,10 +6992,18 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, | |
taskq_wait(spa->spa_zvol_taskq); | ||
} | ||
mutex_enter(&spa_namespace_lock); | ||
spa->spa_export_thread = curthread; | ||
spa_close(spa, FTAG); | ||
mutex_exit(&spa_namespace_lock); | ||
|
||
/* | ||
* At this point we no longer hold the spa_namespace_lock and | ||
* the spa_export_thread indicates that an export is in progress. | ||
*/ | ||
|
||
if (spa->spa_state == POOL_STATE_UNINITIALIZED) | ||
goto export_spa; | ||
|
||
/* | ||
* The pool will be in core if it's openable, in which case we can | ||
* modify its state. Objsets may be open only because they're dirty, | ||
|
@@ -7089,6 +7099,10 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, | |
if (oldconfig && spa->spa_config) | ||
*oldconfig = fnvlist_dup(spa->spa_config); | ||
|
||
if (new_state == POOL_STATE_EXPORTED) | ||
zio_handle_export_delay(spa, gethrtime() - export_start); | ||
|
||
mutex_enter(&spa_namespace_lock); | ||
if (new_state != POOL_STATE_UNINITIALIZED) { | ||
if (!hardforce) | ||
spa_write_cachefile(spa, B_TRUE, B_TRUE, B_FALSE); | ||
|
@@ -7100,17 +7114,25 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, | |
* we make sure to reset the exporting flag. | ||
*/ | ||
spa->spa_is_exporting = B_FALSE; | ||
spa->spa_export_thread = NULL; | ||
} | ||
|
||
if (new_state == POOL_STATE_EXPORTED) | ||
zio_handle_export_delay(spa, gethrtime() - export_start); | ||
|
||
/* | ||
* Wake up any waiters on spa_namespace_lock | ||
* They need to re-attempt a spa_lookup() | ||
*/ | ||
cv_broadcast(&spa_namespace_cv); | ||
mutex_exit(&spa_namespace_lock); | ||
return (0); | ||
|
||
fail: | ||
mutex_enter(&spa_namespace_lock); | ||
spa->spa_is_exporting = B_FALSE; | ||
spa->spa_export_thread = NULL; | ||
spa_async_resume(spa); | ||
|
||
/* Wake up any waiters on spa_namespace_lock */ | ||
cv_broadcast(&spa_namespace_cv); | ||
mutex_exit(&spa_namespace_lock); | ||
return (error); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,7 @@ | |
* Copyright (c) 2017 Datto Inc. | ||
* Copyright (c) 2017, Intel Corporation. | ||
* Copyright (c) 2019, loli10K <[email protected]>. All rights reserved. | ||
* Copyright (c) 2023, Klara Inc. | ||
* Copyright (c) 2023, 2024, Klara Inc. | ||
*/ | ||
|
||
#include <sys/zfs_context.h> | ||
|
@@ -82,8 +82,8 @@ | |
* - Check if spa_refcount is zero | ||
* - Rename a spa_t | ||
* - add/remove/attach/detach devices | ||
* - Held for the duration of create/destroy/export | ||
* - Held at the start and end of import | ||
* - Held for the duration of create/destroy | ||
* - Held at the start and end of import and export | ||
* | ||
* It does not need to handle recursion. A create or destroy may | ||
* reference objects (files or zvols) in other pools, but by | ||
|
@@ -635,8 +635,14 @@ spa_lookup(const char *name) | |
if (spa == NULL) | ||
return (NULL); | ||
|
||
if (spa->spa_load_thread != NULL && | ||
spa->spa_load_thread != curthread) { | ||
/* | ||
* Avoid racing with import/export, which don't hold the namespace | ||
* lock for their entire duration. | ||
*/ | ||
if ((spa->spa_load_thread != NULL && | ||
spa->spa_load_thread != curthread) || | ||
(spa->spa_export_thread != NULL && | ||
spa->spa_export_thread != curthread)) { | ||
cv_wait(&spa_namespace_cv, &spa_namespace_lock); | ||
goto retry; | ||
} | ||
|
@@ -937,14 +943,15 @@ spa_open_ref(spa_t *spa, const void *tag) | |
|
||
/* | ||
* Remove a reference to the given spa_t. Must have at least one reference, or | ||
* have the namespace lock held. | ||
* have the namespace lock held or be part of a pool import/export. | ||
*/ | ||
void | ||
spa_close(spa_t *spa, const void *tag) | ||
{ | ||
ASSERT(zfs_refcount_count(&spa->spa_refcount) > spa->spa_minref || | ||
MUTEX_HELD(&spa_namespace_lock) || | ||
spa->spa_load_thread == curthread); | ||
spa->spa_load_thread == curthread || | ||
spa->spa_export_thread == curthread); | ||
(void) zfs_refcount_remove(&spa->spa_refcount, tag); | ||
} | ||
|
||
|
@@ -964,13 +971,15 @@ spa_async_close(spa_t *spa, const void *tag) | |
|
||
/* | ||
* Check to see if the spa refcount is zero. Must be called with | ||
* spa_namespace_lock held. We really compare against spa_minref, which is the | ||
* number of references acquired when opening a pool | ||
* spa_namespace_lock held or be the spa export thread. We really | ||
* compare against spa_minref, which is the number of references | ||
* acquired when opening a pool | ||
*/ | ||
boolean_t | ||
spa_refcount_zero(spa_t *spa) | ||
{ | ||
ASSERT(MUTEX_HELD(&spa_namespace_lock)); | ||
ASSERT(MUTEX_HELD(&spa_namespace_lock) || | ||
spa->spa_export_thread == curthread); | ||
|
||
return (zfs_refcount_count(&spa->spa_refcount) == spa->spa_minref); | ||
} | ||
|
@@ -1218,6 +1227,21 @@ spa_vdev_enter(spa_t *spa) | |
mutex_enter(&spa->spa_vdev_top_lock); | ||
mutex_enter(&spa_namespace_lock); | ||
|
||
/* | ||
* We have a reference on the spa and a spa export could be | ||
* starting but no longer holding the spa_namespace_lock. So | ||
* check if there is an export and if so wait. It will fail | ||
* fast (EBUSY) since we are still holding a spa reference. | ||
* | ||
* Note that we can be woken by a different spa transitioning | ||
* through an import/export, so we must wait for our condition | ||
* to change before proceeding. | ||
*/ | ||
while (spa->spa_export_thread != NULL && | ||
spa->spa_export_thread != curthread) { | ||
cv_wait(&spa_namespace_cv, &spa_namespace_lock); | ||
} | ||
|
||
vdev_autotrim_stop_all(spa); | ||
|
||
return (spa_vdev_config_enter(spa)); | ||
|
@@ -1235,6 +1259,12 @@ spa_vdev_detach_enter(spa_t *spa, uint64_t guid) | |
mutex_enter(&spa->spa_vdev_top_lock); | ||
mutex_enter(&spa_namespace_lock); | ||
|
||
/* See comment in spa_vdev_enter() */ | ||
while (spa->spa_export_thread != NULL && | ||
spa->spa_export_thread != curthread) { | ||
cv_wait(&spa_namespace_cv, &spa_namespace_lock); | ||
} | ||
|
||
vdev_autotrim_stop_all(spa); | ||
|
||
if (guid != 0) { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.