Research notes / Storage integrity
Why a valid checksum can still return the wrong data
Published 11 October 2026 · Literature review and synthetic examples
A self-consistent record is not necessarily the record you requested. Ask three separate questions: did its bytes change, does it belong here, and is it the version you committed?
An observed distinction, not just a thought experiment
The FAST 2008 NetApp study separated checksum mismatches, identity discrepancies and parity inconsistencies. Its file-system identity checks could catch errors missed by block checksums; the RAID scrub did not have the same identity context. The study covered 1.53 million drives over 41 months from January 2004, using customer support logs. Participation and drive removal limited observation. It establishes historical evidence for different detection classes, not a contemporary SSD failure rate. [2, sections 2-3]
Our existing field-study review covers the reported counts. Here we examine what a successful check actually establishes.
Five records, three checks
This is Hesela's deterministic synthetic demonstration, not a hardware test. We request address 40, generation 2, with payload current. Each sealed record contains an address, a generation, a payload and a SHA-256 digest over their JSON array. The expected address and generation are held separately from the returned record.
Computed at build time. Checks are cumulative: each column adds a requirement. The final column is the fixture's known truth, not something the verifier can infer.
| Returned record | Checksum | + Expected address | + Expected generation | Intended payload? |
|---|---|---|---|---|
| Correct record | Pass | Pass | Pass | Yes |
| Changed bytes after sealing | Reject | Reject | Reject | No |
| Intact record from address 41 | Pass | Reject | Reject | No |
| Intact old generation at address 40 | Pass | Pass | Reject | No |
| Wrong payload sealed at the producer | Pass | Pass | Pass | No |
The relocated and old records carry valid digests; neither case needs a hash collision. The last row moves the fault before sealing: even all three checks pass when the producer supplies the wrong payload with the expected identifiers. A stale external generation would also let the old record pass. The trusted expectation is an explicit assumption, not a solution to keeping that expectation durable.
No device rates or confidence intervals can be inferred from five deliberately selected fixtures. This code does not implement SCSI or NVMe protection information, authenticate against an attacker, emulate caches, or model concurrent transactions.
Executable Node.js model and regression tests are published with an auditable JSON result. The table and exports are generated from the same functions; no device is read or written.
Consistency can preserve the wrong answer
Krioukov and colleagues used model checking of simplified parity-based storage, concentrating on single injected errors. Their term parity pollution describes bad data influencing redundancy calculations. Their results depend on where checks run: a user-read check does not automatically protect a separate maintenance path. Their identity and version mechanisms also have different coverage. This is a design analysis, not a benchmark of today's arrays. [1, sections 3-4]
Original: A = 7, B = 11, P = A XOR B = 12
Fault: observed A = 6; original P can still recover A = 7
Blind rewrite: P = 6 XOR 11 = 13; recovery now returns 6
These are dimensionless byte values, not measurements. After the blind rewrite, the equation balances but the original A is no longer recoverable from B and the new P alone. The example deliberately assumes a policy that trusts the observed data. It is not a claim that every scrub does this, and it is not advice to disable scrubbing.
Detection, repair and validation remain separate operations. Compare our scrubbing review and RAID write-hole model; an interrupted update is a different fault from accepting a complete but incorrect record.
Where does protection begin?
Linux's data-integrity documentation describes metadata attached to I/O, potentially generated by the block layer for an unaware filesystem. It distinguishes device/controller protection from a longer protected path. Consequently, support for PI does not by itself prove coverage back to the application buffer. Record the actual generation point, verification points, transformations and configuration of your deployed stack. The documentation contains historical design discussion; it is not a current support matrix for every driver. [3, sections 1-3 and 5]
For a review or incident report, retain these independently:
- The requested object, address and committed generation, with the authority that supplied them.
- The returned identifiers and checksum result, including which bytes and metadata were covered.
- The layer at which integrity metadata was created and where it was checked.
- The inputs used for reconstruction and how the result was validated before rewriting.
- The acknowledgement and persistence contract; a successful content check is not evidence that a pending write survived power loss.
Structured entries: lost write, misdirected write, parity pollution, protection information and end-to-end data protection.
Primary sources and limits
- Krioukov et al. Parity Lost and Parity Regained. FAST 2008, sections 3-4.
- Bairavasundaram et al. An Analysis of Data Corruption in the Storage Stack. FAST 2008, sections 2-3 and 6.
- Linux kernel documentation: Data Integrity, protection boundaries and automatic metadata generation.
Reviewed 11 October 2026. No original drive traces, third-party figures or paper model-checker implementation are reproduced. The examples illustrate boundaries; they do not establish a probability of data loss or certify a storage product.