diff options
author | NeilBrown <neilb@suse.com> | 2017-10-19 12:17:16 +1100 |
---|---|---|
committer | Shaohua Li <shli@fb.com> | 2017-11-01 21:32:18 -0700 |
commit | 4d5324f760aacaefeb721b172aa14bf66045c332 (patch) | |
tree | 4115e3a5b37b7890c402d07ce551648b93f63844 /drivers/md/dm-raid.c | |
parent | 230b55fa8d64007339319539f8f8e68114d08529 (diff) | |
download | linux-stable-4d5324f760aacaefeb721b172aa14bf66045c332.tar.gz linux-stable-4d5324f760aacaefeb721b172aa14bf66045c332.tar.bz2 linux-stable-4d5324f760aacaefeb721b172aa14bf66045c332.zip |
md: always hold reconfig_mutex when calling mddev_suspend()
Most often mddev_suspend() is called with
reconfig_mutex held. Make this a requirement in
preparation a subsequent patch. Also require
reconfig_mutex to be held for mddev_resume(),
partly for symmetry and partly to guarantee
no races with incr/decr of mddev->suspend.
Taking the mutex in r5c_disable_writeback_async() is
a little tricky as this is called from a work queue
via log->disable_writeback_work, and flush_work()
is called on that while holding ->reconfig_mutex.
If the work item hasn't run before flush_work()
is called, the work function will not be able to
get the mutex.
So we use mddev_trylock() inside the wait_event() call, and have that
abort when conf->log is set to NULL, which happens before
flush_work() is called.
We wait in mddev->sb_wait and ensure this is woken
when any of the conditions change. This requires
waking mddev->sb_wait in mddev_unlock(). This is only
like to trigger extra wake_ups of threads that needn't
be woken when metadata is being written, and that
doesn't happen often enough that the cost would be
noticeable.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Shaohua Li <shli@fb.com>
Diffstat (limited to 'drivers/md/dm-raid.c')
-rw-r--r-- | drivers/md/dm-raid.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 252770696a05..8b1d93114f40 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -3628,8 +3628,11 @@ static void raid_postsuspend(struct dm_target *ti) { struct raid_set *rs = ti->private; - if (!test_and_set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) + if (!test_and_set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) { + mddev_lock_nointr(&rs->md); mddev_suspend(&rs->md); + mddev_unlock(&rs->md); + } rs->md.ro = 1; } @@ -3886,8 +3889,11 @@ static void raid_resume(struct dm_target *ti) if (!(rs->ctr_flags & RESUME_STAY_FROZEN_FLAGS)) clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); - if (test_and_clear_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) + if (test_and_clear_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) { + mddev_lock_nointr(mddev); mddev_resume(mddev); + mddev_unlock(mddev); + } } static struct target_type raid_target = { |