Merge tag 'vfs-7.2-rc1.bh' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull buffer_head updates from Christian Brauner:
 "This removes b_end_io from struct buffer_head.

  Instead of setting bio->bi_end_io to end_bio_bh_io_sync() which then
  calls bh->b_end_io(), the new bh_submit() and __bh_submit() interfaces
  set bio->bi_end_io to the appropriate completion handler directly,
  replacing two indirect function calls in the completion path with one.
  It is also one fewer function pointer in the middle of a writable data
  structure that can be corrupted, it shrinks struct buffer_head from
  104 to 96 bytes allowing roughly 7% more buffer_heads to be cached in
  the same amount of memory, and it removes some atomic operations as
  the buffer refcount is no longer incremented before calling the end_io
  handler.

  All in-tree users (fs/buffer.c itself, ext4, jbd2, ocfs2, gfs2,
  nilfs2, and md-bitmap) are converted, and submit_bh(),
  mark_buffer_async_write(), and end_buffer_write_sync() are removed"

* tag 'vfs-7.2-rc1.bh' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (34 commits)
  buffer: Remove end_buffer_write_sync()
  buffer: Change calling convention for end_buffer_read_sync()
  buffer: Remove b_end_io
  buffer: Remove submit_bh()
  md-bitmap: Convert read_file_page and write_file_page to bh_submit()
  nilfs2: Convert nilfs_mdt_submit_block to bh_submit()
  nilfs2: Convert nilfs_gccache_submit_read_data to bh_submit()
  nilfs2: Convert nilfs_btnode_submit_block to bh_submit()
  buffer: Remove mark_buffer_async_write()
  gfs2: Convert gfs2_aspace_write_folio to bh_submit()
  gfs2: Remove use of b_end_io in gfs2_meta_read_endio()
  gfs2: Convert gfs2_dir_readahead to bh_submit()
  gfs2: Convert gfs2_metapath_ra to bh_submit()
  ocfs2: Convert ocfs2_write_super_or_backup to bh_submit()
  ocfs2: Convert ocfs2_read_blocks to bh_submit()
  ocfs2: Convert ocfs2_read_block to bh_submit()
  ocfs2: Convert ocfs2_write_block to bh_submit()
  jbd2: Convert jbd2_write_superblock() to bh_submit()
  jbd2: Convert journal commit to bh_submit()
  ext4: Convert ext4_commit_super() to bh_submit()
  ...
This commit is contained in:
Linus Torvalds
2026-06-15 03:36:08 +05:30
21 changed files with 291 additions and 299 deletions

View File

@@ -416,20 +416,6 @@ lm_open_conflict yes no no
lm_breaker_timedout yes no no
====================== ============= ================= =========
buffer_head
===========
prototypes::
void (*b_end_io)(struct buffer_head *bh, int uptodate);
locking rules:
called from interrupts. In other words, extreme care is needed here.
bh is locked, but that's all warranties we have here. Currently only RAID1,
highmem, fs/buffer.c, and fs/ntfs/aops.c are providing these. Block devices
call this method upon the IO completion.
block_device_operations
=======================
prototypes::

View File

@@ -1624,7 +1624,7 @@ function-trace, we get a much larger output::
=> blk_queue_bio
=> submit_bio_noacct
=> submit_bio
=> submit_bh
=> bh_submit
=> __ext3_get_inode_loc
=> ext3_iget
=> ext3_lookup
@@ -1909,7 +1909,7 @@ tracers.
=> blk_queue_bio
=> submit_bio_noacct
=> submit_bio
=> submit_bh
=> bh_submit
=> ext3_bread
=> ext3_dir_bread
=> htree_dirblock_to_tree

View File

@@ -502,6 +502,18 @@ static void write_sb_page(struct bitmap *bitmap, unsigned long pg_index,
static void md_bitmap_file_kick(struct bitmap *bitmap);
#ifdef CONFIG_MD_BITMAP_FILE
static void end_bitmap_write(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
struct bitmap *bitmap = bh->b_private;
if (!uptodate)
set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
if (atomic_dec_and_test(&bitmap->pending_writes))
wake_up(&bitmap->write_wait);
}
static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
{
struct buffer_head *bh = page_buffers(page);
@@ -510,7 +522,7 @@ static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
atomic_inc(&bitmap->pending_writes);
set_buffer_locked(bh);
set_buffer_mapped(bh);
submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
bh_submit(bh, REQ_OP_WRITE | REQ_SYNC, end_bitmap_write);
bh = bh->b_this_page;
}
@@ -519,16 +531,6 @@ static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
atomic_read(&bitmap->pending_writes) == 0);
}
static void end_bitmap_write(struct buffer_head *bh, int uptodate)
{
struct bitmap *bitmap = bh->b_private;
if (!uptodate)
set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
if (atomic_dec_and_test(&bitmap->pending_writes))
wake_up(&bitmap->write_wait);
}
static void free_buffers(struct page *page)
{
struct buffer_head *bh;
@@ -592,12 +594,11 @@ static int read_file_page(struct file *file, unsigned long index,
else
count -= blocksize;
bh->b_end_io = end_bitmap_write;
bh->b_private = bitmap;
atomic_inc(&bitmap->pending_writes);
set_buffer_locked(bh);
set_buffer_mapped(bh);
submit_bh(REQ_OP_READ, bh);
bh_submit(bh, REQ_OP_READ, end_bitmap_write);
}
blk_cur++;
bh = bh->b_this_page;

View File

@@ -38,7 +38,7 @@
* Clean -> Dirty - on compute_parity to satisfy write/sync (RECONSTRUCT or RMW)
*
* The Want->Empty, Want->Clean, Dirty->Clean, transitions
* all happen in b_end_io at interrupt time.
* all happen in end_io at interrupt time.
* Each sets the Uptodate bit before releasing the Lock bit.
* This leaves one multi-stage transition:
* Want->Dirty->Clean
@@ -64,7 +64,7 @@
* together, but we are not guaranteed of that so we allow for more.
*
* If a buffer is on the read list when the associated cache buffer is
* Uptodate, the data is copied into the read buffer and it's b_end_io
* Uptodate, the data is copied into the read buffer and it's end_io
* routine is called. This may happen in the end_request routine only
* if the buffer has just successfully been read. end_request should
* remove the buffers from the list and then set the Uptodate bit on
@@ -76,7 +76,7 @@
* into the cache buffer, which is then marked dirty, and moved onto a
* third list, the written list (bh_written). Once both the parity
* block and the cached buffer are successfully written, any buffer on
* a written list can be returned with b_end_io.
* a written list can be returned with end_io.
*
* The write list and read list both act as fifos. The read list,
* write list and written list are protected by the device_lock.

View File

@@ -54,9 +54,6 @@
#include "internal.h"
static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
enum rw_hint hint, struct writeback_control *wbc);
#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
inline void touch_buffer(struct buffer_head *bh)
@@ -132,15 +129,43 @@ static void buffer_io_error(struct buffer_head *bh, char *msg)
bh->b_bdev, (unsigned long long)bh->b_blocknr, msg);
}
/*
* End-of-IO handler helper function which does not touch the bh after
* unlocking it.
* Note: unlock_buffer() sort-of does touch the bh after unlocking it, but
* a race there is benign: unlock_buffer() only use the bh's address for
* hashing after unlocking the buffer, so it doesn't actually touch the bh
* itself.
/**
* 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.
*/
static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate)
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_buffer_read_sync - Handle buffer reads finishing
* @bh: The buffer.
* @uptodate: True if the read was successful.
*
* If a buffer is read through a mechanism that isn't bh_submit(), you
* can call this function to finish the read.
*/
void end_buffer_read_sync(struct buffer_head *bh, int uptodate)
{
if (uptodate) {
set_buffer_uptodate(bh);
@@ -150,21 +175,36 @@ static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate)
}
unlock_buffer(bh);
}
/*
* Default synchronous end-of-IO handler.. Just mark it up-to-date and
* unlock the buffer.
*/
void end_buffer_read_sync(struct buffer_head *bh, int uptodate)
{
put_bh(bh);
__end_buffer_read_notouch(bh, 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)
{
if (uptodate) {
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
end_buffer_read_sync(bh, uptodate);
}
EXPORT_SYMBOL(bh_end_read);
/**
* 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);
if (success) {
set_buffer_uptodate(bh);
} else {
buffer_io_error(bh, ", lost sync page write");
@@ -172,9 +212,8 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
clear_buffer_uptodate(bh);
}
unlock_buffer(bh);
put_bh(bh);
}
EXPORT_SYMBOL(end_buffer_write_sync);
EXPORT_SYMBOL(bh_end_write);
static struct buffer_head *
__find_get_block_slow(struct block_device *bdev, sector_t block, bool atomic)
@@ -342,11 +381,13 @@ static void decrypt_bh(struct work_struct *work)
}
/*
* I/O completion handler for block_read_full_folio() - pages
* I/O completion handler for block_read_full_folio() - folios
* which come unlocked at the end of I/O.
*/
static void end_buffer_async_read_io(struct buffer_head *bh, int uptodate)
static void bh_end_async_read(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
struct inode *inode = bh->b_folio->mapping->host;
bool decrypt = fscrypt_inode_uses_fs_layer_crypto(inode);
struct fsverity_info *vi = NULL;
@@ -371,17 +412,24 @@ static void end_buffer_async_read_io(struct buffer_head *bh, int uptodate)
}
return;
}
uptodate = 0;
uptodate = false;
}
end_buffer_async_read(bh, uptodate);
}
/*
* Completion handler for block_write_full_folio() - folios which are unlocked
* during I/O, and which have the writeback flag cleared upon I/O completion.
/**
* 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.
*/
static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
void bh_end_async_write(struct bio *bio)
{
struct buffer_head *bh;
bool success = bio_endio_bh(bio, &bh);
unsigned long flags;
struct buffer_head *first;
struct buffer_head *tmp;
@@ -390,7 +438,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
BUG_ON(!buffer_async_write(bh));
folio = bh->b_folio;
if (uptodate) {
if (success) {
set_buffer_uptodate(bh);
} else {
buffer_io_error(bh, ", lost async page write");
@@ -418,46 +466,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
still_busy:
spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
}
/*
* If a page's buffers are under async readin (end_buffer_async_read
* completion) then there is a possibility that another thread of
* control could lock one of the buffers after it has completed
* but while some of the other buffers have not completed. This
* locked buffer would confuse end_buffer_async_read() into not unlocking
* the page. So the absence of BH_Async_Read tells end_buffer_async_read()
* that this buffer is not under async I/O.
*
* The page comes unlocked when it has no locked buffer_async buffers
* left.
*
* PageLocked prevents anyone starting new async I/O reads any of
* the buffers.
*
* PageWriteback is used to prevent simultaneous writeout of the same
* page.
*
* PageLocked prevents anyone from starting writeback of a page which is
* under read I/O (PageWriteback is only ever set against a locked page).
*/
static void mark_buffer_async_read(struct buffer_head *bh)
{
bh->b_end_io = end_buffer_async_read_io;
set_buffer_async_read(bh);
}
static void mark_buffer_async_write_endio(struct buffer_head *bh,
bh_end_io_t *handler)
{
bh->b_end_io = handler;
set_buffer_async_write(bh);
}
void mark_buffer_async_write(struct buffer_head *bh)
{
mark_buffer_async_write_endio(bh, end_buffer_async_write);
}
EXPORT_SYMBOL(mark_buffer_async_write);
EXPORT_SYMBOL(bh_end_async_write);
/*
@@ -916,7 +925,6 @@ static sector_t folio_init_buffers(struct folio *folio,
do {
if (!buffer_mapped(bh)) {
bh->b_end_io = NULL;
bh->b_private = NULL;
bh->b_bdev = bdev;
bh->b_blocknr = block;
@@ -1157,6 +1165,83 @@ void __bforget(struct buffer_head *bh)
}
EXPORT_SYMBOL(__bforget);
static void buffer_set_crypto_ctx(struct bio *bio, const struct buffer_head *bh,
gfp_t gfp_mask)
{
const struct address_space *mapping = folio_mapping(bh->b_folio);
/*
* The ext4 journal (jbd2) can submit a buffer_head it directly created
* for a non-pagecache page. fscrypt doesn't care about these.
*/
if (!mapping)
return;
fscrypt_set_bio_crypt_ctx(bio, mapping->host,
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)
{
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))
opf |= REQ_PRIO;
bio = bio_alloc(bh->b_bdev, 1, opf, GFP_NOIO);
if (IS_ENABLED(CONFIG_FS_ENCRYPTION))
buffer_set_crypto_ctx(bio, bh, GFP_NOIO);
bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_write_hint = write_hint;
bio_add_folio_nofail(bio, bh->b_folio, bh->b_size, bh_offset(bh));
bio->bi_end_io = end_bio;
bio->bi_private = bh;
/* Take care of bh's that straddle the end of the device */
guard_bio_eod(bio);
if (wbc) {
wbc_init_bio(wbc, bio);
wbc_account_cgroup_owner(wbc, bh->b_folio, bh->b_size);
}
blk_crypto_submit_bio(bio);
}
/**
* bh_submit - Start I/O against a buffer head
* @bh: The buffer head to perform I/O on.
* @opf: Operation and flags for bio.
* @end_io: The routine to call when I/O has completed.
*
* If you need to do I/O on an individual bh (instead of allowing the
* page cache to do I/O on the folio that it is in), call this function.
*/
void bh_submit(struct buffer_head *bh, blk_opf_t opf, bio_end_io_t end_io)
{
__bh_submit(bh, opf, WRITE_LIFE_NOT_SET, NULL, end_io);
}
EXPORT_SYMBOL(bh_submit);
static struct buffer_head *__bread_slow(struct buffer_head *bh)
{
lock_buffer(bh);
@@ -1164,9 +1249,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)
unlock_buffer(bh);
return bh;
} else {
get_bh(bh);
bh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ, bh);
bh_submit(bh, REQ_OP_READ, bh_end_read);
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
@@ -1716,15 +1799,15 @@ static struct buffer_head *folio_create_buffers(struct folio *folio,
/*
* While block_write_full_folio is writing back the dirty buffers under
* the page lock, whoever dirtied the buffers may decide to clean them
* the folio lock, whoever dirtied the buffers may decide to clean them
* again at any time. We handle that by only looking at the buffer
* state inside lock_buffer().
*
* If block_write_full_folio() is called for regular writeback
* (wbc->sync_mode == WB_SYNC_NONE) then it will redirty a page which has a
* locked buffer. This only can happen if someone has written the buffer
* directly, with submit_bh(). At the address_space level PageWriteback
* prevents this contention from occurring.
* (wbc->sync_mode == WB_SYNC_NONE) then it will redirty a folio which
* has a locked buffer. This only can happen if someone has written
* the buffer directly, with bh_submit(). At the address_space level
* the folio writeback flag prevents this contention from occurring.
*
* If block_write_full_folio() is called with wbc->sync_mode ==
* WB_SYNC_ALL, the writes are posted using REQ_SYNC; this
@@ -1810,8 +1893,7 @@ int __block_write_full_folio(struct inode *inode, struct folio *folio,
continue;
}
if (test_clear_buffer_dirty(bh)) {
mark_buffer_async_write_endio(bh,
end_buffer_async_write);
set_buffer_async_write(bh);
} else {
unlock_buffer(bh);
}
@@ -1827,8 +1909,9 @@ int __block_write_full_folio(struct inode *inode, struct folio *folio,
do {
struct buffer_head *next = bh->b_this_page;
if (buffer_async_write(bh)) {
submit_bh_wbc(REQ_OP_WRITE | write_flags, bh,
inode->i_write_hint, wbc);
__bh_submit(bh, REQ_OP_WRITE | write_flags,
inode->i_write_hint, wbc,
bh_end_async_write);
nr_underway++;
}
bh = next;
@@ -1841,7 +1924,7 @@ int __block_write_full_folio(struct inode *inode, struct folio *folio,
/*
* The folio was marked dirty, but the buffers were
* clean. Someone wrote them back by hand with
* write_dirty_buffer/submit_bh. A rare case.
* write_dirty_buffer/bh_submit. A rare case.
*/
folio_end_writeback(folio);
@@ -1865,8 +1948,7 @@ int __block_write_full_folio(struct inode *inode, struct folio *folio,
if (buffer_mapped(bh) && buffer_dirty(bh) &&
!buffer_delay(bh)) {
lock_buffer(bh);
mark_buffer_async_write_endio(bh,
end_buffer_async_write);
set_buffer_async_write(bh);
} else {
/*
* The buffer may have been set dirty during
@@ -1882,8 +1964,9 @@ int __block_write_full_folio(struct inode *inode, struct folio *folio,
struct buffer_head *next = bh->b_this_page;
if (buffer_async_write(bh)) {
clear_buffer_dirty(bh);
submit_bh_wbc(REQ_OP_WRITE | write_flags, bh,
inode->i_write_hint, wbc);
__bh_submit(bh, REQ_OP_WRITE | write_flags,
inode->i_write_hint, wbc,
bh_end_async_write);
nr_underway++;
}
bh = next;
@@ -2339,9 +2422,33 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block)
continue;
}
mark_buffer_async_read(bh);
/*
* If a folio's buffers are under async readin
* (end_buffer_async_read completion) then there is a
* possibility that another thread of control could lock
* one of the buffers after it has completed but while
* some of the other buffers have not completed. This
* locked buffer would confuse end_buffer_async_read()
* into not unlocking the folio. So the absence of
* BH_Async_Read tells end_buffer_async_read() that this
* buffer is not under async I/O.
*
* The folio comes unlocked when it has no locked
* buffer_async buffers left.
*
* The folio lock prevents anyone starting new async
* I/O reads into any of the buffers.
*
* The writeback flag is used to prevent simultaneous
* writeout of the same folio.
*
* The folio lock prevents anyone from starting writeback
* of a folio which is under read I/O (the writeback
* flag is only ever set on a locked folio).
*/
set_buffer_async_read(bh);
if (prev)
submit_bh(REQ_OP_READ, prev);
bh_submit(prev, REQ_OP_READ, bh_end_async_read);
prev = bh;
} while (iblock++, (bh = bh->b_this_page) != head);
@@ -2355,7 +2462,7 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block)
* in this folio.
*/
if (prev)
submit_bh(REQ_OP_READ, prev);
bh_submit(prev, REQ_OP_READ, bh_end_async_read);
else
folio_end_read(folio, !page_error);
@@ -2663,86 +2770,6 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block,
}
EXPORT_SYMBOL(generic_block_bmap);
static void end_bio_bh_io_sync(struct bio *bio)
{
struct buffer_head *bh = bio->bi_private;
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);
}
static void buffer_set_crypto_ctx(struct bio *bio, const struct buffer_head *bh,
gfp_t gfp_mask)
{
const struct address_space *mapping = folio_mapping(bh->b_folio);
/*
* The ext4 journal (jbd2) can submit a buffer_head it directly created
* for a non-pagecache page. fscrypt doesn't care about these.
*/
if (!mapping)
return;
fscrypt_set_bio_crypt_ctx(bio, mapping->host,
folio_pos(bh->b_folio) + bh_offset(bh), gfp_mask);
}
static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
enum rw_hint write_hint,
struct writeback_control *wbc)
{
const enum req_op op = opf & REQ_OP_MASK;
struct bio *bio;
BUG_ON(!buffer_locked(bh));
BUG_ON(!buffer_mapped(bh));
BUG_ON(!bh->b_end_io);
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))
opf |= REQ_PRIO;
bio = bio_alloc(bh->b_bdev, 1, opf, GFP_NOIO);
if (IS_ENABLED(CONFIG_FS_ENCRYPTION))
buffer_set_crypto_ctx(bio, bh, GFP_NOIO);
bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_write_hint = write_hint;
bio_add_folio_nofail(bio, bh->b_folio, bh->b_size, bh_offset(bh));
bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh;
/* Take care of bh's that straddle the end of the device */
guard_bio_eod(bio);
if (wbc) {
wbc_init_bio(wbc, bio);
wbc_account_cgroup_owner(wbc, bh->b_folio, bh->b_size);
}
blk_crypto_submit_bio(bio);
}
void submit_bh(blk_opf_t opf, struct buffer_head *bh)
{
submit_bh_wbc(opf, bh, WRITE_LIFE_NOT_SET, NULL);
}
EXPORT_SYMBOL(submit_bh);
void write_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)
{
lock_buffer(bh);
@@ -2750,9 +2777,7 @@ void write_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)
unlock_buffer(bh);
return;
}
bh->b_end_io = end_buffer_write_sync;
get_bh(bh);
submit_bh(REQ_OP_WRITE | op_flags, bh);
bh_submit(bh, REQ_OP_WRITE | op_flags, bh_end_write);
}
EXPORT_SYMBOL(write_dirty_buffer);
@@ -2775,9 +2800,7 @@ int __sync_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)
return -EIO;
}
get_bh(bh);
bh->b_end_io = end_buffer_write_sync;
submit_bh(REQ_OP_WRITE | op_flags, bh);
bh_submit(bh, REQ_OP_WRITE | op_flags, bh_end_write);
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
return -EIO;
@@ -3009,9 +3032,7 @@ int __bh_read(struct buffer_head *bh, blk_opf_t op_flags, bool wait)
BUG_ON(!buffer_locked(bh));
get_bh(bh);
bh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ | op_flags, bh);
bh_submit(bh, REQ_OP_READ | op_flags, bh_end_read);
if (wait) {
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
@@ -3053,9 +3074,7 @@ void __bh_read_batch(int nr, struct buffer_head *bhs[],
continue;
}
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
submit_bh(REQ_OP_READ | op_flags, bh);
bh_submit(bh, REQ_OP_READ | op_flags, bh_end_read);
}
}
EXPORT_SYMBOL(__bh_read_batch);

View File

@@ -2959,7 +2959,7 @@ extern unsigned long ext4_count_dirs(struct super_block *);
extern void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
extern int ext4_init_inode_table(struct super_block *sb,
ext4_group_t group, int barrier);
extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
void ext4_end_bitmap_read(struct bio *bio);
/* fast_commit.c */
int ext4_fc_info_show(struct seq_file *seq, void *v);
@@ -3184,10 +3184,10 @@ extern struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,
sector_t block);
extern struct buffer_head *ext4_sb_bread_nofail(struct super_block *sb,
sector_t block);
extern void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,
bh_end_io_t *end_io, bool simu_fail);
extern int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
bh_end_io_t *end_io, bool simu_fail);
void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,
bio_end_io_t end_io, bool simu_fail);
int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
bio_end_io_t end_io, bool simu_fail);
extern int ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait);
extern void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block);
extern int ext4_seq_options_show(struct seq_file *seq, void *offset);

View File

@@ -184,8 +184,11 @@
#include <trace/events/ext4.h>
static struct kmem_cache *ext4_fc_dentry_cachep;
static void ext4_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
static void ext4_end_buffer_io_sync(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
BUFFER_TRACE(bh, "");
if (uptodate) {
ext4_debug("%s: Block %lld up-to-date",
@@ -659,8 +662,7 @@ static void ext4_fc_submit_bh(struct super_block *sb, bool is_tail)
lock_buffer(bh);
set_buffer_dirty(bh);
set_buffer_uptodate(bh);
bh->b_end_io = ext4_end_buffer_io_sync;
submit_bh(REQ_OP_WRITE | write_flags, bh);
bh_submit(bh, REQ_OP_WRITE | write_flags, ext4_end_buffer_io_sync);
EXT4_SB(sb)->s_fc_bh = NULL;
}

View File

@@ -66,14 +66,16 @@ void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
}
void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
void ext4_end_bitmap_read(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
if (uptodate) {
set_buffer_uptodate(bh);
set_bitmap_uptodate(bh);
}
unlock_buffer(bh);
put_bh(bh);
}
static int ext4_validate_inode_bitmap(struct super_block *sb,

View File

@@ -46,9 +46,8 @@ static int write_mmp_block_thawed(struct super_block *sb,
ext4_mmp_csum_set(sb, mmp);
lock_buffer(bh);
bh->b_end_io = end_buffer_write_sync;
get_bh(bh);
submit_bh(REQ_OP_WRITE | REQ_SYNC | REQ_META | REQ_PRIO, bh);
bh_submit(bh, REQ_OP_WRITE | REQ_SYNC | REQ_META | REQ_PRIO,
bh_end_write);
wait_on_buffer(bh);
if (unlikely(!buffer_uptodate(bh)))
return -EIO;

View File

@@ -161,7 +161,7 @@ MODULE_ALIAS("ext3");
static inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
bh_end_io_t *end_io, bool simu_fail)
bio_end_io_t end_io, bool simu_fail)
{
if (simu_fail) {
clear_buffer_uptodate(bh);
@@ -176,13 +176,13 @@ static inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
*/
clear_buffer_verified(bh);
bh->b_end_io = end_io ? end_io : end_buffer_read_sync;
get_bh(bh);
submit_bh(REQ_OP_READ | op_flags, bh);
if (!end_io)
end_io = bh_end_read;
bh_submit(bh, REQ_OP_READ | op_flags, end_io);
}
void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,
bh_end_io_t *end_io, bool simu_fail)
bio_end_io_t end_io, bool simu_fail)
{
BUG_ON(!buffer_locked(bh));
@@ -194,7 +194,7 @@ void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,
}
int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
bh_end_io_t *end_io, bool simu_fail)
bio_end_io_t end_io, bool simu_fail)
{
BUG_ON(!buffer_locked(bh));
@@ -6316,12 +6316,10 @@ static int ext4_commit_super(struct super_block *sb)
clear_buffer_write_io_error(sbh);
set_buffer_uptodate(sbh);
}
get_bh(sbh);
/* Clear potential dirty bit if it was journalled update */
clear_buffer_dirty(sbh);
sbh->b_end_io = end_buffer_write_sync;
submit_bh(REQ_OP_WRITE | REQ_SYNC |
(test_opt(sb, BARRIER) ? REQ_FUA : 0), sbh);
bh_submit(sbh, REQ_OP_WRITE | REQ_SYNC |
(test_opt(sb, BARRIER) ? REQ_FUA : 0), bh_end_write);
wait_on_buffer(sbh);
if (buffer_write_io_error(sbh)) {
ext4_msg(sb, KERN_ERR, "I/O error while writing "

View File

@@ -304,14 +304,15 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE);
if (trylock_buffer(rabh)) {
if (!buffer_uptodate(rabh)) {
rabh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ | REQ_RAHEAD | REQ_META |
REQ_PRIO, rabh);
continue;
bh_submit(rabh,
REQ_OP_READ | REQ_RAHEAD | REQ_META |
REQ_PRIO,
bh_end_read);
} else {
unlock_buffer(rabh);
}
unlock_buffer(rabh);
}
brelse(rabh);
put_bh(rabh);
}
}

View File

@@ -1505,15 +1505,13 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index,
if (trylock_buffer(bh)) {
if (buffer_uptodate(bh)) {
unlock_buffer(bh);
brelse(bh);
continue;
} else {
bh_submit(bh, REQ_OP_READ | REQ_RAHEAD |
REQ_META | REQ_PRIO,
bh_end_read);
}
bh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ | REQ_RAHEAD | REQ_META |
REQ_PRIO, bh);
continue;
}
brelse(bh);
put_bh(bh);
}
}

View File

@@ -59,7 +59,7 @@ static void gfs2_aspace_write_folio(struct folio *folio,
continue;
}
if (test_clear_buffer_dirty(bh)) {
mark_buffer_async_write(bh);
set_buffer_async_write(bh);
} else {
unlock_buffer(bh);
}
@@ -75,7 +75,8 @@ static void gfs2_aspace_write_folio(struct folio *folio,
do {
struct buffer_head *next = bh->b_this_page;
if (buffer_async_write(bh)) {
submit_bh(REQ_OP_WRITE | write_flags, bh);
bh_submit(bh, REQ_OP_WRITE | write_flags,
bh_end_async_write);
nr_underway++;
}
bh = next;
@@ -212,7 +213,7 @@ static void gfs2_meta_read_endio(struct bio *bio)
do {
struct buffer_head *next = bh->b_this_page;
len -= bh->b_size;
bh->b_end_io(bh, !bio->bi_status);
end_buffer_read_sync(bh, bio->bi_status == BLK_STS_OK);
bh = next;
} while (bh && len);
}
@@ -221,7 +222,7 @@ static void gfs2_meta_read_endio(struct bio *bio)
/*
* Submit several consecutive buffer head I/O requests as a single bio I/O
* request. (See submit_bh_wbc.)
* request. (See bh_submit.)
*/
static void gfs2_submit_bhs(blk_opf_t opf, struct buffer_head *bhs[], int num)
{
@@ -275,7 +276,6 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
unlock_buffer(bh);
flags &= ~DIO_WAIT;
} else {
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
bhs[num++] = bh;
}
@@ -286,11 +286,10 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
lock_buffer(bh);
if (buffer_uptodate(bh)) {
unlock_buffer(bh);
brelse(bh);
} else {
bh->b_end_io = end_buffer_read_sync;
bhs[num++] = bh;
}
brelse(bh);
}
gfs2_submit_bhs(REQ_OP_READ | REQ_META | REQ_PRIO, bhs, num);

View File

@@ -29,8 +29,10 @@
/*
* IO end handler for temporary buffer_heads handling writes to the journal.
*/
static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
static void journal_end_buffer_io_sync(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
struct buffer_head *orig_bh = bh->b_private;
BUFFER_TRACE(bh, "");
@@ -147,13 +149,12 @@ static int journal_submit_commit_record(journal_t *journal,
lock_buffer(bh);
clear_buffer_dirty(bh);
set_buffer_uptodate(bh);
bh->b_end_io = journal_end_buffer_io_sync;
if (journal->j_flags & JBD2_BARRIER &&
!jbd2_has_feature_async_commit(journal))
write_flags |= REQ_PREFLUSH | REQ_FUA;
submit_bh(write_flags, bh);
bh_submit(bh, write_flags, journal_end_buffer_io_sync);
*cbh = bh;
return 0;
}
@@ -751,9 +752,9 @@ void jbd2_journal_commit_transaction(journal_t *journal)
lock_buffer(bh);
clear_buffer_dirty(bh);
set_buffer_uptodate(bh);
bh->b_end_io = journal_end_buffer_io_sync;
submit_bh(REQ_OP_WRITE | JBD2_JOURNAL_REQ_FLAGS,
bh);
bh_submit(bh,
REQ_OP_WRITE | JBD2_JOURNAL_REQ_FLAGS,
journal_end_buffer_io_sync);
}
cond_resched();

View File

@@ -1820,9 +1820,7 @@ static int jbd2_write_superblock(journal_t *journal, blk_opf_t write_flags)
}
if (jbd2_journal_has_csum_v2or3(journal))
sb->s_checksum = jbd2_superblock_csum(sb);
get_bh(bh);
bh->b_end_io = end_buffer_write_sync;
submit_bh(REQ_OP_WRITE | write_flags, bh);
bh_submit(bh, REQ_OP_WRITE | write_flags, bh_end_write);
wait_on_buffer(bh);
if (buffer_write_io_error(bh)) {
clear_buffer_write_io_error(bh);

View File

@@ -134,9 +134,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
}
set_buffer_mapped(bh);
bh->b_blocknr = pblocknr; /* set block address for read */
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
submit_bh(opf, bh);
bh_submit(bh, opf, bh_end_read);
bh->b_blocknr = blocknr; /* set back to the given block address */
*submit_ptr = pblocknr;
err = 0;

View File

@@ -83,9 +83,7 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff,
if (!buffer_mapped(bh))
set_buffer_mapped(bh);
bh->b_blocknr = pbn;
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
submit_bh(REQ_OP_READ, bh);
bh_submit(bh, REQ_OP_READ, bh_end_read);
if (vbn)
bh->b_blocknr = vbn;
out:

View File

@@ -148,9 +148,7 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, blk_opf_t opf,
}
map_bh(bh, inode->i_sb, (sector_t)blknum);
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
submit_bh(opf, bh);
bh_submit(bh, opf, bh_end_read);
ret = 0;
trace_nilfs2_mdt_submit_block(inode, inode->i_ino, blkoff,

View File

@@ -62,9 +62,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
/* remove from dirty list before I/O. */
clear_buffer_dirty(bh);
get_bh(bh); /* for end_buffer_write_sync() */
bh->b_end_io = end_buffer_write_sync;
submit_bh(REQ_OP_WRITE, bh);
bh_submit(bh, REQ_OP_WRITE, bh_end_write);
wait_on_buffer(bh);
@@ -145,9 +143,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
#endif
}
get_bh(bh); /* for end_buffer_read_sync() */
bh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ, bh);
bh_submit(bh, REQ_OP_READ, bh_end_read);
}
read_failure:
@@ -323,11 +319,9 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
continue;
}
get_bh(bh); /* for end_buffer_read_sync() */
if (validate)
set_buffer_needs_validate(bh);
bh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ, bh);
bh_submit(bh, REQ_OP_READ, bh_end_read);
continue;
}
}
@@ -446,10 +440,8 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
/* remove from dirty list before I/O. */
clear_buffer_dirty(bh);
get_bh(bh); /* for end_buffer_write_sync() */
bh->b_end_io = end_buffer_write_sync;
ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &di->i_check);
submit_bh(REQ_OP_WRITE, bh);
bh_submit(bh, REQ_OP_WRITE, bh_end_write);
wait_on_buffer(bh);

View File

@@ -46,7 +46,6 @@ enum bh_state_bits {
struct page;
struct buffer_head;
struct address_space;
typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
/*
* Historically, a buffer_head was used to map a single block
@@ -55,7 +54,7 @@ typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
* is the bio, and buffer_heads are used for extracting block
* mappings (via a get_block_t call), for tracking state within
* a folio (via a folio_mapping) and for wrapping bio submission
* for backward compatibility reasons (e.g. submit_bh).
* for backward compatibility reasons (e.g. bh_submit).
*/
struct buffer_head {
unsigned long b_state; /* buffer state bitmap (see above) */
@@ -70,8 +69,7 @@ struct buffer_head {
char *b_data; /* pointer to data within the page */
struct block_device *b_bdev;
bh_end_io_t *b_end_io; /* I/O completion */
void *b_private; /* reserved for b_end_io */
void *b_private; /* reserved for bio_end_io */
struct list_head b_assoc_buffers; /* associated with another mapping */
struct mapping_metadata_bhs *b_mmb; /* head of the list of metadata bhs
* this buffer is associated with */
@@ -203,7 +201,12 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size);
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);
@@ -218,7 +221,6 @@ static inline void clean_bdev_bh_alias(struct buffer_head *bh)
clean_bdev_aliases(bh->b_bdev, bh->b_blocknr, 1);
}
void mark_buffer_async_write(struct buffer_head *bh);
void __wait_on_buffer(struct buffer_head *);
wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
struct buffer_head *__find_get_block(struct block_device *bdev, sector_t block,
@@ -239,7 +241,7 @@ void __lock_buffer(struct buffer_head *bh);
int sync_dirty_buffer(struct buffer_head *bh);
int __sync_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags);
void write_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags);
void submit_bh(blk_opf_t, struct buffer_head *);
void bh_submit(struct buffer_head *, blk_opf_t, bio_end_io_t);
void write_boundary_block(struct block_device *bdev,
sector_t bblock, unsigned blocksize);
int bh_uptodate_or_lock(struct buffer_head *bh);

View File

@@ -1449,7 +1449,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
* is possible for a folio to have the dirty flag set,
* but it is actually clean (all its buffers are clean).
* This happens if the buffers were written out directly,
* with submit_bh(). ext3 will do this, as well as
* with bh_submit(). ext3 will do this, as well as
* the blockdev mapping. filemap_release_folio() will
* discover that cleanness and will drop the buffers
* and mark the folio clean - it can be freed.