C++ / a working model

149 / 163   ·   C11   ·   约 8 分钟

数据完整性与保护

先记住这句话

本章探讨在硬件不可靠时如何保证写入存储的数据日后能原样读回。内容涵盖局部磁盘故障(潜在扇区错误与静默损坏)、冗余恢复手段以及校验和检测技术,并强调空间与时间开销的权衡。

本篇内容
  1. 现代磁盘的局部故障
  2. 处理可检测的扇区错误
  3. 用校验和捕捉静默损坏
  4. 运行示例
  5. 动手练习

官方章节 PDF

现代磁盘的局部故障

早期设计假定磁盘要么完全正常要么整盘报废。现实中驱动器常在看似工作的状态下丢失个别扇区或静默改写内容。潜在扇区错误由磁头划伤或宇宙射线引起,磁盘ECC能发现并报错;静默损坏则来自固件写错位置或总线传输出错,磁盘自身毫无察觉。廉价盘出现这些问题的概率明显高于企业级盘,但即使后者也不能忽略。

处理可检测的扇区错误

潜在扇区错误一旦出现,磁盘会立即返回失败。存储层只需启用已有冗余:镜像盘读另一份副本,奇偶校验组则用其余块重建。真正的风险出现在整盘失效后的重建过程中又碰上第二个错误。此时单奇偶RAID无法完成恢复,因此一些系统增加第二份奇偶信息,用空间换取重建成功率。

用校验和捕捉静默损坏

静默损坏不会产生任何错误码,因此必须在数据旁保存一份短摘要。写入时计算校验和,读回时重新计算并比对;不匹配即判定损坏并转向副本。简单异或或字节累加速度快但漏检某些模式,CRC或加密哈希更强却更耗CPU。没有免费午餐:保护越强,开销越大。

常见误区

  • 以为磁盘ECC已足够而完全不做上层校验
  • 重建RAID时未预留额外冗余,一旦再遇扇区错误就丢失数据
  • 选用过弱的校验函数,无法发现特定翻转模式

运行一个例子

最低标准 C11 · 完整程序 · 下载 .c

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define BLOCK_SIZE 16

static uint8_t compute_xor_checksum(const uint8_t *block, size_t n) {
    uint8_t cs = 0;
    for (size_t i = 0; i < n; ++i) {
        cs ^= block[i];
    }
    return cs;
}

int main(void) {
    uint8_t block[BLOCK_SIZE];
    const char *msg = "Hello OSTEP!";
    memset(block, 0, BLOCK_SIZE);
    strncpy((char *)block, msg, BLOCK_SIZE - 1);
    uint8_t stored_cs = compute_xor_checksum(block, BLOCK_SIZE);
    printf("Stored data: %s\n", (char *)block);
    printf("Stored checksum: 0x%02X\n", stored_cs);
    block[3] ^= 0x01;  /* silent corruption */
    uint8_t read_cs = compute_xor_checksum(block, BLOCK_SIZE);
    printf("Read checksum: 0x%02X\n", read_cs);
    if (read_cs != stored_cs) {
        printf("Corruption detected! Data integrity violated.\n");
    } else {
        printf("Checksums match.\n");
    }
    return 0;
}

在本地编译

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-45-data-integrity.c -o example && ./example

预期结果

Stored data: Hello OSTEP!
Stored checksum: 0x1E
Read checksum: 0x1F
Corruption detected! Data integrity violated.

CHECK YOUR UNDERSTANDING

合上答案,试着解释。

为何在已经使用RAID的情况下仍必须计算并验证校验和?

查看参考答案

RAID能应付整盘故障或磁盘主动报告的错误,却无法发现静默改写,因为被篡改的数据仍可能让奇偶校验通过。校验和在每个块上独立验证内容是否被改动,两者互补。

继续查证

标准草案与官方章节会更新;版本标记只说明示例最低要求。

回到目录