[RHEL7.4.z PATCH] md: separate request handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Rediffed for RHEL7.4.z.

Conflicts:
The return value of md_make_request is different from RHEL to upstream.
And RHEL7 MD code does not use bio->bi_opf, but bio->bi_rw.
-Nigel Croxon

commit 393debc23c7820211d1c8253dd6a8408a7628fe7
Author: Shaohua Li <shli@xxxxxx>
Date:   Thu Sep 21 10:23:35 2017 -0700

md: separate request handling

With commit cc27b0c78c79, pers->make_request could bail out without handling
the bio. If that happens, we should retry.  The commit fixes md_make_request
but not other call sites. Separate the request handling part, so other call
 sites can use it.

Reported-by: Nate Dailey <nate.dailey@xxxxxxxxxxx>
Fix: cc27b0c78c79(md: fix deadlock between mddev_suspend() and md_write_start())
Cc: stable@xxxxxxxxxxxxxxx
Reviewed-by: NeilBrown <neilb@xxxxxxxx>
Signed-off-by: Shaohua Li <shli@xxxxxx>
Signed-off-by: Denys Vlasenko <dvlasenk@xxxxxxxxxx>

diff --git a/drivers/md/md.c b/drivers/md/md.c
index 85fe7a99290..407e15f4bfe 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -248,21 +248,8 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
  * call has finished, the bio has been linked into some internal structure
  * and so is visible to ->quiesce(), so we don't need the refcount any more.
  */
-static void md_make_request(struct request_queue *q, struct bio *bio)
+void md_handle_request(struct mddev *mddev, struct bio *bio)
 {
-	const int rw = bio_data_dir(bio);
-	struct mddev *mddev = q->queuedata;
-	int cpu;
-	unsigned int sectors;
-
-	if (mddev == NULL || mddev->pers == NULL) {
-		bio_io_error(bio);
-		return;
-	}
-	if (mddev->ro == 1 && unlikely(rw == WRITE)) {
-		bio_endio(bio, bio_sectors(bio) == 0 ? 0 : -EROFS);
-		return;
-	}
 check_suspended:
 	smp_rmb(); /* Ensure implications of  'active' are visible */
 	rcu_read_lock();
@@ -282,24 +269,45 @@ check_suspended:
 	atomic_inc(&mddev->active_io);
 	rcu_read_unlock();
 
-	/*
-	 * save the sectors now since our bio can
-	 * go away inside make_request
-	 */
-	sectors = bio_sectors(bio);
 	if (!mddev->pers->make_request(mddev, bio)) {
 		atomic_dec(&mddev->active_io);
 		wake_up(&mddev->sb_wait);
 		goto check_suspended;
 	}
 
+	if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
+		wake_up(&mddev->sb_wait);
+}
+EXPORT_SYMBOL(md_handle_request);
+
+static void md_make_request(struct request_queue *q, struct bio *bio)
+{
+	const int rw = bio_data_dir(bio);
+	struct mddev *mddev = q->queuedata;
+	int cpu;
+	unsigned int sectors;
+
+	if (mddev == NULL || mddev->pers == NULL) {
+		bio_io_error(bio);
+		return;
+	}
+	if (mddev->ro == 1 && unlikely(rw == WRITE)) {
+		bio_endio(bio, bio_sectors(bio) == 0 ? 0 : -EROFS);
+		return;
+	}
+
+	/*
+	 * save the sectors now since our bio can
+	 * go away inside make_request
+	 */
+	sectors = bio_sectors(bio);
+
+	md_handle_request(mddev, bio);
+
 	cpu = part_stat_lock();
 	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
 	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors);
 	part_stat_unlock();
-
-	if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
-		wake_up(&mddev->sb_wait);
 }
 
 /* mddev_suspend makes sure no new requests are submitted
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 0d13bf88f41..12e19d6d373 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -679,6 +679,7 @@ extern void md_stop_writes(struct mddev *mddev);
 extern int md_rdev_init(struct md_rdev *rdev);
 extern void md_rdev_clear(struct md_rdev *rdev);
 
+extern void md_handle_request(struct mddev *mddev, struct bio *bio);
 extern void mddev_suspend(struct mddev *mddev);
 extern void mddev_resume(struct mddev *mddev);
 extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
-- 
2.16.2




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]