1. 故障场景设定
-
硬件:嵌入式设备,搭载 256MB MLC NAND Flash(页大小 2KB,块大小 128KB,OOB 大小 64B)。
-
分区:mtdblock3(30MB)挂载为 /data,文件系统为 JFFS2。
-
触发:设备异常断电重启后,启动脚本执行 mount -t jffs2 /dev/mtdblock3 /data失败,系统卡死。
2. 详细定位与分析过程
第一阶段:应用层与内核日志分析(捕捉症状)
操作:观察串口控制台输出或执行 dmesg | grep -i jffs2。
异常现象:
[ 5.678901] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x02a56780
[ 5.687623] jffs2: read failed at 0x02a56780, err -5 (EIO)
[ 5.693457] jffs2: Error: Node header CRC failed at 0x02a56800
[ 5.702331] jffs2: scan_mutex unlocked because of error -5
[ 5.708912] mount: mounting /dev/mtdblock3 on /data failed: Input/output error
分析:
-
Magic bitmask not found:JFFS2 在预期位置未找到节点幻数(0x1985),数据结构错乱。
-
Node header CRC failed:节点头校验和错误,数据无效。
-
关键线索:err -5 (EIO)。这表明错误不是 JFFS2 逻辑问题,而是底层 MTD/Flash 驱动报告了物理 I/O 错误。
第二阶段:MTD 驱动层追踪(注入调试打印)
操作:在 NAND 驱动关键函数(如 drivers/mtd/nand/raw/nand_base.c的 nand_read_page_op)添加打印,定位物理错误。
驱动代码逻辑与异常打印:
// 驱动读取函数伪代码
static int nand_read_page_op(…)
{
/* 1. 发送命令读取页数据 */
chip->cmdfunc(chip, NAND_CMD_READ0, 0x00, page);
/* 2. 读取数据到缓存 */
ret = chip->read_buf(chip, buf, chip->ecc.size + chip->ecc.bytes);
/* 3. ECC 校验(核心步骤) */
stat = chip->ecc.correct(chip, buf, &chip->ecc.code_buf[0], &chip->ecc.calc_buf[0]);
/* ———– 添加调试打印 ———– */
pr_err("DEBUG READ: Page=0x%08x, ECC_Stat=%d, Ret=%d\\n",
page, stat, ret);
/* ———————————— */
if (stat < 0) {
pr_err("NAND ECC Unc correctable error at page 0x%x\\n", page);
return -EIO; // 关键:返回输入/输出错误
}
return 0;
}
调试输出:
[ 5.612345] DEBUG READ: Page=0x02a56000, ECC_Stat=-74, Ret=0
[ 5.618999] NAND ECC Unc correctable error at page 0x02a56000
分析:驱动在读取物理页 0x02a56000时,ECC 引擎检测到不可纠正的错误(Uncorrectable),超过了纠错能力(如 BCH-8 只能纠 8bit),驱动被迫放弃并返回 -EIO。
第三阶段:物理层取证(nanddump 工具分析)
操作:使用 mtd-utils的 nanddump绕过文件系统,直接读取 Flash 物理数据。
# 读取特定块的数据和 OOB (Spare Area)
nanddump -p -b -s 0x02a56000 -l 0x2000 /dev/mtd3 | head -50
异常输出分析:
Reading from 0x02a56000 to 0x02a58000…
Page 0x02a56000 dump:
DATA:
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff | …………….
… (全 FF 或随机乱码) …
OOOB:
42 61 64 20 42 6c 6f 63 6b 21 20 52 65 6a 65 63 | Bad Block! Reject
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | …………….
分析:
OOB 标记:OOB 区域出现了 ASCII 字符串 "Bad Block! Reject",或者关键字节(如厂商规定的坏块标记位)非 0xFF。这表明该块已被控制器或 Bootloader 标记为坏块。
数据全 FF:数据区全 0xFF表明电荷完全流失,或曾被擦除但未写入成功。
逻辑断层:JFFS2 依靠连续的节点链(Node Chain)构建文件系统。坏块切断了这条链,导致 jffs2_scan_eraseblock()无法解析后续数据,挂载流程崩溃。





