Re: [PATCH 3/3] btrfs: disguise single-data-RAID56 as RAID1/RAID1C3
Qu Wenruo <[email protected]>
| Newsgroups | gmane.comp.file-systems.btrfs,gmane.linux.raid |
|---|---|
| Message-ID | <[email protected]> |
在 2026/5/24 08:16, Qu Wenruo 写道:
>
>
> 在 2026/5/23 23:53, David Sterba 写道:
>> On Fri, May 22, 2026 at 06:53:53PM +0930, Qu Wenruo wrote:
>>> Recently kernel RAID56 lib is trying to remove the unexpected
>>> single-data-RAID56 (2 disks RAID5 or 3 disk RAID5) support, meanwhile
>>> btrfs still supports such setup, which means in the long run btrfs has
>>> to handle such corner case by ourselves.
>>>
>>> Thankfully single-data-RAID56 is really RAID1/RAID1C3, since data and
>>> P/Q stripes all match each other, rotation also makes no difference.
>>>
>>> This patch will disguise those single-data-RAID56 chunks as
>>> RAID1/RAID1C3 chunks.
>>
>> I don't think this is the right way to fix it. Calculations are an
>> implementation detail and should be done at the time of the xor_gen or
>> raid6_call, not touching the upper level structures related to format.
>>
>> Instead, please add helpers that take the same parameters and do the
>> switch if there's the edge case of raid5 or raid6, using memcpy. Thanks.
>
> I'd say going dedicated memcpy() is an adhoc fix, and not any easier to
> maintain.
>
> Now you have two paths, one from the raid56 lib, one from the btrfs
> specific handling for the single-data specific corner case, and that no
> one else is going to review/utilize that corner case.
>
> From this point of view, reusing the existing RAID1/RAID1C3 is way more
> reliable and sane.
I tried the idea, and it doesn't look elegant at all, we need a lot of
if () checks around every xor_gen()/raid6_call.
Sure the end result is not that huge (and I have only compile tested
it), but if we had some parameters passed wrongly, or some corner case
missed, it can be very hard to notice.
Just paste the adhoc fix for reference:
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index 08ee8f316d96..50fefe33bbe3 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -1410,11 +1410,17 @@ static void generate_pq_vertical_step(struct
btrfs_raid_bio *rbio, unsigned int
rbio_qstripe_paddr(rbio, sector_nr, step_nr));
assert_rbio(rbio);
- raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
+ if (rbio->nr_data > 1) {
+ raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
+ } else {
+ memcpy(pointers[1], pointers[0], step);
+ memcpy(pointers[2], pointers[0], step);
+ }
} else {
/* raid5 */
memcpy(pointers[rbio->nr_data], pointers[0], step);
- xor_gen(pointers[rbio->nr_data], pointers + 1, rbio->nr_data - 1,
+ if (rbio->nr_data > 1)
+ xor_gen(pointers[rbio->nr_data], pointers + 1, rbio->nr_data - 1,
step);
}
for (stripe = stripe - 1; stripe >= 0; stripe--)
@@ -1987,11 +1993,17 @@ static void recover_vertical_step(struct
btrfs_raid_bio *rbio,
}
if (failb == rbio->real_stripes - 2) {
- raid6_datap_recov(rbio->real_stripes, step,
- faila, pointers);
+ if (unlikely(rbio->nr_data == 1))
+ memcpy(pointers[0], pointers[rbio->real_stripes - 1], step);
+ else
+ raid6_datap_recov(rbio->real_stripes, step,
+ faila, pointers);
} else {
- raid6_2data_recov(rbio->real_stripes, step,
- faila, failb, pointers);
+ if (unlikely(rbio->nr_data == 1))
+ memcpy(pointers[0], pointers[rbio->real_stripes - 2], step);
+ else
+ raid6_2data_recov(rbio->real_stripes, step,
+ faila, failb, pointers);
}
} else {
void *p;
@@ -2002,6 +2014,9 @@ static void recover_vertical_step(struct
btrfs_raid_bio *rbio,
/* Copy parity block into failed block to start with */
memcpy(pointers[faila], pointers[rbio->nr_data], step);
+ if (rbio->nr_data == 1)
+ goto cleanup;
+
/* Rearrange the pointer array */
p = pointers[faila];
for (stripe_nr = faila; stripe_nr < rbio->nr_data - 1;
@@ -2644,11 +2659,17 @@ static bool verify_one_parity_step(struct
btrfs_raid_bio *rbio,
if (has_qstripe) {
assert_rbio(rbio);
/* RAID6, call the library function to fill in our P/Q. */
- raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
+ if (rbio->nr_data > 1) {
+ raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
+ } else {
+ memcpy(pointers[1], pointers[0], step);
+ memcpy(pointers[2], pointers[0], step);
+ }
} else {
/* RAID5. */
memcpy(pointers[nr_data], pointers[0], step);
- xor_gen(pointers[nr_data], pointers + 1, nr_data - 1, step);
+ if (rbio->nr_data > 1)
+ xor_gen(pointers[nr_data], pointers + 1, nr_data - 1, step);
}
/* Check scrubbing parity and repair it. */
--
2.54.0