Skip to content

Commit 0b73284

Browse files
zhangyi089tytso
authored andcommitted
ext4: ext4_read_bh_lock() should submit IO if the buffer isn't uptodate
Recently we notice that ext4 filesystem would occasionally fail to read metadata from disk and report error message, but the disk and block layer looks fine. After analyse, we lockon commit 88dbcbb ("blkdev: avoid migration stalls for blkdev pages"). It provide a migration method for the bdev, we could move page that has buffers without extra users now, but it lock the buffers on the page, which breaks the fragile metadata read operation on ext4 filesystem, ext4_read_bh_lock() was copied from ll_rw_block(), it depends on the assumption of that locked buffer means it is under IO. So it just trylock the buffer and skip submit IO if it lock failed, after wait_on_buffer() we conclude IO error because the buffer is not uptodate. This issue could be easily reproduced by add some delay just after buffer_migrate_lock_buffers() in __buffer_migrate_folio() and do fsstress on ext4 filesystem. EXT4-fs error (device pmem1): __ext4_find_entry:1658: inode #73193: comm fsstress: reading directory lblock 0 EXT4-fs error (device pmem1): __ext4_find_entry:1658: inode #75334: comm fsstress: reading directory lblock 0 Fix it by removing the trylock logic in ext4_read_bh_lock(), just lock the buffer and submit IO if it's not uptodate, and also leave over readahead helper. Cc: [email protected] Signed-off-by: Zhang Yi <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 1ff2030 commit 0b73284

File tree

1 file changed

+5
-11
lines changed

1 file changed

+5
-11
lines changed

fs/ext4/super.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -205,19 +205,12 @@ int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags, bh_end_io_t *end_io
205205

206206
int ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait)
207207
{
208-
if (trylock_buffer(bh)) {
209-
if (wait)
210-
return ext4_read_bh(bh, op_flags, NULL);
208+
lock_buffer(bh);
209+
if (!wait) {
211210
ext4_read_bh_nowait(bh, op_flags, NULL);
212211
return 0;
213212
}
214-
if (wait) {
215-
wait_on_buffer(bh);
216-
if (buffer_uptodate(bh))
217-
return 0;
218-
return -EIO;
219-
}
220-
return 0;
213+
return ext4_read_bh(bh, op_flags, NULL);
221214
}
222215

223216
/*
@@ -264,7 +257,8 @@ void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block)
264257
struct buffer_head *bh = sb_getblk_gfp(sb, block, 0);
265258

266259
if (likely(bh)) {
267-
ext4_read_bh_lock(bh, REQ_RAHEAD, false);
260+
if (trylock_buffer(bh))
261+
ext4_read_bh_nowait(bh, REQ_RAHEAD, NULL);
268262
brelse(bh);
269263
}
270264
}

0 commit comments

Comments
 (0)