mirror of
https://git.yoctoproject.org/meta-ti
synced 2026-07-16 22:38:04 +00:00
bb34e69f3d
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> Signed-off-by: Denys Dmytriyenko <denys@ti.com>
98 lines
3.2 KiB
Diff
98 lines
3.2 KiB
Diff
From 250082bf56c6157c888f21df27d73475cb6f0065 Mon Sep 17 00:00:00 2001
|
|
From: NeilBrown <neilb@suse.de>
|
|
Date: Mon, 19 Mar 2012 12:46:38 +1100
|
|
Subject: [PATCH 068/147] md/raid1,raid10: avoid deadlock during
|
|
resync/recovery.
|
|
|
|
commit d6b42dcb995e6acd7cc276774e751ffc9f0ef4bf upstream.
|
|
|
|
If RAID1 or RAID10 is used under LVM or some other stacking
|
|
block device, it is possible to enter a deadlock during
|
|
resync or recovery.
|
|
This can happen if the upper level block device creates
|
|
two requests to the RAID1 or RAID10. The first request gets
|
|
processed, blocks recovery and queue requests for underlying
|
|
requests in current->bio_list. A resync request then starts
|
|
which will wait for those requests and block new IO.
|
|
|
|
But then the second request to the RAID1/10 will be attempted
|
|
and it cannot progress until the resync request completes,
|
|
which cannot progress until the underlying device requests complete,
|
|
which are on a queue behind that second request.
|
|
|
|
So allow that second request to proceed even though there is
|
|
a resync request about to start.
|
|
|
|
This is suitable for any -stable kernel.
|
|
|
|
Reported-by: Ray Morris <support@bettercgi.com>
|
|
Tested-by: Ray Morris <support@bettercgi.com>
|
|
Signed-off-by: NeilBrown <neilb@suse.de>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
---
|
|
drivers/md/raid1.c | 17 +++++++++++++++--
|
|
drivers/md/raid10.c | 17 +++++++++++++++--
|
|
2 files changed, 30 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
|
|
index 7d9e071..7af60ec 100644
|
|
--- a/drivers/md/raid1.c
|
|
+++ b/drivers/md/raid1.c
|
|
@@ -731,9 +731,22 @@ static void wait_barrier(struct r1conf *conf)
|
|
spin_lock_irq(&conf->resync_lock);
|
|
if (conf->barrier) {
|
|
conf->nr_waiting++;
|
|
- wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
|
|
+ /* Wait for the barrier to drop.
|
|
+ * However if there are already pending
|
|
+ * requests (preventing the barrier from
|
|
+ * rising completely), and the
|
|
+ * pre-process bio queue isn't empty,
|
|
+ * then don't wait, as we need to empty
|
|
+ * that queue to get the nr_pending
|
|
+ * count down.
|
|
+ */
|
|
+ wait_event_lock_irq(conf->wait_barrier,
|
|
+ !conf->barrier ||
|
|
+ (conf->nr_pending &&
|
|
+ current->bio_list &&
|
|
+ !bio_list_empty(current->bio_list)),
|
|
conf->resync_lock,
|
|
- );
|
|
+ );
|
|
conf->nr_waiting--;
|
|
}
|
|
conf->nr_pending++;
|
|
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
|
|
index 685ddf3..b219449 100644
|
|
--- a/drivers/md/raid10.c
|
|
+++ b/drivers/md/raid10.c
|
|
@@ -790,9 +790,22 @@ static void wait_barrier(struct r10conf *conf)
|
|
spin_lock_irq(&conf->resync_lock);
|
|
if (conf->barrier) {
|
|
conf->nr_waiting++;
|
|
- wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
|
|
+ /* Wait for the barrier to drop.
|
|
+ * However if there are already pending
|
|
+ * requests (preventing the barrier from
|
|
+ * rising completely), and the
|
|
+ * pre-process bio queue isn't empty,
|
|
+ * then don't wait, as we need to empty
|
|
+ * that queue to get the nr_pending
|
|
+ * count down.
|
|
+ */
|
|
+ wait_event_lock_irq(conf->wait_barrier,
|
|
+ !conf->barrier ||
|
|
+ (conf->nr_pending &&
|
|
+ current->bio_list &&
|
|
+ !bio_list_empty(current->bio_list)),
|
|
conf->resync_lock,
|
|
- );
|
|
+ );
|
|
conf->nr_waiting--;
|
|
}
|
|
conf->nr_pending++;
|
|
--
|
|
1.7.9.4
|
|
|