md: separate request handling
authorShaohua Li <shli@fb.com>
Thu, 21 Sep 2017 17:23:35 +0000 (10:23 -0700)
committerShaohua Li <shli@fb.com>
Thu, 28 Sep 2017 03:07:40 +0000 (20:07 -0700)
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@stratus.com>
Fix: cc27b0c78c79(md: fix deadlock between mddev_suspend() and md_write_start())
Cc: stable@vger.kernel.org
Reviewed-by: NeilBrown <neilb@suse.com>
Signed-off-by: Shaohua Li <shli@fb.com>
drivers/md/md.c
drivers/md/md.h

index 08fcaeb..1db1a22 100644 (file)
@@ -266,6 +266,37 @@ 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.
  */
+void md_handle_request(struct mddev *mddev, struct bio *bio)
+{
+check_suspended:
+       rcu_read_lock();
+       if (mddev->suspended) {
+               DEFINE_WAIT(__wait);
+               for (;;) {
+                       prepare_to_wait(&mddev->sb_wait, &__wait,
+                                       TASK_UNINTERRUPTIBLE);
+                       if (!mddev->suspended)
+                               break;
+                       rcu_read_unlock();
+                       schedule();
+                       rcu_read_lock();
+               }
+               finish_wait(&mddev->sb_wait, &__wait);
+       }
+       atomic_inc(&mddev->active_io);
+       rcu_read_unlock();
+
+       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 blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
 {
        const int rw = bio_data_dir(bio);
@@ -285,23 +316,6 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
                bio_endio(bio);
                return BLK_QC_T_NONE;
        }
-check_suspended:
-       rcu_read_lock();
-       if (mddev->suspended) {
-               DEFINE_WAIT(__wait);
-               for (;;) {
-                       prepare_to_wait(&mddev->sb_wait, &__wait,
-                                       TASK_UNINTERRUPTIBLE);
-                       if (!mddev->suspended)
-                               break;
-                       rcu_read_unlock();
-                       schedule();
-                       rcu_read_lock();
-               }
-               finish_wait(&mddev->sb_wait, &__wait);
-       }
-       atomic_inc(&mddev->active_io);
-       rcu_read_unlock();
 
        /*
         * save the sectors now since our bio can
@@ -310,20 +324,14 @@ check_suspended:
        sectors = bio_sectors(bio);
        /* bio could be mergeable after passing to underlayer */
        bio->bi_opf &= ~REQ_NOMERGE;
-       if (!mddev->pers->make_request(mddev, bio)) {
-               atomic_dec(&mddev->active_io);
-               wake_up(&mddev->sb_wait);
-               goto check_suspended;
-       }
+
+       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);
-
        return BLK_QC_T_NONE;
 }
 
index 561d22b..d8287d3 100644 (file)
@@ -692,6 +692,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_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,