btrfs: check for contiguity in submit_extent_page
authorChristoph Hellwig <hch@lst.de>
Mon, 27 Feb 2023 15:17:03 +0000 (08:17 -0700)
committerDavid Sterba <dsterba@suse.com>
Mon, 17 Apr 2023 16:01:16 +0000 (18:01 +0200)
Different loop iterations in btrfs_bio_add_page not only have the same
contiguity parameters, but also any non-initial operation operates on a
fresh bio anyway.

Factor out the contiguity check into a new btrfs_bio_is_contig and only
call it once in submit_extent_page before descending into the
bio_add_page loop.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent_io.c

index 3d11298..305d262 100644 (file)
@@ -866,6 +866,38 @@ int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array)
        return 0;
 }
 
+static bool btrfs_bio_is_contig(struct btrfs_bio_ctrl *bio_ctrl,
+                               struct page *page, u64 disk_bytenr,
+                               unsigned int pg_offset)
+{
+       struct bio *bio = bio_ctrl->bio;
+       struct bio_vec *bvec = bio_last_bvec_all(bio);
+       const sector_t sector = disk_bytenr >> SECTOR_SHIFT;
+
+       if (bio_ctrl->compress_type != BTRFS_COMPRESS_NONE) {
+               /*
+                * For compression, all IO should have its logical bytenr set
+                * to the starting bytenr of the compressed extent.
+                */
+               return bio->bi_iter.bi_sector == sector;
+       }
+
+       /*
+        * The contig check requires the following conditions to be met:
+        *
+        * 1) The pages are belonging to the same inode
+        *    This is implied by the call chain.
+        *
+        * 2) The range has adjacent logical bytenr
+        *
+        * 3) The range has adjacent file offset
+        *    This is required for the usage of btrfs_bio->file_offset.
+        */
+       return bio_end_sector(bio) == sector &&
+               page_offset(bvec->bv_page) + bvec->bv_offset + bvec->bv_len ==
+               page_offset(page) + pg_offset;
+}
+
 /*
  * Attempt to add a page to bio.
  *
@@ -890,44 +922,11 @@ static int btrfs_bio_add_page(struct btrfs_bio_ctrl *bio_ctrl,
        struct bio *bio = bio_ctrl->bio;
        u32 bio_size = bio->bi_iter.bi_size;
        u32 real_size;
-       const sector_t sector = disk_bytenr >> SECTOR_SHIFT;
-       bool contig = false;
 
        ASSERT(bio);
        /* The limit should be calculated when bio_ctrl->bio is allocated */
        ASSERT(bio_ctrl->len_to_oe_boundary);
 
-       if (bio->bi_iter.bi_size == 0) {
-               /* We can always add a page into an empty bio. */
-               contig = true;
-       } else if (bio_ctrl->compress_type == BTRFS_COMPRESS_NONE) {
-               struct bio_vec *bvec = bio_last_bvec_all(bio);
-
-               /*
-                * The contig check requires the following conditions to be met:
-                * 1) The pages are belonging to the same inode
-                *    This is implied by the call chain.
-                *
-                * 2) The range has adjacent logical bytenr
-                *
-                * 3) The range has adjacent file offset
-                *    This is required for the usage of btrfs_bio->file_offset.
-                */
-               if (bio_end_sector(bio) == sector &&
-                   page_offset(bvec->bv_page) + bvec->bv_offset +
-                   bvec->bv_len == page_offset(page) + pg_offset)
-                       contig = true;
-       } else {
-               /*
-                * For compression, all IO should have its logical bytenr
-                * set to the starting bytenr of the compressed extent.
-                */
-               contig = bio->bi_iter.bi_sector == sector;
-       }
-
-       if (!contig)
-               return 0;
-
        real_size = min(bio_ctrl->len_to_oe_boundary - bio_size, size);
 
        /*
@@ -1024,6 +1023,10 @@ static void submit_extent_page(struct btrfs_bio_ctrl *bio_ctrl,
 
        ASSERT(bio_ctrl->end_io_func);
 
+       if (bio_ctrl->bio &&
+           !btrfs_bio_is_contig(bio_ctrl, page, disk_bytenr, pg_offset))
+               submit_one_bio(bio_ctrl);
+
        while (cur < pg_offset + size) {
                u32 offset = cur - pg_offset;
                int added;