Skip to content

Commit b2324e0

Browse files
adam900710kdave
authored andcommitted
btrfs: raid56: extra debugging for raid6 syndrome generation
[BUG] I have got at least two crash report for RAID6 syndrome generation, no matter if it's AVX2 or SSE2, they all seems to have a similar calltrace with corrupted RAX: BUG: kernel NULL pointer dereference, address: 0000000000000000 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP PTI Workqueue: btrfs-rmw rmw_rbio_work [btrfs] RIP: 0010:raid6_sse21_gen_syndrome+0x9e/0x130 [raid6_pq] RAX: 0000000000000000 RBX: 0000000000001000 RCX: ffffa0ff4cfa3248 RDX: 0000000000000000 RSI: ffffa0f74cfa3238 RDI: 0000000000000000 Call Trace: <TASK> rmw_rbio+0x5c8/0xa80 [btrfs] process_one_work+0x1c7/0x3d0 worker_thread+0x4d/0x380 kthread+0xf3/0x120 ret_from_fork+0x2c/0x50 </TASK> [CAUSE] The cause is not known. Recently I also hit this in AVX512 path, and that's even in v5.15 backport, which doesn't have any of my RAID56 rework. Furthermore according to the registers: RAX: 0000000000000000 RBX: 0000000000001000 RCX: ffffa0ff4cfa3248 The RAX register is showing the number of stripes (including PQ), which is not correct (0). But the remaining two registers are all sane. - RBX is the sectorsize For x86_64 it should always be 4K and matches the output. - RCX is the pointers array Which is from rbio->finish_pointers, and it looks like a sane kernel address. [WORKAROUND] For now, I can only add extra debug ASSERT()s before we call raid6 gen_syndrome() helper and hopes to catch the problem. The debug requires both CONFIG_BTRFS_DEBUG and CONFIG_BTRFS_ASSERT enabled. My current guess is some use-after-free, but every report is only having corrupted RAX but seemingly valid pointers doesn't make much sense. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 74cd8ca commit b2324e0

1 file changed

Lines changed: 30 additions & 0 deletions

File tree

fs/btrfs/raid56.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,13 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
917917
*/
918918
ASSERT(stripe_nsectors <= BITS_PER_LONG);
919919

920+
/*
921+
* Real stripes must be between 2 (2 disks RAID5, aka RAID1) and 256
922+
* (limited by u8).
923+
*/
924+
ASSERT(real_stripes >= 2);
925+
ASSERT(real_stripes <= U8_MAX);
926+
920927
rbio = kzalloc(sizeof(*rbio), GFP_NOFS);
921928
if (!rbio)
922929
return ERR_PTR(-ENOMEM);
@@ -954,6 +961,7 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
954961

955962
ASSERT(btrfs_nr_parity_stripes(bioc->map_type));
956963
rbio->nr_data = real_stripes - btrfs_nr_parity_stripes(bioc->map_type);
964+
ASSERT(rbio->nr_data > 0);
957965

958966
return rbio;
959967
}
@@ -1180,6 +1188,26 @@ static inline void bio_list_put(struct bio_list *bio_list)
11801188
bio_put(bio);
11811189
}
11821190

1191+
static void assert_rbio(struct btrfs_raid_bio *rbio)
1192+
{
1193+
if (!IS_ENABLED(CONFIG_BTRFS_DEBUG) ||
1194+
!IS_ENABLED(CONFIG_BTRFS_ASSERT))
1195+
return;
1196+
1197+
/*
1198+
* At least two stripes (2 disks RAID5), and since real_stripes is U8,
1199+
* we won't go beyond 256 disks anyway.
1200+
*/
1201+
ASSERT(rbio->real_stripes >= 2);
1202+
ASSERT(rbio->nr_data > 0);
1203+
1204+
/*
1205+
* This is another check to make sure nr data stripes is smaller
1206+
* than total stripes.
1207+
*/
1208+
ASSERT(rbio->nr_data < rbio->real_stripes);
1209+
}
1210+
11831211
/* Generate PQ for one vertical stripe. */
11841212
static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
11851213
{
@@ -1211,6 +1239,7 @@ static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
12111239
pointers[stripe++] = kmap_local_page(sector->page) +
12121240
sector->pgoff;
12131241

1242+
assert_rbio(rbio);
12141243
raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
12151244
pointers);
12161245
} else {
@@ -2472,6 +2501,7 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
24722501
}
24732502

24742503
if (has_qstripe) {
2504+
assert_rbio(rbio);
24752505
/* RAID6, call the library function to fill in our P/Q */
24762506
raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
24772507
pointers);

0 commit comments

Comments
 (0)