]> git.hungrycats.org Git - linux/commit
lib/raid6: fix the x1 SIMD gen_syndrome variants for a single data disk misc-next/topics/raid6-fixes
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Tue, 15 Sep 2026 01:44:19 +0000 (21:44 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Fri, 18 Sep 2026 21:36:19 +0000 (17:36 -0400)
commitd645fee6d9c80880362e6a78a2c332c95cc82486
tree5f2bc87bb3a5ed195e729a3296a0afd2e32dc083
parent1397021ba66f3c04ce85760af47d0cd7f52f7d4b
lib/raid6: fix the x1 SIMD gen_syndrome variants for a single data disk

The single-unrolled x86 syndrome generators (sse1x1, sse2x1, avx2x1 and
avx512x1) software-pipeline their data loads: before the loop over the
remaining data disks (z0-2 .. 0) they load dptr[z0-1], and after the
loop they fold that register in.  With exactly one data disk (disks == 3,
z0 == 0) the preload reads dptr[-1], one pointer BEFORE the caller's
array.  Whatever is stored there is then dereferenced for `bytes` bytes
and XORed into both outputs: a NULL oopses, anything else silently
produces P = D0 ^ X and Q = 2*D0 ^ X instead of P = Q = D0.

md never gets here (raid6 needs four devices there), but btrfs allows
raid6 on three devices, and a wider btrfs raid6 with unevenly sized
devices creates 3-wide chunks as soon as the small devices are full.
Which implementation runs is decided by the boot-time benchmark, so the
same filesystem is fine on a boot where x2 or x4 won and crashes on the
boot where x1 won:

  raid6: using algorithm avx2x1 gen() 29714 MB/s
  ...
  BUG: kernel NULL pointer dereference, address: 0000000000000000
  Workqueue: btrfs-rmw rmw_rbio_work
  RIP: 0010:raid6_avx21_gen_syndrome+0xaa/0x150
  Call Trace:
   rmw_rbio+0x9fe/0x15b0
   rmw_rbio_work+0x29b/0x400
   process_one_work+0x239/0x5d0

on a 9-device btrfs raid6 (6 x 512M + 3 x 6G) writing into its first
3-wide chunk.  lib/raid6/test with NDISKS set to 3 segfaults on the same
line (avx2.c:54) under AddressSanitizer, and every x1 variant fails the
same way.

Give the x1 variants the loop shape the x2 and x4 variants already use:
copy the highest data disk into P and Q, then loop over z0-1 .. 0
multiplying Q and XORing each disk in as it is loaded.  With one data
disk the loop body never runs and P = Q = D0 fall out of the initial
copy.  The generic integer variants and the other architectures already
loop from z0-1 and are not affected.

With the change lib/raid6/test passes for every algorithm at NDISKS 3
and 16 (AddressSanitizer clean); a 3-device btrfs raid6 written with the
forced avx2x1 implementation has P == Q == D0 on disk and reconstructs
after losing any device.

Fixes: 53b381b3abeb ("Btrfs: RAID-5/6 support") # first user of 3-disk raid6
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-fable-5-1
lib/raid/raid6/x86/avx2.c
lib/raid/raid6/x86/avx512.c
lib/raid/raid6/x86/sse1.c
lib/raid/raid6/x86/sse2.c