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 */

