summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorOlaf Faaland <[email protected]>2017-07-24 08:48:28 -0700
committerBrian Behlendorf <[email protected]>2017-07-25 12:25:05 -0400
commitffb195c256f8a74a87c3834258ec90c513d66adb (patch)
tree07c0c43142ed997d8d5105ca05c802a859b8cd77 /module
parentf43615d0cc22d7db496c1291c84e64e269ca51d9 (diff)
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 <[email protected]> Signed-off-by: Olaf Faaland <[email protected]> Closes #6394
Diffstat (limited to 'module')
-rw-r--r--module/zfs/mmp.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/module/zfs/mmp.c b/module/zfs/mmp.c
index ae5478a33..539b76826 100644
--- a/module/zfs/mmp.c
+++ b/module/zfs/mmp.c
@@ -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,