]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
md: improve handling of bio with REQ_PREFLUSH in md_flush_request()
authorDavid Jeffery <djeffery@redhat.com>
Mon, 16 Sep 2019 17:15:14 +0000 (13:15 -0400)
committerMarcelo Henrique Cerri <marcelo.cerri@canonical.com>
Fri, 17 Jan 2020 17:23:03 +0000 (14:23 -0300)
BugLink: https://bugs.launchpad.net/bugs/1857158
commit 775d78319f1ceb32be8eb3b1202ccdc60e9cb7f1 upstream.

If pers->make_request fails in md_flush_request(), the bio is lost. To
fix this, pass back a bool to indicate if the original make_request call
should continue to handle the I/O and instead of assuming the flush logic
will push it to completion.

Convert md_flush_request to return a bool and no longer calls the raid
driver's make_request function.  If the return is true, then the md flush
logic has or will complete the bio and the md make_request call is done.
If false, then the md make_request function needs to keep processing like
it is a normal bio. Let the original call to md_handle_request handle any
need to retry sending the bio to the raid driver's make_request function
should it be needed.

Also mark md_flush_request and the make_request function pointer as
__must_check to issue warnings should these critical return values be
ignored.

Fixes: 2bc13b83e629 ("md: batch flush requests.")
Cc: stable@vger.kernel.org # # v4.19+
Cc: NeilBrown <neilb@suse.com>
Signed-off-by: David Jeffery <djeffery@redhat.com>
Reviewed-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/md/md-linear.c
drivers/md/md-multipath.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c

index c8fb680bb9527a964a6142d597e20d0b893e481b..c92364bb3df024217d2ab90e2666c60e857d5b12 100644 (file)
@@ -252,10 +252,9 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
        sector_t start_sector, end_sector, data_offset;
        sector_t bio_sector = bio->bi_iter.bi_sector;
 
-       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-               md_flush_request(mddev, bio);
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+           && md_flush_request(mddev, bio))
                return true;
-       }
 
        tmp_dev = which_dev(mddev, bio_sector);
        start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors;
index e40065bdbfc84ef8455dbcc88d6a3208a6780571..de4b727b4403578113a7049b52cbc22f58ed35f8 100644 (file)
@@ -112,10 +112,9 @@ static bool multipath_make_request(struct mddev *mddev, struct bio * bio)
        struct multipath_bh * mp_bh;
        struct multipath_info *multipath;
 
-       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-               md_flush_request(mddev, bio);
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+           && md_flush_request(mddev, bio))
                return true;
-       }
 
        mp_bh = mempool_alloc(conf->pool, GFP_NOIO);
 
index 2399e7e847bd7b72327f14ce4174c02c5966da77..81abd706f02932a3c1e85d3069ed63c443667e80 100644 (file)
@@ -493,7 +493,13 @@ static void md_submit_flush_data(struct work_struct *ws)
        }
 }
 
-void md_flush_request(struct mddev *mddev, struct bio *bio)
+/*
+ * Manages consolidation of flushes and submitting any flushes needed for
+ * a bio with REQ_PREFLUSH.  Returns true if the bio is finished or is
+ * being finished in another context.  Returns false if the flushing is
+ * complete but still needs the I/O portion of the bio to be processed.
+ */
+bool md_flush_request(struct mddev *mddev, struct bio *bio)
 {
        ktime_t start = ktime_get_boottime();
        spin_lock_irq(&mddev->lock);
@@ -518,9 +524,10 @@ void md_flush_request(struct mddev *mddev, struct bio *bio)
                        bio_endio(bio);
                else {
                        bio->bi_opf &= ~REQ_PREFLUSH;
-                       mddev->pers->make_request(mddev, bio);
+                       return false;
                }
        }
+       return true;
 }
 EXPORT_SYMBOL(md_flush_request);
 
index 06e13b83ab734341daca2e925a64246f03861b75..8960b462e0b26fc26e351dd42c1a1d5aab582cc4 100644 (file)
@@ -533,7 +533,7 @@ struct md_personality
        int level;
        struct list_head list;
        struct module *owner;
-       bool (*make_request)(struct mddev *mddev, struct bio *bio);
+       bool __must_check (*make_request)(struct mddev *mddev, struct bio *bio);
        int (*run)(struct mddev *mddev);
        void (*free)(struct mddev *mddev, void *priv);
        void (*status)(struct seq_file *seq, struct mddev *mddev);
@@ -679,7 +679,7 @@ extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
 extern void md_finish_reshape(struct mddev *mddev);
 
 extern int mddev_congested(struct mddev *mddev, int bits);
-extern void md_flush_request(struct mddev *mddev, struct bio *bio);
+extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
 extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
                           sector_t sector, int size, struct page *page);
 extern int md_super_wait(struct mddev *mddev);
index 5c5e4c538878e1fc57ebe731a3b0737fbfc27d5f..654e19a5b77ec88f67889ecd24810532640c5ed6 100644 (file)
@@ -559,10 +559,9 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
        unsigned chunk_sects;
        unsigned sectors;
 
-       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-               md_flush_request(mddev, bio);
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+           && md_flush_request(mddev, bio))
                return true;
-       }
 
        if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
                raid0_handle_discard(mddev, bio);
index a072e0b1154c0f6f6d73224836a9b8e116495d1c..9639607ff2e1073a66f6a9a49a87de75a1a1f878 100644 (file)
@@ -1516,10 +1516,9 @@ static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
 {
        sector_t sectors;
 
-       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-               md_flush_request(mddev, bio);
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+           && md_flush_request(mddev, bio))
                return true;
-       }
 
        /*
         * There is a limit to the maximum size, but
index 667ec57debaa28fe7cef0fc042a4af2616428d3d..9fb42859c230a0d3751f7cc8effcaeef9688acd4 100644 (file)
@@ -1548,10 +1548,9 @@ static bool raid10_make_request(struct mddev *mddev, struct bio *bio)
        int chunk_sects = chunk_mask + 1;
        int sectors = bio_sectors(bio);
 
-       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-               md_flush_request(mddev, bio);
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+           && md_flush_request(mddev, bio))
                return true;
-       }
 
        if (!md_write_start(mddev, bio))
                return false;
index e179a5fb03307eabef42335e18d5f83e76c542b3..31236349e25c2cd12ea03ff0777bfa8074095840 100644 (file)
@@ -5586,8 +5586,8 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
                if (ret == 0)
                        return true;
                if (ret == -ENODEV) {
-                       md_flush_request(mddev, bi);
-                       return true;
+                       if (md_flush_request(mddev, bi))
+                               return true;
                }
                /* ret == -EAGAIN, fallback */
                /*