]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
dm: respect REQ_NOWAIT flag in normal bios issued to DM
authorMike Snitzer <snitzer@kernel.org>
Wed, 25 Oct 2023 23:29:03 +0000 (19:29 -0400)
committerMike Snitzer <snitzer@kernel.org>
Fri, 27 Oct 2023 17:22:51 +0000 (13:22 -0400)
Update DM core's normal IO submission to allocate required memory
using GFP_NOWAIT if REQ_NOWAIT is set.

Tested with simple test provided in commit a9ce385344f916 ("dm: don't
attempt to queue IO under RCU protection") that was enhanced to check
error codes.  Also tested using fio's pvsync2 with nowait=1.

But testing with induced GFP_NOWAIT allocation failures wasn't
performed (yet).

Signed-off-by: Mike Snitzer <snitzer@kernel.org>
drivers/md/dm.c

index b5b1b220dfd64e54caa8c16272b8a1c011da8ba6..0dd8ddf40006b947a5a62c7bfd7b8ca091cb2b63 100644 (file)
@@ -570,13 +570,15 @@ static void dm_end_io_acct(struct dm_io *io)
        dm_io_acct(io, true);
 }
 
-static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio)
+static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio, gfp_t gfp_mask)
 {
        struct dm_io *io;
        struct dm_target_io *tio;
        struct bio *clone;
 
-       clone = bio_alloc_clone(NULL, bio, GFP_NOIO, &md->mempools->io_bs);
+       clone = bio_alloc_clone(NULL, bio, gfp_mask, &md->mempools->io_bs);
+       if (unlikely(!clone))
+               return NULL;
        tio = clone_to_tio(clone);
        tio->flags = 0;
        dm_tio_set_flag(tio, DM_TIO_INSIDE_DM_IO);
@@ -1714,10 +1716,6 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
        if (unlikely(!ti))
                return BLK_STS_IOERR;
 
-       if (unlikely((ci->bio->bi_opf & REQ_NOWAIT) != 0) &&
-           unlikely(!dm_target_supports_nowait(ti->type)))
-               return BLK_STS_NOTSUPP;
-
        if (unlikely(ci->is_abnormal_io))
                return __process_abnormal_io(ci, ti);
 
@@ -1729,7 +1727,17 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
 
        len = min_t(sector_t, max_io_len(ti, ci->sector), ci->sector_count);
        setup_split_accounting(ci, len);
-       clone = alloc_tio(ci, ti, 0, &len, GFP_NOIO);
+
+       if (unlikely(ci->bio->bi_opf & REQ_NOWAIT)) {
+               if (unlikely(!dm_target_supports_nowait(ti->type)))
+                       return BLK_STS_NOTSUPP;
+
+               clone = alloc_tio(ci, ti, 0, &len, GFP_NOWAIT);
+               if (unlikely(!clone))
+                       return BLK_STS_AGAIN;
+       } else {
+               clone = alloc_tio(ci, ti, 0, &len, GFP_NOIO);
+       }
        __map_bio(clone);
 
        ci->sector += len;
@@ -1738,11 +1746,11 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
        return BLK_STS_OK;
 }
 
-static void init_clone_info(struct clone_info *ci, struct mapped_device *md,
+static void init_clone_info(struct clone_info *ci, struct dm_io *io,
                            struct dm_table *map, struct bio *bio, bool is_abnormal)
 {
        ci->map = map;
-       ci->io = alloc_io(md, bio);
+       ci->io = io;
        ci->bio = bio;
        ci->is_abnormal_io = is_abnormal;
        ci->submit_as_polled = false;
@@ -1777,8 +1785,18 @@ static void dm_split_and_process_bio(struct mapped_device *md,
                        return;
        }
 
-       init_clone_info(&ci, md, map, bio, is_abnormal);
-       io = ci.io;
+       /* Only support nowait for normal IO */
+       if (unlikely(bio->bi_opf & REQ_NOWAIT) && !is_abnormal) {
+               io = alloc_io(md, bio, GFP_NOWAIT);
+               if (unlikely(!io)) {
+                       /* Unable to do anything without dm_io. */
+                       bio_wouldblock_error(bio);
+                       return;
+               }
+       } else {
+               io = alloc_io(md, bio, GFP_NOIO);
+       }
+       init_clone_info(&ci, io, map, bio, is_abnormal);
 
        if (bio->bi_opf & REQ_PREFLUSH) {
                __send_empty_flush(&ci);