btrfs: add an ordered_extent pointer to struct btrfs_bio
authorChristoph Hellwig <hch@lst.de>
Wed, 31 May 2023 07:54:02 +0000 (09:54 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 19 Jun 2023 11:59:36 +0000 (13:59 +0200)
Add a pointer to the ordered_extent to the existing union in struct
btrfs_bio, so all code dealing with data write bios can just use a
pointer dereference to retrieve the ordered_extent instead of doing
multiple rbtree lookups per I/O.

The reference to this ordered_extent is dropped at end I/O time,
which implies that an extra one must be acquired when the bio is split.
This also requires moving the btrfs_extract_ordered_extent call into
btrfs_split_bio so that the invariant of always having a valid
ordered_extent reference for the btrfs_bio is kept.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.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/bio.c
fs/btrfs/bio.h
fs/btrfs/compression.c
fs/btrfs/extent_io.c
fs/btrfs/file-item.c
fs/btrfs/inode.c

index 41a152e8742948d1c77f8a4f63f3249bd449bda7..12b12443efaabb338a93e46ef70421c5881035d8 100644 (file)
@@ -33,6 +33,11 @@ static inline bool is_data_bbio(struct btrfs_bio *bbio)
        return bbio->inode && is_data_inode(&bbio->inode->vfs_inode);
 }
 
+static bool bbio_has_ordered_extent(struct btrfs_bio *bbio)
+{
+       return is_data_bbio(bbio) && btrfs_op(&bbio->bio) == BTRFS_MAP_WRITE;
+}
+
 /*
  * Initialize a btrfs_bio structure.  This skips the embedded bio itself as it
  * is already initialized by the block layer.
@@ -88,11 +93,40 @@ static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info,
        bbio->inode = orig_bbio->inode;
        bbio->file_offset = orig_bbio->file_offset;
        orig_bbio->file_offset += map_length;
-
+       if (bbio_has_ordered_extent(bbio)) {
+               refcount_inc(&orig_bbio->ordered->refs);
+               bbio->ordered = orig_bbio->ordered;
+       }
        atomic_inc(&orig_bbio->pending_ios);
        return bbio;
 }
 
+/* Free a bio that was never submitted to the underlying device. */
+static void btrfs_cleanup_bio(struct btrfs_bio *bbio)
+{
+       if (bbio_has_ordered_extent(bbio))
+               btrfs_put_ordered_extent(bbio->ordered);
+       bio_put(&bbio->bio);
+}
+
+static void __btrfs_bio_end_io(struct btrfs_bio *bbio)
+{
+       if (bbio_has_ordered_extent(bbio)) {
+               struct btrfs_ordered_extent *ordered = bbio->ordered;
+
+               bbio->end_io(bbio);
+               btrfs_put_ordered_extent(ordered);
+       } else {
+               bbio->end_io(bbio);
+       }
+}
+
+void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
+{
+       bbio->bio.bi_status = status;
+       __btrfs_bio_end_io(bbio);
+}
+
 static void btrfs_orig_write_end_io(struct bio *bio);
 
 static void btrfs_bbio_propagate_error(struct btrfs_bio *bbio,
@@ -121,12 +155,12 @@ static void btrfs_orig_bbio_end_io(struct btrfs_bio *bbio)
 
                if (bbio->bio.bi_status)
                        btrfs_bbio_propagate_error(bbio, orig_bbio);
-               bio_put(&bbio->bio);
+               btrfs_cleanup_bio(bbio);
                bbio = orig_bbio;
        }
 
        if (atomic_dec_and_test(&bbio->pending_ios))
-               bbio->end_io(bbio);
+               __btrfs_bio_end_io(bbio);
 }
 
 static int next_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
@@ -684,7 +718,7 @@ done:
 
 fail_put_bio:
        if (map_length < length)
-               bio_put(bio);
+               btrfs_cleanup_bio(bbio);
 fail:
        btrfs_bio_counter_dec(fs_info);
        btrfs_bio_end_io(orig_bbio, ret);
index 52e7962103fff2fedb346ea71aa5763be6ffc08e..ca79decee0607fb0df6c46967bbdc20cc05b2022 100644 (file)
@@ -50,11 +50,13 @@ struct btrfs_bio {
 
                /*
                 * For data writes:
+                * - ordered extent covering the bio
                 * - pointer to the checksums for this bio
                 * - original physical address from the allocator
                 *   (for zone append only)
                 */
                struct {
+                       struct btrfs_ordered_extent *ordered;
                        struct btrfs_ordered_sum *sums;
                        u64 orig_physical;
                };
@@ -95,12 +97,7 @@ void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info,
 struct btrfs_bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
                                  struct btrfs_fs_info *fs_info,
                                  btrfs_bio_end_io_t end_io, void *private);
-
-static inline void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
-{
-       bbio->bio.bi_status = status;
-       bbio->end_io(bbio);
-}
+void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status);
 
 /* Submit using blkcg_punt_bio_submit. */
 #define REQ_BTRFS_CGROUP_PUNT                  REQ_FS_PRIVATE
index aafc846bcd4fb60bdbf4dce69615e8af910706a8..ce4be0f21c5cf8ae44edb38956597b694069ba39 100644 (file)
@@ -303,10 +303,10 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
        INIT_WORK(&cb->write_end_work, btrfs_finish_compressed_write_work);
        cb->nr_pages = nr_pages;
        cb->bbio.bio.bi_iter.bi_sector = ordered->disk_bytenr >> SECTOR_SHIFT;
+       cb->bbio.ordered = ordered;
        btrfs_add_compressed_bio_pages(cb);
 
        btrfs_submit_bio(&cb->bbio, 0);
-       btrfs_put_ordered_extent(ordered);
 }
 
 /*
index 35141a223a3ec5b74e17113add2082cea2e5e559..ad536eaf02b00c311841d1af6e3250f808315b54 100644 (file)
@@ -835,7 +835,7 @@ static void alloc_new_bio(struct btrfs_inode *inode,
                        bio_ctrl->len_to_oe_boundary = min_t(u32, U32_MAX,
                                        ordered->file_offset +
                                        ordered->disk_num_bytes - file_offset);
-                       btrfs_put_ordered_extent(ordered);
+                       bbio->ordered = ordered;
                }
 
                /*
index 782bbf081c26b5aa7f64d52369773f43fb49e4b0..cbacaa80526c3f28f4e44a4aab9ddbea1fc88816 100644 (file)
@@ -799,19 +799,12 @@ blk_status_t btrfs_csum_one_bio(struct btrfs_bio *bbio)
  */
 blk_status_t btrfs_alloc_dummy_sum(struct btrfs_bio *bbio)
 {
-       struct btrfs_ordered_extent *ordered =
-               btrfs_lookup_ordered_extent(bbio->inode, bbio->file_offset);
-
-       if (WARN_ON_ONCE(!ordered))
-               return BLK_STS_IOERR;
-
        bbio->sums = kmalloc(sizeof(*bbio->sums), GFP_NOFS);
        if (!bbio->sums)
                return BLK_STS_RESOURCE;
        bbio->sums->len = bbio->bio.bi_iter.bi_size;
        bbio->sums->logical = bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT;
-       btrfs_add_ordered_sum(ordered, bbio->sums);
-       btrfs_put_ordered_extent(ordered);
+       btrfs_add_ordered_sum(bbio->ordered, bbio->sums);
        return 0;
 }
 
index 020d871bb1359b633b3168b676264a432747e43b..b8ec3d95e6591ff92c3ae0e243d4a4b936395da4 100644 (file)
@@ -2716,8 +2716,11 @@ static int btrfs_extract_ordered_extent(struct btrfs_bio *bbio,
                return -EINVAL;
 
        /* No need to split if the ordered extent covers the entire bio. */
-       if (ordered->disk_num_bytes == len)
+       if (ordered->disk_num_bytes == len) {
+               refcount_inc(&ordered->refs);
+               bbio->ordered = ordered;
                return 0;
+       }
 
        /*
         * Don't split the extent_map for NOCOW extents, as we're writing into
@@ -2734,8 +2737,7 @@ static int btrfs_extract_ordered_extent(struct btrfs_bio *bbio,
        new = btrfs_split_ordered_extent(ordered, len);
        if (IS_ERR(new))
                return PTR_ERR(new);
-       btrfs_put_ordered_extent(new);
-
+       bbio->ordered = new;
        return 0;
 }