btrfs: stop allocation a btrfs_io_context for simple I/O
authorChristoph Hellwig <hch@lst.de>
Sat, 6 Aug 2022 08:03:30 +0000 (10:03 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 26 Sep 2022 10:27:59 +0000 (12:27 +0200)
The I/O context structure is only used to pass the btrfs_device to
the end I/O handler for I/Os that go to a single device.

Stop allocating the I/O context for these cases by passing the optional
btrfs_io_stripe argument to __btrfs_map_block to query the mapping
information and then using a fast path submission and I/O completion
handler.  As the old btrfs_io_context based I/O submission path is
only used for mirrored writes, rename the functions to make that
clear and stop setting the btrfs_bio device and mirror_num field
that is only used for reads.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Tested-by: Nikolay Borisov <nborisov@suse.com>
Tested-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/volumes.c

index 58c9993..1153a85 100644 (file)
@@ -6706,11 +6706,12 @@ static void btrfs_log_dev_io_error(struct bio *bio, struct btrfs_device *dev)
                btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_FLUSH_ERRS);
 }
 
-static struct workqueue_struct *btrfs_end_io_wq(struct btrfs_io_context *bioc)
+static struct workqueue_struct *btrfs_end_io_wq(struct btrfs_fs_info *fs_info,
+                                               struct bio *bio)
 {
-       if (bioc->orig_bio->bi_opf & REQ_META)
-               return bioc->fs_info->endio_meta_workers;
-       return bioc->fs_info->endio_workers;
+       if (bio->bi_opf & REQ_META)
+               return fs_info->endio_meta_workers;
+       return fs_info->endio_workers;
 }
 
 static void btrfs_end_bio_work(struct work_struct *work)
@@ -6721,6 +6722,24 @@ static void btrfs_end_bio_work(struct work_struct *work)
        bbio->end_io(bbio);
 }
 
+static void btrfs_simple_end_io(struct bio *bio)
+{
+       struct btrfs_fs_info *fs_info = bio->bi_private;
+       struct btrfs_bio *bbio = btrfs_bio(bio);
+
+       btrfs_bio_counter_dec(fs_info);
+
+       if (bio->bi_status)
+               btrfs_log_dev_io_error(bio, bbio->device);
+
+       if (bio_op(bio) == REQ_OP_READ) {
+               INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
+               queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work);
+       } else {
+               bbio->end_io(bbio);
+       }
+}
+
 static void btrfs_raid56_end_io(struct bio *bio)
 {
        struct btrfs_io_context *bioc = bio->bi_private;
@@ -6733,7 +6752,7 @@ static void btrfs_raid56_end_io(struct bio *bio)
        btrfs_put_bioc(bioc);
 }
 
-static void btrfs_end_bio(struct bio *bio)
+static void btrfs_orig_write_end_io(struct bio *bio)
 {
        struct btrfs_io_stripe *stripe = bio->bi_private;
        struct btrfs_io_context *bioc = stripe->bioc;
@@ -6746,8 +6765,6 @@ static void btrfs_end_bio(struct bio *bio)
                btrfs_log_dev_io_error(bio, stripe->dev);
        }
 
-       bbio->mirror_num = bioc->mirror_num;
-
        /*
         * Only send an error to the higher layers if it is beyond the tolerance
         * threshold.
@@ -6757,13 +6774,7 @@ static void btrfs_end_bio(struct bio *bio)
        else
                bio->bi_status = BLK_STS_OK;
 
-       if (btrfs_op(bio) == BTRFS_MAP_READ) {
-               INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
-               queue_work(btrfs_end_io_wq(bioc), &bbio->end_io_work);
-       } else {
-               bbio->end_io(bbio);
-       }
-
+       bbio->end_io(bbio);
        btrfs_put_bioc(bioc);
 }
 
@@ -6820,15 +6831,16 @@ static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio)
        submit_bio(bio);
 }
 
-static void submit_stripe_bio(struct btrfs_io_context *bioc, int dev_nr)
+static void btrfs_submit_mirrored_bio(struct btrfs_io_context *bioc, int dev_nr)
 {
        struct bio *orig_bio = bioc->orig_bio, *bio;
 
+       ASSERT(bio_op(orig_bio) != REQ_OP_READ);
+
        /* Reuse the bio embedded into the btrfs_bio for the last mirror */
        if (dev_nr == bioc->num_stripes - 1) {
                bio = orig_bio;
-               btrfs_bio(bio)->device = bioc->stripes[dev_nr].dev;
-               bio->bi_end_io = btrfs_end_bio;
+               bio->bi_end_io = btrfs_orig_write_end_io;
        } else {
                bio = bio_alloc_clone(NULL, orig_bio, GFP_NOFS, &fs_bio_set);
                bio_inc_remaining(orig_bio);
@@ -6846,34 +6858,19 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror
        u64 logical = bio->bi_iter.bi_sector << 9;
        u64 length = bio->bi_iter.bi_size;
        u64 map_length = length;
-       int ret;
-       int dev_nr;
-       int total_devs;
        struct btrfs_io_context *bioc = NULL;
+       struct btrfs_io_stripe smap;
+       int ret;
 
        btrfs_bio_counter_inc_blocked(fs_info);
        ret = __btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
-                               &bioc, NULL, &mirror_num, 1);
+                               &bioc, &smap, &mirror_num, 1);
        if (ret) {
                btrfs_bio_counter_dec(fs_info);
                btrfs_bio_end_io(btrfs_bio(bio), errno_to_blk_status(ret));
                return;
        }
 
-       total_devs = bioc->num_stripes;
-       bioc->orig_bio = bio;
-
-       if ((bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) &&
-           ((btrfs_op(bio) == BTRFS_MAP_WRITE) || (mirror_num > 1))) {
-               bio->bi_private = bioc;
-               bio->bi_end_io = btrfs_raid56_end_io;
-               if (btrfs_op(bio) == BTRFS_MAP_WRITE)
-                       raid56_parity_write(bio, bioc);
-               else
-                       raid56_parity_recover(bio, bioc, mirror_num);
-               return;
-       }
-
        if (map_length < length) {
                btrfs_crit(fs_info,
                           "mapping failed logical %llu bio len %llu len %llu",
@@ -6881,8 +6878,31 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror
                BUG();
        }
 
-       for (dev_nr = 0; dev_nr < total_devs; dev_nr++)
-               submit_stripe_bio(bioc, dev_nr);
+       if (!bioc) {
+               /* Single mirror read/write fast path */
+               btrfs_bio(bio)->mirror_num = mirror_num;
+               btrfs_bio(bio)->device = smap.dev;
+               bio->bi_iter.bi_sector = smap.physical >> SECTOR_SHIFT;
+               bio->bi_private = fs_info;
+               bio->bi_end_io = btrfs_simple_end_io;
+               btrfs_submit_dev_bio(smap.dev, bio);
+       } else if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+               /* Parity RAID write or read recovery */
+               bio->bi_private = bioc;
+               bio->bi_end_io = btrfs_raid56_end_io;
+               if (bio_op(bio) == REQ_OP_READ)
+                       raid56_parity_recover(bio, bioc, mirror_num);
+               else
+                       raid56_parity_write(bio, bioc);
+       } else {
+               /* Write to multiple mirrors */
+               int total_devs = bioc->num_stripes;
+               int dev_nr;
+
+               bioc->orig_bio = bio;
+               for (dev_nr = 0; dev_nr < total_devs; dev_nr++)
+                       btrfs_submit_mirrored_bio(bioc, dev_nr);
+       }
 }
 
 static bool dev_args_match_fs_devices(const struct btrfs_dev_lookup_args *args,