Sync thread should avoid holding the spa config write lock when possible

spa_sync() currently grabs the write lock due to an old hack that is
documented by a comment:

    We need the write lock here because, for aux vdevs,
    calling vdev_config_dirty() modifies sav_config.
    This is ugly and will become unnecessary when we
    eliminate the aux vdev wart by integrating all vdevs
    into the root vdev tree.
 
This has lead to deadlocks in rare edge cases from holding the write 
lock. We can reduce incidence of these deadlocks by not grabbing the 
write lock on pools without auxillary vdevs.

Sponsored-By: Wasabi Technology, Inc.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Richard Yao <richard.yao@klarasystems.com>
Closes #14282
This commit is contained in:
Richard Yao 2023-02-16 17:10:52 -05:00 committed by GitHub
parent dc72c60ec1
commit 9f08b6e31f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -9281,7 +9281,13 @@ spa_sync(spa_t *spa, uint64_t txg)
* into config changes that go out with this transaction group. * into config changes that go out with this transaction group.
*/ */
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER); spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
while (list_head(&spa->spa_state_dirty_list) != NULL) { while ((vd = list_head(&spa->spa_state_dirty_list)) != NULL) {
/* Avoid holding the write lock unless actually necessary */
if (vd->vdev_aux == NULL) {
vdev_state_clean(vd);
vdev_config_dirty(vd);
continue;
}
/* /*
* We need the write lock here because, for aux vdevs, * We need the write lock here because, for aux vdevs,
* calling vdev_config_dirty() modifies sav_config. * calling vdev_config_dirty() modifies sav_config.