mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
buffer: allow a buffer_head to point at memory outside the page cache
jbd2 builds a temporary buffer_head to write out the frozen copy of a metadata block, and that copy lives in slab memory. Today jbd2 points the temporary buffer at the slab folio backing it. A slab folio's ->mapping is not an address_space, so anything that follows bh->b_folio->mapping there gets garbage rather than NULL; mark_buffer_write_io_error() does exactly that, and we are about to start calling it on this buffer. Rather than teach every such helper about slab folios, allow bh->b_folio to be NULL and let b_data point straight at the memory. Code that needs the folio has to check. There are two places in this file: - __bh_submit() adds the data by virtual address using bio_add_virt_nofail(), and skips the cgroup accounting: a buffer that is not in the page cache has no owning folio to attribute writeback to. - buffer_set_crypto_ctx() returns early. fscrypt has no interest in a buffer that is not part of a file mapping, which is why it already returns when the folio has no mapping. Nothing sets b_folio to NULL yet, so this patch is a no-op on its own. A buffer_head without a folio is a narrow thing, not a new general capability. Most of the buffer_head API assumes a folio and will fault or corrupt state without one - touch_buffer(), bh_offset(), the async read completion path, and plenty more - so it is up to whoever builds such a buffer to keep it away from all of that. What NULL buys us is that getting it wrong fails loudly instead of quietly following a slab folio's overloaded ->mapping. It is also only valid over memory that is always mapped: buffers over highmem have no permanent kernel virtual address, which is why folio_set_bh() records a folio and an offset instead. Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org> Acked-by: Weidong Zhu <weizhu@fiu.edu> Signed-off-by: Chao Shi <coshi036@gmail.com> Reviewed-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/bb6fab2111a48d7ba61887fc1372362576fce6e6.1785951556.git.coshi036@gmail.com Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
parent
1aeacc2cbf
commit
781bf9c7e3
20
fs/buffer.c
20
fs/buffer.c
|
|
@ -1070,12 +1070,16 @@ 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);
|
||||
const struct address_space *mapping;
|
||||
|
||||
/*
|
||||
* The ext4 journal (jbd2) can submit a buffer_head it directly created
|
||||
* for a non-pagecache page. fscrypt doesn't care about these.
|
||||
* for memory that is not in the page cache at all. fscrypt doesn't
|
||||
* care about these.
|
||||
*/
|
||||
if (!bh->b_folio)
|
||||
return;
|
||||
mapping = folio_mapping(bh->b_folio);
|
||||
if (!mapping)
|
||||
return;
|
||||
fscrypt_set_bio_crypt_ctx(bio, mapping->host,
|
||||
|
|
@ -1107,7 +1111,8 @@ static void __bh_submit(struct buffer_head *bh, blk_opf_t opf,
|
|||
|
||||
bio = bio_alloc(bh->b_bdev, 1, opf, GFP_NOIO);
|
||||
|
||||
if (folio_test_dropbehind(bh->b_folio) && op_is_write(opf))
|
||||
if (bh->b_folio && folio_test_dropbehind(bh->b_folio) &&
|
||||
op_is_write(opf))
|
||||
bio_set_flag(bio, BIO_COMPLETE_IN_TASK);
|
||||
|
||||
if (IS_ENABLED(CONFIG_FS_ENCRYPTION))
|
||||
|
|
@ -1116,7 +1121,11 @@ 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_add_folio_nofail(bio, bh->b_folio, bh->b_size, bh_offset(bh));
|
||||
if (bh->b_folio)
|
||||
bio_add_folio_nofail(bio, bh->b_folio, bh->b_size,
|
||||
bh_offset(bh));
|
||||
else
|
||||
bio_add_virt_nofail(bio, bh->b_data, bh->b_size);
|
||||
|
||||
bio->bi_end_io = end_bio;
|
||||
bio->bi_private = bh;
|
||||
|
|
@ -1126,7 +1135,8 @@ static void __bh_submit(struct buffer_head *bh, blk_opf_t opf,
|
|||
|
||||
if (wbc) {
|
||||
wbc_init_bio(wbc, bio);
|
||||
wbc_account_cgroup_owner(wbc, bh->b_folio, bh->b_size);
|
||||
if (bh->b_folio)
|
||||
wbc_account_cgroup_owner(wbc, bh->b_folio, bh->b_size);
|
||||
}
|
||||
|
||||
blk_crypto_submit_bio(bio);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user