Merge ec5d1ae94e ("Merge tag 'vfs-7.2-rc1.iomap' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs") into android-mainline

Steps on the way to v7.2-rc1

Change-Id: Ibbed9e3820914b49aa2b59d15844f6c366c89380
Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
Carlos Llamas authored and android-test-infra-autosubmit@system.gserviceaccount.com committed 2026-07-01 12:48:23 -07:00
commit a85d7063a9
36 files changed
+1362 -805

No files matched your search

-14
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::
+2 -2
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
+14 -13
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;
+3 -3
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.
+205 -186
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 @@ done:
/*
* 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 @@ recover:
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 @@ recover:
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);
+848 -457
View File
File diff suppressed because it is too large. Load diff
+5 -5
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);
+5 -3
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;
}
+4 -2
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,
+2 -3
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;
+8 -10
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 "
+7 -6
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);
}
}
+5 -7
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);
}
}
+6 -7
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);
+104 -12
View File
@@ -9,6 +9,7 @@
#include <linux/swap.h>
#include <linux/migrate.h>
#include <linux/fserror.h>
#include <linux/fsverity.h>
#include "internal.h"
#include "trace.h"
@@ -353,9 +354,26 @@ static inline bool iomap_block_needs_zeroing(const struct iomap_iter *iter,
{
const struct iomap *srcmap = iomap_iter_srcmap(iter);
return srcmap->type != IOMAP_MAPPED ||
(srcmap->flags & IOMAP_F_NEW) ||
pos >= i_size_read(iter->inode);
/*
* If this block has not been written, there's nothing to read
*/
if (srcmap->type != IOMAP_MAPPED)
return true;
/*
* Newly allocated blocks have not been written
*/
if (srcmap->flags & IOMAP_F_NEW)
return true;
/*
* fsverity metadata is stored past i_size, we need to read it instead
* of zeroing
*/
if (srcmap->flags & IOMAP_F_FSVERITY)
return false;
return pos >= i_size_read(iter->inode);
}
/**
@@ -544,9 +562,27 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
if (plen == 0)
return 0;
/* zero post-eof blocks as the page may be mapped */
if (iomap_block_needs_zeroing(iter, pos)) {
/*
* Handling of fsverity "holes". We hit this for two case:
* 1. No need to go further, the hole after fsverity
* descriptor is the end of the fsverity metadata.
*
* 2. This folio contains merkle tree blocks which need to be
* synthesized. If we already have fsverity info (ctx->vi)
* synthesize these blocks.
*/
if ((iomap->flags & IOMAP_F_FSVERITY) &&
iomap->type == IOMAP_HOLE) {
if (ctx->vi)
fsverity_fill_zerohash(folio, poff, plen,
ctx->vi);
iomap_set_range_uptodate(folio, poff, plen);
} else if (iomap_block_needs_zeroing(iter, pos)) {
/* zero post-eof blocks as the page may be mapped */
folio_zero_range(folio, poff, plen);
if (ctx->vi &&
!fsverity_verify_blocks(ctx->vi, folio, plen, poff))
return -EIO;
iomap_set_range_uptodate(folio, poff, plen);
} else {
if (!*bytes_submitted)
@@ -597,6 +633,15 @@ void iomap_read_folio(const struct iomap_ops *ops,
trace_iomap_readpage(iter.inode, 1);
/*
* Fetch fsverity_info for both data and fsverity metadata, as iomap
* needs zeroed hash for merkle tree block synthesis
*/
ctx->vi = fsverity_get_info(iter.inode);
if (ctx->vi && iter.pos < i_size_read(iter.inode))
fsverity_readahead(ctx->vi, folio->index,
folio_nr_pages(folio));
while ((ret = iomap_iter(&iter, ops)) > 0)
iter.status = iomap_read_folio_iter(&iter, ctx,
&bytes_submitted);
@@ -664,6 +709,15 @@ void iomap_readahead(const struct iomap_ops *ops,
trace_iomap_readahead(rac->mapping->host, readahead_count(rac));
/*
* Fetch fsverity_info for both data and fsverity metadata, as iomap
* needs zeroed hash for merkle tree block synthesis
*/
ctx->vi = fsverity_get_info(iter.inode);
if (ctx->vi && iter.pos < i_size_read(iter.inode))
fsverity_readahead(ctx->vi, readahead_index(rac),
readahead_count(rac));
while (iomap_iter(&iter, ops) > 0)
iter.status = iomap_readahead_iter(&iter, ctx,
&cur_bytes_submitted);
@@ -836,6 +890,7 @@ static int __iomap_write_begin(const struct iomap_iter *iter,
return -EIO;
folio_zero_segments(folio, poff, from, to, poff + plen);
} else {
const struct iomap *iomap = iomap_iter_srcmap(iter);
int status;
if (iter->flags & IOMAP_NOWAIT)
@@ -853,6 +908,9 @@ static int __iomap_write_begin(const struct iomap_iter *iter,
len, status, GFP_NOFS);
if (status)
return status;
if (iomap->flags & IOMAP_F_ZERO_TAIL)
folio_zero_segment(folio, to, poff + plen);
}
iomap_set_range_uptodate(folio, poff, plen);
} while ((block_start += plen) < block_end);
@@ -1058,7 +1116,6 @@ static bool iomap_write_end_inline(const struct iomap_iter *iter,
void *addr;
WARN_ON_ONCE(!folio_test_uptodate(folio));
BUG_ON(!iomap_inline_data_valid(iomap));
if (WARN_ON_ONCE(!iomap->inline_data))
return false;
@@ -1167,13 +1224,14 @@ retry:
* unlock and release the folio.
*/
old_size = iter->inode->i_size;
if (pos + written > old_size) {
if (pos + written > old_size &&
!(iter->iomap.flags & IOMAP_F_FSVERITY)) {
i_size_write(iter->inode, pos + written);
iter->iomap.flags |= IOMAP_F_SIZE_CHANGED;
}
__iomap_put_folio(iter, write_ops, written, folio);
if (old_size < pos)
if (old_size < pos && !(iter->iomap.flags & IOMAP_F_FSVERITY))
pagecache_isize_extended(iter->inode, old_size, pos);
cond_resched();
@@ -1232,6 +1290,31 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
}
EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
const void *buf, const struct iomap_ops *ops,
const struct iomap_write_ops *write_ops)
{
int ret;
struct iov_iter iiter;
struct kvec kvec = {
.iov_base = (void *)buf,
.iov_len = length,
};
struct kiocb iocb = {
.ki_filp = file,
.ki_ioprio = get_current_ioprio(),
.ki_pos = pos,
};
iov_iter_kvec(&iiter, WRITE, &kvec, 1, length);
ret = iomap_file_buffered_write(&iocb, &iiter, ops, write_ops, NULL);
if (ret < 0)
return ret;
return ret == length ? 0 : -EIO;
}
EXPORT_SYMBOL_GPL(iomap_fsverity_write);
static void iomap_write_delalloc_ifs_punch(struct inode *inode,
struct folio *folio, loff_t start_byte, loff_t end_byte,
struct iomap *iomap, iomap_punch_t punch)
@@ -1543,6 +1626,8 @@ static int iomap_zero_iter(struct iomap_iter *iter, bool *did_zero,
size_t offset;
bool ret;
balance_dirty_pages_ratelimited(iter->inode->i_mapping);
bytes = min_t(u64, SIZE_MAX, bytes);
status = iomap_write_begin(iter, write_ops, &folio, &offset,
&bytes);
@@ -1797,13 +1882,20 @@ static int iomap_writeback_range(struct iomap_writepage_ctx *wpc,
* Check interaction of the folio with the file end.
*
* If the folio is entirely beyond i_size, return false. If it straddles
* i_size, adjust end_pos and zero all data beyond i_size.
* i_size, adjust end_pos and zero all data beyond i_size. Don't skip fsverity
* folios as those are beyond i_size.
*/
static bool iomap_writeback_handle_eof(struct folio *folio, struct inode *inode,
u64 *end_pos)
static bool iomap_writeback_handle_eof(struct folio *folio,
struct iomap_writepage_ctx *wpc, u64 *end_pos)
{
struct inode *inode = wpc->inode;
u64 isize = i_size_read(inode);
if (wpc->iomap.flags & IOMAP_F_FSVERITY) {
WARN_ON_ONCE(folio_pos(folio) < isize);
return true;
}
if (*end_pos > isize) {
size_t poff = offset_in_folio(folio, isize);
pgoff_t end_index = isize >> PAGE_SHIFT;
@@ -1869,7 +1961,7 @@ int iomap_writeback_folio(struct iomap_writepage_ctx *wpc, struct folio *folio)
trace_iomap_writeback_folio(inode, pos, folio_size(folio));
if (!iomap_writeback_handle_eof(folio, inode, &end_pos))
if (!iomap_writeback_handle_eof(folio, wpc, &end_pos))
return 0;
WARN_ON_ONCE(end_pos <= pos);
+1 -4
View File
@@ -69,7 +69,7 @@ static void iomap_dio_submit_bio(const struct iomap_iter *iter,
/* Sync dio can't be polled reliably */
if ((iocb->ki_flags & IOCB_HIPRI) && !is_sync_kiocb(iocb)) {
bio_set_polled(bio, iocb);
bio->bi_opf |= REQ_POLLED;
WRITE_ONCE(iocb->private, bio);
}
@@ -603,9 +603,6 @@ static int iomap_dio_inline_iter(struct iomap_iter *iomi, struct iomap_dio *dio)
if (WARN_ON_ONCE(!inline_data))
return -EIO;
if (WARN_ON_ONCE(!iomap_inline_data_valid(iomap)))
return -EIO;
if (dio->flags & IOMAP_DIO_WRITE) {
loff_t size = iomi->inode->i_size;
+1
View File
@@ -28,6 +28,7 @@ struct iomap_ioend *iomap_init_ioend(struct inode *inode,
ioend->io_offset = file_offset;
ioend->io_size = bio->bi_iter.bi_size;
ioend->io_sector = bio->bi_iter.bi_sector;
ioend->io_vi = NULL;
ioend->io_private = NULL;
return ioend;
}
+6 -6
View File
@@ -6,17 +6,13 @@
#include <linux/iomap.h>
#include "trace.h"
static inline void iomap_iter_reset_iomap(struct iomap_iter *iter)
static inline void iomap_iter_clean_fbatch(struct iomap_iter *iter)
{
if (iter->iomap.flags & IOMAP_F_FOLIO_BATCH) {
folio_batch_release(iter->fbatch);
folio_batch_reinit(iter->fbatch);
iter->iomap.flags &= ~IOMAP_F_FOLIO_BATCH;
}
iter->status = 0;
memset(&iter->iomap, 0, sizeof(iter->iomap));
memset(&iter->srcmap, 0, sizeof(iter->srcmap));
}
/* Advance the current iterator position and decrement the remaining length */
@@ -102,10 +98,14 @@ int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
ret = 0;
else
ret = 1;
iomap_iter_reset_iomap(iter);
iomap_iter_clean_fbatch(iter);
iter->status = 0;
if (ret <= 0)
return ret;
memset(&iter->iomap, 0, sizeof(iter->iomap));
memset(&iter->srcmap, 0, sizeof(iter->srcmap));
begin:
ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags,
&iter->iomap, &iter->srcmap);
+3 -1
View File
@@ -118,7 +118,9 @@ DEFINE_RANGE_EVENT(iomap_zero_iter);
{ IOMAP_F_ATOMIC_BIO, "ATOMIC_BIO" }, \
{ IOMAP_F_PRIVATE, "PRIVATE" }, \
{ IOMAP_F_SIZE_CHANGED, "SIZE_CHANGED" }, \
{ IOMAP_F_STALE, "STALE" }
{ IOMAP_F_STALE, "STALE" }, \
{ IOMAP_F_FSVERITY, "FSVERITY" }, \
{ IOMAP_F_ZERO_TAIL, "ZERO TAIL" }
#define IOMAP_DIO_STRINGS \
+7 -6
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 @@ start_journal_io:
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();
+1 -3
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);
+1 -3
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;
+1 -3
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:
+1 -3
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,
+4 -12
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);
+3
View File
@@ -53,6 +53,9 @@ struct merkle_tree_params {
u64 tree_size; /* Merkle tree size in bytes */
unsigned long tree_pages; /* Merkle tree size in pages */
/* the hash of an all-zeroes block */
u8 zero_digest[FS_VERITY_MAX_DIGEST_SIZE];
/*
* Starting block index for each tree level, ordered from leaf level (0)
* to root level ('num_levels - 1')
+2 -2
View File
@@ -68,8 +68,8 @@ EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);
* @alg: (out) the digest's algorithm, as a FS_VERITY_HASH_ALG_* value
* @halg: (out) the digest's algorithm, as a HASH_ALGO_* value
*
* Retrieves the fsverity digest of the given file. The file must have been
* opened at least once since the inode was last loaded into the inode cache;
* Retrieves the fsverity digest of the given file. The
* fsverity_ensure_verity_info() must be called on the inode beforehand;
* otherwise this function will not recognize when fsverity is enabled.
*
* The file's fsverity digest consists of @raw_digest in combination with either
+3
View File
@@ -153,6 +153,9 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
goto out_err;
}
fsverity_hash_block(params, page_address(ZERO_PAGE(0)),
params->zero_digest);
params->tree_size = offset << log_blocksize;
params->tree_pages = PAGE_ALIGN(params->tree_size) >> PAGE_SHIFT;
return 0;
+22
View File
@@ -2,6 +2,7 @@
/*
* Copyright 2019 Google LLC
*/
#include "fsverity_private.h"
#include <linux/export.h>
#include <linux/fsverity.h>
@@ -56,3 +57,24 @@ void generic_readahead_merkle_tree(struct inode *inode, pgoff_t index,
folio_put(folio);
}
EXPORT_SYMBOL_GPL(generic_readahead_merkle_tree);
/**
* fsverity_fill_zerohash() - fill folio with hashes of zero data block
* @folio: folio to fill
* @offset: offset in the folio to start
* @len: length of the range to fill with hashes
* @vi: fsverity info
*/
void fsverity_fill_zerohash(struct folio *folio, size_t offset, size_t len,
struct fsverity_info *vi)
{
size_t off = offset;
WARN_ON_ONCE(!IS_ALIGNED(offset, vi->tree_params.digest_size));
WARN_ON_ONCE(!IS_ALIGNED(len, vi->tree_params.digest_size));
for (; off < (offset + len); off += vi->tree_params.digest_size)
memcpy_to_folio(folio, off, vi->tree_params.zero_digest,
vi->tree_params.digest_size);
}
EXPORT_SYMBOL_GPL(fsverity_fill_zerohash);
-14
View File
@@ -703,20 +703,6 @@ static inline bool bioset_initialized(struct bio_set *bs)
return bs->bio_slab != NULL;
}
/*
* Mark a bio as polled. Note that for async polled IO, the caller must
* expect -EWOULDBLOCK if we cannot allocate a request (or other resources).
* We cannot block waiting for requests on polled IO, as those completions
* must be found by the caller. This is different than IRQ driven IO, where
* it's safe to wait for IO to complete.
*/
static inline void bio_set_polled(struct bio *bio, struct kiocb *kiocb)
{
bio->bi_opf |= REQ_POLLED;
if (kiocb->ki_flags & IOCB_NOWAIT)
bio->bi_opf |= REQ_NOWAIT;
}
static inline void bio_clear_polled(struct bio *bio)
{
bio->bi_opf &= ~REQ_POLLED;
+9 -7
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);
+8
View File
@@ -61,8 +61,16 @@ static inline void eventpoll_release(struct file *file)
eventpoll_release_file(file);
}
struct epoll_key {
struct file *file;
int fd;
} __packed;
int do_epoll_ctl_file(struct file *f, int op, struct epoll_key *tf,
struct epoll_event *epds, bool nonblock);
int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
bool nonblock);
bool is_file_epoll(struct file *f);
/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
static inline int ep_op_has_event(int op)
+8
View File
@@ -201,6 +201,8 @@ bool fsverity_verify_blocks(struct fsverity_info *vi, struct folio *folio,
size_t len, size_t offset);
void fsverity_verify_bio(struct fsverity_info *vi, struct bio *bio);
void fsverity_enqueue_verify_work(struct work_struct *work);
void fsverity_fill_zerohash(struct folio *folio, size_t offset, size_t len,
struct fsverity_info *vi);
#else /* !CONFIG_FS_VERITY */
@@ -281,6 +283,12 @@ static inline void fsverity_enqueue_verify_work(struct work_struct *work)
WARN_ON_ONCE(1);
}
static inline void fsverity_fill_zerohash(struct folio *folio, size_t offset,
size_t len, struct fsverity_info *vi)
{
WARN_ON_ONCE(1);
}
#endif /* !CONFIG_FS_VERITY */
static inline bool fsverity_verify_folio(struct fsverity_info *vi,
+17 -10
View File
@@ -67,6 +67,9 @@ struct vm_fault;
* bio, i.e. set REQ_ATOMIC.
*
* IOMAP_F_INTEGRITY indicates that the filesystems handles integrity metadata.
*
* IOMAP_F_ZERO_TAIL indicates the remainder of the block after the data
* written should be zeroed.
*/
#define IOMAP_F_NEW (1U << 0)
#define IOMAP_F_DIRTY (1U << 1)
@@ -86,6 +89,15 @@ struct vm_fault;
#else
#define IOMAP_F_INTEGRITY 0
#endif /* CONFIG_BLK_DEV_INTEGRITY */
#define IOMAP_F_ZERO_TAIL (1U << 10)
/*
* Indicates reads and writes of fsverity metadata.
*
* Fsverity metadata is stored after the regular file data and thus beyond
* i_size.
*/
#define IOMAP_F_FSVERITY (1U << 11)
/*
* Flag reserved for file system specific usage
@@ -142,16 +154,6 @@ static inline void *iomap_inline_data(const struct iomap *iomap, loff_t pos)
return iomap->inline_data + pos - iomap->offset;
}
/*
* Check if the mapping's length is within the valid range for inline data.
* This is used to guard against accessing data beyond the page inline_data
* points at.
*/
static inline bool iomap_inline_data_valid(const struct iomap *iomap)
{
return iomap->length <= PAGE_SIZE - offset_in_page(iomap->inline_data);
}
/*
* When get_folio succeeds, put_folio will always be called to do any
* cleanup work necessary. put_folio is responsible for unlocking and putting
@@ -351,6 +353,9 @@ static inline bool iomap_want_unshare_iter(const struct iomap_iter *iter)
ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
const struct iomap_ops *ops,
const struct iomap_write_ops *write_ops, void *private);
int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
const void *buf, const struct iomap_ops *ops,
const struct iomap_write_ops *write_ops);
void iomap_read_folio(const struct iomap_ops *ops,
struct iomap_read_folio_ctx *ctx, void *private);
void iomap_readahead(const struct iomap_ops *ops,
@@ -427,6 +432,7 @@ struct iomap_ioend {
loff_t io_offset; /* offset in the file */
sector_t io_sector; /* start sector of ioend */
void *io_private; /* file system private data */
struct fsverity_info *io_vi; /* fsverity info */
struct bio io_bio; /* MUST BE LAST! */
};
@@ -501,6 +507,7 @@ struct iomap_read_folio_ctx {
struct readahead_control *rac;
void *read_ctx;
loff_t read_ctx_file_offset;
struct fsverity_info *vi;
};
struct iomap_read_ops {
+1 -1
View File
@@ -1452,7 +1452,7 @@ retry:
* 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.
@@ -3493,4 +3493,49 @@ TEST(epoll64)
close(ctx.sfd[1]);
}
static void *epoll65_wait(void *ctx_)
{
struct epoll_mtcontext *ctx = ctx_;
struct epoll_event event;
for (int i = 0; i < 100000; ++i) {
if (!epoll_wait(ctx->efd[0], &event, 1, 0))
return (void *)ENODATA;
}
return (void *)0;
}
TEST(epoll65)
{
struct epoll_mtcontext ctx;
struct epoll_event event;
int64_t dummy_data = 99;
pthread_t threads[64];
uintptr_t ret;
int i, err;
ctx.efd[0] = epoll_create(1);
ASSERT_GE(ctx.efd[0], 0);
ctx.efd[1] = eventfd(0, 0);
ASSERT_GE(ctx.efd[1], 0);
event.events = EPOLLIN;
err = epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &event);
ASSERT_EQ(err, 0);
write(ctx.efd[1], &dummy_data, sizeof(dummy_data));
for (i = 0; i < ARRAY_SIZE(threads); ++i)
ASSERT_EQ(pthread_create(&threads[i], NULL, epoll65_wait, &ctx), 0);
for (i = 0; i < ARRAY_SIZE(threads); ++i) {
ASSERT_EQ(pthread_join(threads[i], (void **)&ret), 0);
ASSERT_EQ(ret, 0);
}
close(ctx.efd[0]);
close(ctx.efd[1]);
}
TEST_HARNESS_MAIN