buffer: Add bh_end_read(), bh_end_write() and bh_end_async_write()

These are the bio_end_io_t versions of end_buffer_read_sync(),
end_buffer_write_sync() and end_buffer_async_write().  They do not
contain a put_bh() call as it is no longer necessary.

Also add the helper function bio_endio_bh().

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Link: https://patch.msgid.link/20260528173150.1093780-5-willy@infradead.org
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Matthew Wilcox (Oracle) 2026-05-28 18:31:17 +01:00 committed by Christian Brauner
parent df21e33ff9
commit 86ecf5704e
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
2 changed files with 88 additions and 7 deletions

View File

@ -129,6 +129,34 @@ static void buffer_io_error(struct buffer_head *bh, char *msg)
bh->b_bdev, (unsigned long long)bh->b_blocknr, msg);
}
/**
* bio_endio_bh - Discard the bio used to submit a buffer.
* @bio: The bio.
* @bhp: Where to return the buffer_head.
*
* Call this in your bio_end_io handler to retrieve the buffer_head
* submitted in bh_submit(). If you did not call bh_submit(), do not
* call this function; it will return garbage.
*
* This function consumes the bio refcount which will probably free the
* bio.
*
* Return: True if the I/O succeeded.
*/
bool bio_endio_bh(struct bio *bio, struct buffer_head **bhp)
{
bool success = bio->bi_status == BLK_STS_OK;
struct buffer_head *bh = bio->bi_private;
if (unlikely(bio_flagged(bio, BIO_QUIET)))
set_bit(BH_Quiet, &bh->b_state);
bio_put(bio);
*bhp = bh;
return success;
}
EXPORT_SYMBOL(bio_endio_bh);
/*
* End-of-IO handler helper function which does not touch the bh after
* unlocking it.
@ -159,7 +187,22 @@ void end_buffer_read_sync(struct buffer_head *bh, int uptodate)
}
EXPORT_SYMBOL(end_buffer_read_sync);
void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
/**
* bh_end_read - I/O end handler for reads
* @bio: The bio being completed.
*
* Pass this function to bh_submit() if you're reading into the buffer,
* unless you need your own special I/O end handler.
*/
void bh_end_read(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
__end_buffer_read_notouch(bh, uptodate);
}
EXPORT_SYMBOL(bh_end_read);
static void __end_buffer_write_sync(struct buffer_head *bh, int uptodate)
{
if (uptodate) {
set_buffer_uptodate(bh);
@ -169,10 +212,30 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
clear_buffer_uptodate(bh);
}
unlock_buffer(bh);
}
void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
{
__end_buffer_write_sync(bh, uptodate);
put_bh(bh);
}
EXPORT_SYMBOL(end_buffer_write_sync);
/**
* bh_end_write - I/O end handler for writes
* @bio: The bio being completed.
*
* Pass this function to bh_submit() if you're writing from the buffer,
* unless you need your own special I/O end handler.
*/
void bh_end_write(struct bio *bio)
{
struct buffer_head *bh;
bool success = bio_endio_bh(bio, &bh);
__end_buffer_write_sync(bh, success);
}
EXPORT_SYMBOL(bh_end_write);
static struct buffer_head *
__find_get_block_slow(struct block_device *bdev, sector_t block, bool atomic)
{
@ -416,6 +479,21 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
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().
*/
void bh_end_async_write(struct bio *bio)
{
struct buffer_head *bh;
bool success = bio_endio_bh(bio, &bh);
end_buffer_async_write(bh, success);
}
EXPORT_SYMBOL(bh_end_async_write);
/*
* If a page's buffers are under async readin (end_buffer_async_read
* completion) then there is a possibility that another thread of
@ -1150,13 +1228,10 @@ EXPORT_SYMBOL(__bforget);
static void end_bio_bh_io_sync(struct bio *bio)
{
struct buffer_head *bh = bio->bi_private;
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
if (unlikely(bio_flagged(bio, BIO_QUIET)))
set_bit(BH_Quiet, &bh->b_state);
bh->b_end_io(bh, !bio->bi_status);
bio_put(bio);
bh->b_end_io(bh, uptodate);
}
static void buffer_set_crypto_ctx(struct bio *bio, const struct buffer_head *bh,

View File

@ -204,6 +204,12 @@ struct buffer_head *create_empty_buffers(struct folio *folio,
unsigned long blocksize, unsigned long b_state);
void end_buffer_read_sync(struct buffer_head *bh, int uptodate);
void end_buffer_write_sync(struct buffer_head *bh, int uptodate);
bool bio_endio_bh(struct bio *bio, struct buffer_head **bhp);
/* Completion routines suitable for passing to bh_submit() */
void bh_end_read(struct bio *bio);
void bh_end_write(struct bio *bio);
void bh_end_async_write(struct bio *bio);
/* Things to do with metadata buffers list */
void mmb_mark_buffer_dirty(struct buffer_head *bh, struct mapping_metadata_bhs *mmb);