Release SCL_STATE in map_write_done()

The config lock must be held for the duration of the MMP write.
Since the I/Os are executed via map_nowait(), the done function
is the only place where we know the write has completed.

Since SCL_STATE is taken as reader, overlapping I/Os do not
create a deadlock.  The refcount is simply increased when new
I/Os are queued and decreased when I/Os complete.

Test case added which exercises the probe IO call path to
verify the fix and prevent a regression.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Olaf Faaland <faaland1@llnl.gov>
Closes #6394
This commit is contained in:
Olaf Faaland
2017-07-24 08:48:28 -07:00
committed by Brian Behlendorf
parent f43615d0cc
commit ffb195c256
4 changed files with 69 additions and 6 deletions
+6 -5
View File
@@ -287,6 +287,7 @@ mmp_write_done(zio_t *zio)
unlock:
mutex_exit(&mts->mmp_io_lock);
spa_config_exit(spa, SCL_STATE, FTAG);
abd_free(zio->io_abd);
}
@@ -322,9 +323,12 @@ mmp_write_uberblock(spa_t *spa)
int label;
uint64_t offset;
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
vd = vdev_random_leaf(spa);
if (vd == NULL || !vdev_writeable(vd))
if (vd == NULL || !vdev_writeable(vd)) {
spa_config_exit(spa, SCL_STATE, FTAG);
return;
}
mutex_enter(&mmp->mmp_io_lock);
@@ -437,11 +441,8 @@ mmp_thread(spa_t *spa)
zio_suspend(spa, NULL);
}
if (multihost) {
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
if (multihost)
mmp_write_uberblock(spa);
spa_config_exit(spa, SCL_STATE, FTAG);
}
CALLB_CPR_SAFE_BEGIN(&cpr);
(void) cv_timedwait_sig(&mmp->mmp_thread_cv,