Split the bio allocation out of __bh_submit() and the folio writeback
completion out of bh_end_async_write() into helpers, so that other
submit and completion paths can share them. This prevents code
duplication and code drift.

As this is a pure refactor the behavior of __bh_submit() and
bh_end_async_write() is unchanged.

Signed-off-by: Lukas Sichert <[email protected]>
---
 fs/buffer.c | 89 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 36 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index ed966fa73b1b..3389d866a85c 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -386,27 +386,10 @@ static void bh_end_async_read(struct bio *bio)
        end_buffer_async_read(bh, uptodate);
 }
 
-/**
- * bh_end_async_write - I/O end handler for async folio writes
- * @bio: The bio being completed.
- *
- * Pass this function to bh_submit() if you're doing the equivalent of
- * block_write_full_folio().  That is, the folio is unlocked, and will
- * have its writeback flag cleared once all async write buffers have
- * completed.
- */
-void bh_end_async_write(struct bio *bio)
+static void bh_complete_write(struct buffer_head *bh, bool success)
 {
-       struct buffer_head *bh;
-       bool success = bio_endio_bh(bio, &bh);
-       unsigned long flags;
-       struct buffer_head *first;
-       struct buffer_head *tmp;
-       struct folio *folio;
-
        BUG_ON(!buffer_async_write(bh));
 
-       folio = bh->b_folio;
        if (success) {
                set_buffer_uptodate(bh);
        } else {
@@ -414,8 +397,14 @@ void bh_end_async_write(struct bio *bio)
                mark_buffer_write_io_error(bh);
                clear_buffer_uptodate(bh);
        }
+}
+
+static void bh_complete_folio_write(struct folio *folio, struct buffer_head 
*bh)
+{
+       struct buffer_head *first = folio_buffers(folio);
+       struct buffer_head *tmp;
+       unsigned long flags;
 
-       first = folio_buffers(folio);
        spin_lock_irqsave(&first->b_uptodate_lock, flags);
 
        clear_buffer_async_write(bh);
@@ -435,6 +424,25 @@ void bh_end_async_write(struct bio *bio)
 still_busy:
        spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
 }
+
+/**
+ * bh_end_async_write - I/O end handler for async folio writes
+ * @bio: The bio being completed.
+ *
+ * Pass this function to bh_submit() if you're doing the equivalent of
+ * block_write_full_folio().  That is, the folio is unlocked, and will
+ * have its writeback flag cleared once all async write buffers have
+ * completed.
+ */
+void bh_end_async_write(struct bio *bio)
+{
+       struct buffer_head *bh;
+       bool success = bio_endio_bh(bio, &bh);
+       struct folio *folio = bh->b_folio;
+
+       bh_complete_write(bh, success);
+       bh_complete_folio_write(folio, bh);
+}
 EXPORT_SYMBOL(bh_end_async_write);
 
 
@@ -1082,24 +1090,11 @@ static void buffer_set_crypto_ctx(struct bio *bio, 
const struct buffer_head *bh,
                        folio_pos(bh->b_folio) + bh_offset(bh), gfp_mask);
 }
 
-static void __bh_submit(struct buffer_head *bh, blk_opf_t opf,
-               enum rw_hint write_hint, struct writeback_control *wbc,
-               bio_end_io_t end_bio)
+static struct bio *bh_bio_alloc(struct buffer_head *bh, blk_opf_t opf,
+                               enum rw_hint write_hint, bio_end_io_t end_bio)
 {
-       const enum req_op op = opf & REQ_OP_MASK;
        struct bio *bio;
 
-       BUG_ON(!buffer_locked(bh));
-       BUG_ON(!buffer_mapped(bh));
-       BUG_ON(buffer_delay(bh));
-       BUG_ON(buffer_unwritten(bh));
-
-       /*
-        * Only clear out a write error when rewriting
-        */
-       if (test_set_buffer_req(bh) && (op == REQ_OP_WRITE))
-               clear_buffer_write_io_error(bh);
-
        if (buffer_meta(bh))
                opf |= REQ_META;
        if (buffer_prio(bh))
@@ -1115,10 +1110,32 @@ static void __bh_submit(struct buffer_head *bh, 
blk_opf_t opf,
 
        bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
        bio->bi_write_hint = write_hint;
+       bio->bi_end_io = end_bio;
 
-       bio_add_folio_nofail(bio, bh->b_folio, bh->b_size, bh_offset(bh));
+       return bio;
+}
 
-       bio->bi_end_io = end_bio;
+static void __bh_submit(struct buffer_head *bh, blk_opf_t opf,
+               enum rw_hint write_hint, struct writeback_control *wbc,
+               bio_end_io_t end_bio)
+{
+       const enum req_op op = opf & REQ_OP_MASK;
+       struct bio *bio;
+
+       BUG_ON(!buffer_locked(bh));
+       BUG_ON(!buffer_mapped(bh));
+       BUG_ON(buffer_delay(bh));
+       BUG_ON(buffer_unwritten(bh));
+
+       /*
+        * Only clear out a write error when rewriting
+        */
+       if (test_set_buffer_req(bh) && (op == REQ_OP_WRITE))
+               clear_buffer_write_io_error(bh);
+
+       bio = bh_bio_alloc(bh, opf, write_hint, end_bio);
+
+       bio_add_folio_nofail(bio, bh->b_folio, bh->b_size, bh_offset(bh));
        bio->bi_private = bh;
 
        /* Take care of bh's that straddle the end of the device */


Reply via email to