This is a note to let you know that I've just added the patch titled
raid1: prevent freeze_array/wait_all_barriers deadlock
to the 4.14-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git%3Ba=su...
The filename of the patch is: raid1-prevent-freeze_array-wait_all_barriers-deadlock.patch and it can be found in the queue-4.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let stable@vger.kernel.org know about it.
From f6eca2d43ed694ab8124dd24c88277f7eca93b7d Mon Sep 17 00:00:00 2001
From: Nate Dailey nate.dailey@stratus.com Date: Tue, 17 Oct 2017 08:17:03 -0400 Subject: raid1: prevent freeze_array/wait_all_barriers deadlock
From: Nate Dailey nate.dailey@stratus.com
commit f6eca2d43ed694ab8124dd24c88277f7eca93b7d upstream.
If freeze_array is attempted in the middle of close_sync/ wait_all_barriers, deadlock can occur.
freeze_array will wait for nr_pending and nr_queued to line up. wait_all_barriers increments nr_pending for each barrier bucket, one at a time, but doesn't actually issue IO that could be counted in nr_queued. So freeze_array is blocked until wait_all_barriers completes and allow_all_barriers runs. At the same time, when _wait_barrier sees array_frozen == 1, it stops and waits for freeze_array to complete.
Prevent the deadlock by making close_sync call _wait_barrier and _allow_barrier for one bucket at a time, instead of deferring the _allow_barrier calls until after all _wait_barriers are complete.
Signed-off-by: Nate Dailey nate.dailey@stratus.com Fix: fd76863e37fe(RAID1: a new I/O barrier implementation to remove resync window) Reviewed-by: Coly Li colyli@suse.de Signed-off-by: Shaohua Li shli@fb.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/md/raid1.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-)
--- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -990,14 +990,6 @@ static void wait_barrier(struct r1conf * _wait_barrier(conf, idx); }
-static void wait_all_barriers(struct r1conf *conf) -{ - int idx; - - for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++) - _wait_barrier(conf, idx); -} - static void _allow_barrier(struct r1conf *conf, int idx) { atomic_dec(&conf->nr_pending[idx]); @@ -1011,14 +1003,6 @@ static void allow_barrier(struct r1conf _allow_barrier(conf, idx); }
-static void allow_all_barriers(struct r1conf *conf) -{ - int idx; - - for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++) - _allow_barrier(conf, idx); -} - /* conf->resync_lock should be held */ static int get_unqueued_pending(struct r1conf *conf) { @@ -1654,8 +1638,12 @@ static void print_conf(struct r1conf *co
static void close_sync(struct r1conf *conf) { - wait_all_barriers(conf); - allow_all_barriers(conf); + int idx; + + for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++) { + _wait_barrier(conf, idx); + _allow_barrier(conf, idx); + }
mempool_destroy(conf->r1buf_pool); conf->r1buf_pool = NULL;
Patches currently in stable-queue which might be from nate.dailey@stratus.com are
queue-4.14/raid1-prevent-freeze_array-wait_all_barriers-deadlock.patch
linux-stable-mirror@lists.linaro.org