btrfs: track the next file offset in struct btrfs_bio_ctrl
authorChristoph Hellwig <hch@lst.de>
Wed, 9 Apr 2025 11:10:36 +0000 (13:10 +0200)
committerDavid Sterba <dsterba@suse.com>
Thu, 15 May 2025 12:30:46 +0000 (14:30 +0200)
The bio implementation is not something we should really mess around,
and we shouldn't recalculate the pos from the folio over and over.
Instead just track then end of the current bio in logical file offsets
in the btrfs_bio_ctrl, which is much simpler and easier to read.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent_io.c

index 42e985826602c9aab24d625503fa252298092ccf..8366dde0979476868f2d39701a52f3e1b0fff1f3 100644 (file)
@@ -96,6 +96,8 @@ void btrfs_extent_buffer_leak_debug_check(struct btrfs_fs_info *fs_info)
  */
 struct btrfs_bio_ctrl {
        struct btrfs_bio *bbio;
+       /* Last byte contained in bbio + 1 . */
+       loff_t next_file_offset;
        enum btrfs_compression_type compress_type;
        u32 len_to_oe_boundary;
        blk_opf_t opf;
@@ -632,13 +634,10 @@ static int alloc_eb_folio_array(struct extent_buffer *eb, bool nofail)
 }
 
 static bool btrfs_bio_is_contig(struct btrfs_bio_ctrl *bio_ctrl,
-                               struct folio *folio, u64 disk_bytenr,
-                               unsigned int pg_offset)
+                               u64 disk_bytenr, loff_t file_offset)
 {
        struct bio *bio = &bio_ctrl->bbio->bio;
-       struct bio_vec *bvec = bio_last_bvec_all(bio);
        const sector_t sector = disk_bytenr >> SECTOR_SHIFT;
-       struct folio *bv_folio = page_folio(bvec->bv_page);
 
        if (bio_ctrl->compress_type != BTRFS_COMPRESS_NONE) {
                /*
@@ -649,19 +648,11 @@ static bool btrfs_bio_is_contig(struct btrfs_bio_ctrl *bio_ctrl,
        }
 
        /*
-        * The contig check requires the following conditions to be met:
-        *
-        * 1) The folios 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.
+        * To merge into a bio both the disk sector and the logical offset in
+        * the file need to be contiguous.
         */
-       return bio_end_sector(bio) == sector &&
-               folio_pos(bv_folio) + bvec->bv_offset + bvec->bv_len ==
-               folio_pos(folio) + pg_offset;
+       return bio_ctrl->next_file_offset == file_offset &&
+               bio_end_sector(bio) == sector;
 }
 
 static void alloc_new_bio(struct btrfs_inode *inode,
@@ -679,6 +670,7 @@ static void alloc_new_bio(struct btrfs_inode *inode,
        bbio->file_offset = file_offset;
        bio_ctrl->bbio = bbio;
        bio_ctrl->len_to_oe_boundary = U32_MAX;
+       bio_ctrl->next_file_offset = file_offset;
 
        /* Limit data write bios to the ordered boundary. */
        if (bio_ctrl->wbc) {
@@ -720,22 +712,21 @@ static void submit_extent_folio(struct btrfs_bio_ctrl *bio_ctrl,
                               size_t size, unsigned long pg_offset)
 {
        struct btrfs_inode *inode = folio_to_inode(folio);
+       loff_t file_offset = folio_pos(folio) + pg_offset;
 
        ASSERT(pg_offset + size <= folio_size(folio));
        ASSERT(bio_ctrl->end_io_func);
 
        if (bio_ctrl->bbio &&
-           !btrfs_bio_is_contig(bio_ctrl, folio, disk_bytenr, pg_offset))
+           !btrfs_bio_is_contig(bio_ctrl, disk_bytenr, file_offset))
                submit_one_bio(bio_ctrl);
 
        do {
                u32 len = size;
 
                /* Allocate new bio if needed */
-               if (!bio_ctrl->bbio) {
-                       alloc_new_bio(inode, bio_ctrl, disk_bytenr,
-                                     folio_pos(folio) + pg_offset);
-               }
+               if (!bio_ctrl->bbio)
+                       alloc_new_bio(inode, bio_ctrl, disk_bytenr, file_offset);
 
                /* Cap to the current ordered extent boundary if there is one. */
                if (len > bio_ctrl->len_to_oe_boundary) {
@@ -749,14 +740,15 @@ static void submit_extent_folio(struct btrfs_bio_ctrl *bio_ctrl,
                        submit_one_bio(bio_ctrl);
                        continue;
                }
+               bio_ctrl->next_file_offset += len;
 
                if (bio_ctrl->wbc)
-                       wbc_account_cgroup_owner(bio_ctrl->wbc, folio,
-                                                len);
+                       wbc_account_cgroup_owner(bio_ctrl->wbc, folio, len);
 
                size -= len;
                pg_offset += len;
                disk_bytenr += len;
+               file_offset += len;
 
                /*
                 * len_to_oe_boundary defaults to U32_MAX, which isn't folio or