Data integrity data integrity Also called data protection: ensuring that the data a storage system returns is identical to what was written to it, despite the unreliable nature of modern storage devices. This chapter's central concern β the reliability of the data itself, complementing RAID's whole-disk reliability. defined in ch. 45 β open in glossary (or data protection) asks a question RAIDβs whole-disk reliability didnβt: when a storage device hands a block back, is it really the block you stored? Modern disks mostly work β but occasionally return a bad block, sometimes without even knowing it.
The Crux: How To Ensure Data Integrity
How should systems ensure that data written to storage is protected? What techniques are required, and how can they be made efficient β in both space and time?45.1 Disk Failure Modes
Early RAID assumed the fail-stop fail-stop The classic disk-failure model, assumed by early RAID: a disk is either entirely working or has failed completely, and the failure is straightforward to detect. Simple to build around, but it ignores partial faults like latent sector errors and corruption. defined in ch. 45 β open in glossary model: a disk is either entirely working or entirely, detectably dead. Real disks are messier. The fail-partial fail-partial The modern (fail-partial) disk-failure model: a disk can still fail entirely, but it can also seem to be working while individual blocks become inaccessible (latent sector errors) or return the wrong contents (corruption). Faults may be non-silent (an error is returned) or silent (wrong data is returned). Introduced by Prabhakaran et al.'s IRON File Systems work. defined in ch. 45 β open in glossary model (from the IRON File Systems study) says a disk can seem healthy yet have individual blocks fail:
Two single-block faults matter, and they differ in one crucial way β whether the disk knows something is wrong:
- A latent sector error latent sector error A latent sector error (LSE) occurs when a disk sector (or group of sectors) is physically damaged β e.g. a head crash scrapes the surface, or a cosmic ray flips bits. The drive's in-disk error correcting code detects the bad bits and, if it cannot fix them, returns an explicit error when the block is read. Because it is detected, an LSE is a non-silent partial fault and is relatively easy to recover from using redundancy. defined in ch. 45 β open in glossary (LSE): a sector is physically damaged (a head crash, a cosmic-ray bit flip). The driveβs in-disk error correcting codes (ECC) error correcting code Redundant bits (ECC) stored in the disk that the drive uses to determine whether a block's on-disk bits are good and, in some cases, to repair them. If the ECC cannot correct the error, the drive returns an error rather than silently handing back bad data β turning many faults into detectable (non-silent) ones. defined in ch. 45 β open in glossary catch the bad bits and, if they canβt repair them, return an error. Loud and detected.
- Block corruption block corruption A disk block silently holds the wrong contents β e.g. buggy firmware wrote it to the wrong place (a misdirected write) or it was garbled crossing a faulty bus β while the disk's ECC still reports the block as good. The disk gives no indication of the problem, so this is a silent fault that must be detected with checksums. defined in ch. 45 β open in glossary : the block holds the wrong contents (buggy firmware misdirected a write; a faulty bus garbled the bytes) but ECC still says itβs fine. The disk returns bad data with no warning β a silent fault silent fault A fault the device gives no indication of: it returns wrong data as though it were correct. Contrast a non-silent partial fault, where the disk returns an explicit error. Block corruption is the canonical silent fault, and is why checksums are needed for detection. defined in ch. 45 β open in glossary .
| latent sector error (LSE) | block corruption | |
|---|---|---|
| cause | sector physically damaged β head crash, cosmic-ray bit flip | buggy firmware writes to the wrong place, or bits garble over a faulty bus |
| does the disk notice? | yes β in-disk ECC flags the bad bits | no β ECC still says the block is good |
| silent? | non-silent β returns an explicit error | SILENT β returns wrong data as if correct |
| detected by | the drive itself, on the read | a checksum kept by the file system / controller |
| recovered by | redundancy β mirror copy or parity reconstruction | redundancy too β but only once detection tells you it is bad |
Just how often? Over ~1.5 million drives across three years, LSEs and corruption were rare but far from negligible:
| β₯1 latent sector error | β₯1 block corruption | |
|---|---|---|
| cheap drives (SATA) | 9.40% | 0.50% |
| costly drives (SCSI / FC) | 1.40% | 0.05% |
The studies found more texture worth knowing: faults cluster in space and time (a disk with one LSE tends to get more, nearby); the annual LSE rate rises in a driveβs second year and grows with disk size; corruption rates vary wildly between models of the same class; and corruption is only weakly correlated with LSEs. The takeaway is blunt: a reliable storage system must include machinery to detect and recover from both.
45.2 Handling Latent Sector Errors
LSEs are the easy case, precisely because they are detected. When a read returns an error, the system just rebuilds the block from whatever redundancy it has β the mirror copy in a mirrored RAID, or the parity group in RAID-4/5.
There is one nasty corner, though. When a whole disk dies and the RAID rebuilds it by reading every other disk in the parity group, an LSE on one of those disks means two blocks are missing at once β more than a single parity can recover:
1A healthy parity stripe
Four data blocks plus one parity block (P = D0 β D1 β D2 β D3). Any single lost block can be recomputed from the others plus parity.
NetAppβs RAID-DP answers this with a second parity disk β a second independent equation β so a full-disk failure plus a stray LSE can still be reconstructed. The cost is an extra parity block per stripe (softened by WAFLβs log-structured writes). As always, redundancy is the key to both detection and recovery.
45.3 Detecting Corruption: The Checksum
Silent corruption is the hard case: before you can recover a bad block, you have to know itβs bad. The workhorse for detection is the checksum checksum A small summary (typically 4β8 bytes) produced by a function computed over a chunk of data (say a 4 KB block). Stored alongside the data and recomputed when the data is read: if the stored and computed checksums differ, the data has been corrupted. The primary mechanism modern storage systems use to preserve data integrity. Common functions include XOR, addition, the Fletcher checksum, and the CRC. defined in ch. 45 β open in glossary β a small summary (say 4β8 bytes) computed over a data block (say 4 KB). Store it with the data; on every read, recompute it and compare. A mismatch means the data changed since it was written.
Common checksum functions
Different functions trade strength against speed. The simplest is XOR: fold every chunk of the block together with exclusive-or into one word. Here it is on a 16-byte block:
1The 16 bytes to protect
Our (tiny, for illustration) data block is 16 bytes. We want a 4-byte checksum summarizing it.
Tip: Thereβs No Free Lunch (TNSTAAFL)
The more protection a checksum gives, the more it usually costs to compute. When something looks free β a stronger check at no price β look again; youβre probably paying somewhere.Stronger options climb the cost curve. Addition (2βs-complement, ignoring overflow) is fast but fooled by shifted data. The Fletcher checksum fletcher checksum A checksum (named for John G. Fletcher) computed from two running check bytes over the data bytes d_i: s1 = (s1 + d_i) mod 255 and s2 = (s2 + s1) mod 255. Simple to compute yet nearly as strong as a CRC, detecting all single-bit, all double-bit, and many burst errors. defined in ch. 45 β open in glossary keeps two running bytes:
computed over every byte β catching all single- and double-bit errors and many burst errors, almost as strongly as a CRC. The cyclic redundancy check cyclic redundancy check A checksum (CRC) computed by treating the data block as one large binary number and dividing it by an agreed-upon value k; the remainder is the checksum. The modulo operation can be implemented very efficiently, making CRCs popular in storage and networking alike. defined in ch. 45 β open in glossary (CRC) treats the block as one giant number and takes its remainder modulo an agreed value k; the binary modulo is cheap, which is why CRCs are everywhere (networking included).
| how it works | strength | speed | |
|---|---|---|---|
| XOR | XOR every chunk of the block into one word | weak β two flips in the same bit position cancel | very fast |
| addition | 2's-complement add each chunk, ignoring overflow | weak β fooled if the data is merely shifted | very fast |
| Fletcher | two running bytes s1, s2 (each mod 255) | strong β all single-/double-bit and many burst errors | moderate |
| CRC | treat the block as a big number; take remainder mod k | strong | fast β the binary modulo is cheap to implement |
Whatever the function, no checksum is perfect: two different blocks can produce the same summary β a collision checksum collision When two data blocks with non-identical contents produce the same checksum. Collisions are unavoidable β a checksum squeezes something large (e.g. 4 KB) into a tiny summary (e.g. 4β8 bytes) β so a good checksum function is one that merely minimizes the chance of collision while staying cheap to compute. defined in ch. 45 β open in glossary . Thatβs unavoidable when you squeeze 4 KB into 8 bytes; a good function just makes collisions rare while staying cheap.
Checksum layout: where do the checksums go?
Computing a checksum is only half the story β you also have to store it. Start with a plain run of data blocks and no protection:
The natural fix is one checksum right before each block. But checksums are tiny (β8 bytes) and disks write in 512-byte sectors, so this needs special 520-byte sectors (8 extra bytes each) from the drive maker:
On ordinary disks, the file system instead packs n checksums into one sector, followed by the n data blocks they cover:
This works everywhere, but separating a block from its checksum costs I/O: to overwrite block D1 you must read its checksum sector, update C(D1), then write back both the checksum sector and the data β one read and two writes, where the per-sector layout needed just one write. Another instance of TNSTAAFL.
Check yourself: failure modes and checksums
1.How does the fail-partial model differ from the fail-stop model early RAID assumed?
2.Why is a latent sector error (LSE) much easier to handle than block corruption?
3.Why does an LSE encountered DURING a full-disk reconstruction break a single-parity RAID-4/5, and how does RAID-DP fix it?
4.What is a checksum, and why can two different blocks share one (a collision)?
5.What is the known weakness of a simple XOR-based checksum shown by the worked example?
6.Storing checksums packed together (n checksums in a sector, then n data blocks) works on any disk. What's the cost versus one checksum per (520-byte) sector?