Skip to content

Commit 917ac77

Browse files
adam900710kdave
authored andcommitted
btrfs: subpage: fix a crash in metadata repair path
[BUG] Test case btrfs/027 would crash with subpage (64K page size, 4K sectorsize) with the following dying messages: debug: map_length=16384 length=65536 type=metadata|raid6(0x104) assertion failed: map_length >= length, in fs/btrfs/volumes.c:8093 ------------[ cut here ]------------ kernel BUG at fs/btrfs/messages.c:259! Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 Call trace: btrfs_assertfail+0x28/0x2c [btrfs] btrfs_map_repair_block+0x150/0x2b8 [btrfs] btrfs_repair_io_failure+0xd4/0x31c [btrfs] btrfs_read_extent_buffer+0x150/0x16c [btrfs] read_tree_block+0x38/0xbc [btrfs] read_tree_root_path+0xfc/0x1bc [btrfs] btrfs_get_root_ref.part.0+0xd4/0x3a8 [btrfs] open_ctree+0xa30/0x172c [btrfs] btrfs_mount_root+0x3c4/0x4a4 [btrfs] legacy_get_tree+0x30/0x60 vfs_get_tree+0x28/0xec vfs_kern_mount.part.0+0x90/0xd4 vfs_kern_mount+0x14/0x28 btrfs_mount+0x114/0x418 [btrfs] legacy_get_tree+0x30/0x60 vfs_get_tree+0x28/0xec path_mount+0x3e0/0xb64 __arm64_sys_mount+0x200/0x2d8 invoke_syscall+0x48/0x114 el0_svc_common.constprop.0+0x60/0x11c do_el0_svc+0x38/0x98 el0_svc+0x40/0xa8 el0t_64_sync_handler+0xf4/0x120 el0t_64_sync+0x190/0x194 Code: aa0403e2 b0fff060 91010000 959c2024 (d4210000) [CAUSE] In btrfs/027 we test RAID6 with missing devices, in this particular case, we're repairing a metadata at the end of a data stripe. But at btrfs_repair_io_failure(), we always pass a full PAGE for repair, and for subpage case this can cross stripe boundary and lead to the above BUG_ON(). This metadata repair code is always there, since the introduction of subpage support, but this can trigger BUG_ON() after the bio split ability at btrfs_map_bio(). [FIX] Instead of passing the old PAGE_SIZE, we calculate the correct length based on the eb size and page size for both regular and subpage cases. CC: [email protected] # 6.3+ Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent b675df0 commit 917ac77

File tree

1 file changed

+5
-4
lines changed

1 file changed

+5
-4
lines changed

fs/btrfs/disk-io.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
242242
int mirror_num)
243243
{
244244
struct btrfs_fs_info *fs_info = eb->fs_info;
245-
u64 start = eb->start;
246245
int i, num_pages = num_extent_pages(eb);
247246
int ret = 0;
248247

@@ -251,12 +250,14 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
251250

252251
for (i = 0; i < num_pages; i++) {
253252
struct page *p = eb->pages[i];
253+
u64 start = max_t(u64, eb->start, page_offset(p));
254+
u64 end = min_t(u64, eb->start + eb->len, page_offset(p) + PAGE_SIZE);
255+
u32 len = end - start;
254256

255-
ret = btrfs_repair_io_failure(fs_info, 0, start, PAGE_SIZE,
256-
start, p, start - page_offset(p), mirror_num);
257+
ret = btrfs_repair_io_failure(fs_info, 0, start, len,
258+
start, p, offset_in_page(start), mirror_num);
257259
if (ret)
258260
break;
259-
start += PAGE_SIZE;
260261
}
261262

262263
return ret;

0 commit comments

Comments
 (0)