From fa491b14cd9586ad703606ef0155cd43459d2b32 Mon Sep 17 00:00:00 2001 From: "zhangyi (F)" Date: Thu, 24 Sep 2020 15:33:32 +0800 Subject: ext4: introduce new metadata buffer read helpers The previous patch add clear_buffer_verified() before we read metadata block from disk again, but it's rather easy to miss clearing of this bit because currently we read metadata buffer through different open codes (e.g. ll_rw_block(), bh_submit_read() and invoke submit_bh() directly). So, it's time to add common helpers to unify in all the places reading metadata buffers instead. This patch add 3 helpers: - ext4_read_bh_nowait(): async read metadata buffer if it's actually not uptodate, clear buffer_verified bit before read from disk. - ext4_read_bh(): sync version of read metadata buffer, it will wait until the read operation return and check the return status. - ext4_read_bh_lock(): try to lock the buffer before read buffer, it will skip reading if the buffer is already locked. After this patch, we need to use these helpers in all the places reading metadata buffer instead of different open codes. Signed-off-by: zhangyi (F) Suggested-by: Jan Kara Link: https://lore.kernel.org/r/20200924073337.861472-3-yi.zhang@huawei.com Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'fs/ext4/super.c') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6937ab4dfa67..4cfa95abe9dc 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -141,6 +141,68 @@ MODULE_ALIAS_FS("ext3"); MODULE_ALIAS("ext3"); #define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) + +static inline void __ext4_read_bh(struct buffer_head *bh, int op_flags, + bh_end_io_t *end_io) +{ + /* + * buffer's verified bit is no longer valid after reading from + * disk again due to write out error, clear it to make sure we + * recheck the buffer contents. + */ + 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); +} + +void ext4_read_bh_nowait(struct buffer_head *bh, int op_flags, + bh_end_io_t *end_io) +{ + BUG_ON(!buffer_locked(bh)); + + if (ext4_buffer_uptodate(bh)) { + unlock_buffer(bh); + return; + } + __ext4_read_bh(bh, op_flags, end_io); +} + +int ext4_read_bh(struct buffer_head *bh, int op_flags, bh_end_io_t *end_io) +{ + BUG_ON(!buffer_locked(bh)); + + if (ext4_buffer_uptodate(bh)) { + unlock_buffer(bh); + return 0; + } + + __ext4_read_bh(bh, op_flags, end_io); + + wait_on_buffer(bh); + if (buffer_uptodate(bh)) + return 0; + return -EIO; +} + +int ext4_read_bh_lock(struct buffer_head *bh, int op_flags, bool wait) +{ + if (trylock_buffer(bh)) { + if (wait) + return ext4_read_bh(bh, op_flags, NULL); + ext4_read_bh_nowait(bh, op_flags, NULL); + return 0; + } + if (wait) { + wait_on_buffer(bh); + if (buffer_uptodate(bh)) + return 0; + return -EIO; + } + return 0; +} + /* * This works like sb_bread() except it uses ERR_PTR for error * returns. Currently with sb_bread it's impossible to distinguish -- cgit v1.2.3