Re: [REGRESSION] Silent SATA read corruption with dma-iommu on AMD 600-series AHCI (6.19 good, 7.0+ bad)

Vasant Hegde <[email protected]>
Newsgroups gmane.linux.block,gmane.linux.ide
Message-ID <[email protected]>
Mikael,

Thanks for the detailed report!

Can you please apply Commit 1e75a8255f11c81fb and retest. Also boot with
`amd_iommu=pgtbl_v2`?


@Mario, Can you look into this issue? Is this similar to the one you were
debugging internally?


-Vasant


On 8/28/2026 10:20 AM, Mikael Etienne wrote:
> You don't often get email from [email protected]. Learn why this is important<https://aka.ms/LearnAboutSenderIdentification>
> Hi,
> 
> Since Linux 7.0 I observe silent read corruption on SATA disks behind an AMD
> 600-series chipset AHCI controller. AHCI/libata, the block layer, the IOMMU and
> PCIe AER report no error at all; only consumers that validate the returned bytes
> (btrfs data checksums, fio --verify) notice. SMART stays PASSED throughout.
> 
> Hardware, up front because it may matter: AMD Ryzen 7 8700G, with the SATA
> controller integrated in the chipset:
> 
> 0e:00.0 SATA controller [0106]: Advanced Micro Devices, Inc. [AMD]
> 600 Series Chipset SATA Controller [1022:43f6] (rev 01)
> 
> This is the same SoC as bug 219609, where dma-iommu was already identified as the
> trigger for a different device class (NVMe). Details in section 6.
> 
> Two observations sharply constrain the failure:
> 
> 1. Once corruption starts, rebooting with the same kernel and the same command
> line, WITHOUT rewriting the test file, makes the very same blocks verify
> correctly again. Continued reads can later trigger the failure again. I have
> therefore observed no persistent corruption of the test file contents; this
> behaves like transient read-path state.
> 
> 2. Adding only "iommu=pt" to the command line (nothing else changed): no
> corruption observed over 40 consecutive verification passes, 10 TiB re-read
> in 17 h. In the default translated mode the same test failed after 768 GiB
> / 3 h 25 m.
> 
> Good/bad boundary: 6.18.16 and 6.19.x are clean, every 7.0.x and 7.1.x is
> affected. Kernel is untainted (/proc/sys/kernel/tainted = 0), no out-of-tree or
> DKMS modules loaded.
> 
> Important caveat, stated up front: all kernels tested so far are Fedora-packaged.
> I have not confirmed this on vanilla upstream and I have not bisected. See "What
> I can and cannot do" at the end.
> 
> #regzbot introduced: v6.19..v7.0
> 
> 
> ## 1. Test matrix
> 
> Test file: 256 GiB fio canary with crc32c verification, on btrfs, on the 12 TB
> drive (WDC WD120EFGX-68CPHN0).
> 
> 7.1.10-200.fc44, translated (DMA-FQ):
> first verify failure after 768 GiB re-read / 3 h 25 m
> once in the failed state, a plain 4 GiB O_DIRECT read of the same file
> produced tens of thousands of further csum failures
> btrfs corruption_errs reached 20,858,094 in that session
> reboot -> counters back to 0, same file verifies clean again
> 
> 7.1.10-200.fc44, iommu=pt (identity):
> 40 consecutive clean passes, 10 TiB re-read, 17 h
> btrfs corruption_errs = 0, zero kernel error lines
> 
> Earlier, translated mode, other workloads on the 8 TB drive:
> read-only workload 9 h 30 m clean
> deduplication workload failed at 3 h 17 m
> sequential write failed at 6 h 35 m
> 
> I have not yet run enough boots to give a proper min/median/max distribution.
> The 3 h 25 m figure above is a single, carefully instrumented data point.
> 
> 
> ## 2. Reproducer
> 
> fio 3.40, io_uring engine (libaio not tested yet).
> 
> Write the canary once:
> 
> fio --name=canary --filename=/srv/12to/.sata-canary --size=256G --bs=128k \
> --ioengine=io_uring --direct=1 --iodepth=32 \
> --verify=crc32c --verify_interval=4096 --rw=write \
> --do_verify=0 --fsync_on_close=1
> 
> Then loop the verification until it fails:
> 
> while :; do
> fio --name=canary --filename=/srv/12to/.sata-canary --size=256G --bs=128k \
> --ioengine=io_uring --direct=1 --iodepth=32 \
> --verify=crc32c --verify_interval=4096 --rw=write \
> --verify_only=1 --verify_fatal=1 || break
> done
> 
> The reboot-without-rewrite protocol: when it fails, reboot and re-run only the
> verification loop above. The canary file is never rewritten. It verifies clean.
> 
> 
> ## 3. Corruption signature
> 
> The frequent mode is a 4096-byte page read back as all zeros. btrfs reports
> "csum 0x8941f998", which is the CRC32C of a zero-filled 4 KiB block.
> 
> The interesting mode is a structured permutation. From one btrfs report, inode
> 6646:
> 
> offset A offset B delta
> 1314816 1355776 40960
> 1318912 1351680 32768
> 1323008 1347584 24576
> 1327104 1343488 16384
> 1331200 1339392 8192
> 
> Verified programmatically from the raw btrfs csum lines: the data read at offset
> A is exactly what was expected at offset B, and vice versa. Five reciprocal
> pairs, symmetric around the pivot at 1335296 -- a run of 11 consecutive 4 KiB
> blocks in reverse order, the centre block mapping onto itself.
> 
> This pattern suggests incorrect DMA/scatterlist mapping or descriptor handling,
> because the affected chunks form a structured permutation rather than random bit
> corruption. It does not by itself identify the faulty layer.
> 
> 
> ## 4. Hardware and storage stack
> 
> Gigabyte X870I AORUS PRO ICE, BIOS FB1c (2026-07-21)
> AMD Ryzen 7 8700G w/ Radeon 780M Graphics
> 32 GB DDR5 non-ECC, single stick, JEDEC 4800 (EXPO/XMP off)
> 
> 0e:00.0 SATA controller [0106]: Advanced Micro Devices, Inc. [AMD]
> 600 Series Chipset SATA Controller [1022:43f6] (rev 01)
> 
> ahci flags: 64bit ncq sntf stag pm led clo only pmp pio slum part sxs deso
> sadm sds apst
> 32 command slots, queue_depth 32, max_segment_size 65536, max_segments 168,
> max_sectors_kb 4096, scheduler bfq
> 
> IOMMU: AMD-Vi, "Default domain type: Translated",
> "DMA domain TLB invalidation policy: lazy mode"
> Controller iommu_group type: DMA-FQ, becomes "identity" with iommu=pt
> 
> Test drive: /dev/sdb1 -> /srv/12to
> btrfs, data single, metadata DUP, mounted rw,noatime,compress=zstd:3,
> space_cache=v2. Plain partition: no LVM, no dm-crypt, no mdraid.
> 
> Drives that showed the symptom (three different drives, one taken new out of
> its box and affected within hours of first use):
> WDC WD120EFGX-68CPHN0, fw 85.00B85 (btrfs, quantified above)
> Seagate ST8000VN004-2M2101, fw SC60 (btrfs)
> WDC WD101EFBX-68B0AN0 (ext4)
> 
> NVMe devices in the same machine have never shown the symptom.
> 
> 
> ## 5. What I ruled out
> 
> - NCQ: queue_depth 32 -> 1, no change (304 vs 769 csum failures per 4 GiB read)
> - transfer size: max_sectors_kb 4096 -> 64, no change (388 vs 342)
> - both combined: no change
> - SATA link power management: already max_performance on the affected ports
> - PCIe ASPM: disabled on that link
> - PCIe AER: all correctable and non-fatal counters at 0
> - SATA link CRC (SMART attribute 199): 0 on every drive
> - temperature: 41-56 C
> - swiotlb=force does NOT help, which is consistent with the dma-iommu path
> still being used underneath
> - not btrfs-specific: at the same moment, ext4 on a second drive reported
> "bad header/extent: invalid magic - magic 0", and parted reported a corrupt
> GPT on it. Both drives read correctly again after a reboot.
> 
> btrfs is what first exposed the problem, through its data checksums. Filesystems
> without user-data checksums may hand affected data to userspace without noticing,
> although metadata validation or application-level checksums can still catch some
> of it -- which is what happened with ext4 and parted above.
> 
> 
> ## 6. Possibly related
> 
> Bug 219609, "File corruptions on SSD in 1st M.2 socket of AsRock X600M-STX +
> Ryzen 8700G". Christoph Hellwig writes there that "the problem only happens when
> using the dma-iommu code (with or without swiotlb buffering for unaligned /
> untrusted data)", and that iommu=pt or amd_iommu=off fix it.
> 
> Same SoC (Ryzen 8700G) as this machine, but a different device class (SATA/AHCI
> here, NVMe there) and a different kernel window, so I am reporting separately and
> cross-referencing rather than piling onto that bug.
> 
> 
> ## 7. What I can and cannot do
> 
> This is a production home server, not a test bench, so I want to be straight
> about it:
> 
> I CAN: run any specific test, boot parameter or debug patch you ask for, and
> report back with full instrumentation. I have a working reproducer and
> a drive I can dedicate to it.
> 
> I CANNOT realistically: dedicate the machine to a multi-day v6.19..v7.0
> bisection. Classifying a kernel as "good" currently costs several hours
> and several TiB of reads, which makes ~13 bisection steps impractical
> for me. If someone can suggest a faster trigger, that changes.
> 
> I have not yet tested: vanilla upstream kernels, libaio instead of io_uring,
> iommu.strict=1, or amd_iommu=off. I am happy to test any of these.
> 
> Available on request, immediately: full dmesg from a bad boot and from an
> iommu=pt boot, kernel .config for good and bad, /proc/cmdline, uname -a,
> /proc/sys/kernel/tainted, lspci -nnvv, lspci -t, IOMMU group and domain types,
> queue/DMA sysfs attributes, SMART reports, AER counters, raw fio logs, the raw
> btrfs csum lines, and the script that proved the A/B swaps.
> 
> Thanks,
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.