#816·btrfs

scrub: RAID10 repair writes to wrong device offsets (data corruption); devices[j+j] typo; RAID56 MDL double free; stale rewrite flag

Author: xfcyhuangCreated Sep 4, 2026Updated Sep 4, 2026

Audit findings against master @ a0648190 (v1.10), src/scrub.c.

  1. RAID10 repair writes to the wrong device offset (data corruption) — ~1187-1189 (and 1351-1353):
c
Status = write_data_phys(c->devices[j + k]->devobj, c->devices[j + k]->fileobj,
                         c->chunk_item->stripe[j + k].offset + offset - c->offset,
                         context->stripes[j + goodstripe].buf, context->stripes[j + goodstripe].length);

The data was read using the device-relative offset from get_raid0_offset (.start, scrub.c ~1422-1440 / ~1542), but the repair writes at stripe.offset + (chunk-relative logical offset). On a 4-disk RAID10 those differ (logical 0x30000 -> .start 0x10000), so the repair lands 0x20000 off — corrupting an unrelated stripe while leaving the bad one broken. The DUP path sets .start = offset - c->offset explicitly (~1467-1468); the RAID10 branch looks like that formula was copied over. The write offset should be stripe[j + k].offset + context->stripes[j + goodstripe].start.

  1. c->devices[j + j] typo in the all-mirrors-bad branch — ~1291-1295: the inner loop variable is k, so j + j reads past the devices array (1 element on 4 disks, 2 on 6) and dereferences whatever is there; log_error then charges the wrong device.

  2. RAID56 MDL double free — ~2714-2718: after MmProbeAndLockPages throws, the handler calls IoFreeMdl(...->MdlAddress) without clearing the pointer; the cleanup at end4 (~2791-2794) then does MmUnlockPages + IoFreeMdl on it again. The non-raid56 path (~1532-1537) clears the pointer; this one is missing the = NULL.

  3. rewrite flag never reset between batches — initialized once at ~2647, checked at ~2798-2807 inside the per-batch loop: once a stripe was repaired, every later batch rewrites it even if the re-read failed (the ~2765 goto end4 happens before any verification) — writing back unverified/partial data. missing is reset per batch (~2728/2736) but rewrite is not.