“若指针和size先稳定而位图仍为0,重启后的分配器可把块30交给另一文件,产生双重占用。若位图先稳定而指针丢失,则块30泄漏。若新块未初始化就经指针发布,还可能泄漏旧文件残留。文件系统日志要…”
形式陈述
文件系统日志把一次关联的块与分配元数据更新理路文件块映射与空间分配File block mapping · Direct and indirect blocks · 文件块位图分配由文件字节偏移经过inode直接和间接指针找到设备块,并把数据、大小、指针和空闲位图的共同恢复义务列全。放进恢复域。本文构造OS-16的单事务重做日志:事务修改至多4个不同home块,记录每块完整after-image及目标块号;一次只有一个事务,日志在前一事务完全安装并清空之前不得复用,不允许未提交修改写到home。设备采用普通写可易失、flush成功才稳定理路设备I/O、DMA与完成边界Device I/O and DMA · Polling interrupt DMA给设备请求建立提交、数据搬运、命令完成和稳定存储四个边界,核验描述符所有权、DMA地址与缓冲生命周期。的合同,256B稳定块写原子,跨块不原子。
日志有4个payload槽L0…L3和一个原子头H。空头为EMPTY,提交头为COMMIT(t,n,targets);t只标识本轮事务,n与目标列表必须完整有效。磁盘空间固定、目标合法且不指向日志自身。本模型排除撕裂块与静默损坏;真实实现需额外校验和、代际和介质错误处理。
协议明确使用先有稳定恢复证据再发布效果理路预写日志Write-ahead logging · WAL规定数据页落盘与提交确认前必须先持久化相应日志,使崩溃后的撤销和重做拥有可靠依据。的原则,具体顺序为:
- H已稳定为空时,写全部after-image到payload槽,flush成功
- 写提交头H并flush成功,此处是持久提交点
- 把payload写入各home块,flush成功,此处是checkpoint完成
- 将H改为空并flush成功,之后日志才可用于下一事务
恢复完成之前不开放普通文件访问,不能把尚在混合安装阶段的home作为一致文件系统供应用读取。恢复先读稳定H。空则不重放;合法COMMIT则依目标列表把全部after-image装到home并flush,最后清H并flush。恢复本身也遵守第3、4步。
直觉
日志提交与home安装是两个时刻。提交保证已经有一份足够完整的重做依据,home安装把它搬到正常读取位置。提交之后哪怕只搬完一个块便掉电,恢复仍可把其他块补齐。
“日志清掉了”也有稳定边界。若只在内存中清头便重用payload,掉电后旧提交头仍可能指向新一轮内容;旧事务的身份不能和新事务的字节混在一起。
例子与边界
新建文件的四个块必须同一代
初始目录d没有new,inode43未分配,数据块70空闲。事务T建立new→43,内容NEW,修改四个home块:70的数据、80的块位图、81的inode记录、82的目录记录。它们的after-image分别放入日志90…93,提交头位于94。
| 崩溃位置 | 稳定头 | home可能状态 | 恢复结果 |
|---|---|---|---|
| payload只稳定一部分 | EMPTY | 全旧 | 忽略未提交payload,仍无new |
| 全payload稳定但头未稳定 | EMPTY或COMMIT | 全旧 | 依稳定头选择旧或完整新 |
| 提交头稳定后 | COMMIT | 0至4个home已新 | 重做四块,得到完整新 |
| home全部稳定、头尚未清稳 | COMMIT | 全新 | 重复after-image仍为完整新 |
| 空头已稳定 | EMPTY | 全新 | 无需重放,日志可复用 |
恢复不变量不是“设备上时时四块一起变”,而是每个允许崩溃点经恢复后,四个相关home共同等于完整旧状态或已提交新状态。中间home可以混合,只要稳定日志足以完成已提交事务。
三个看似省事的错误
省略payload的flush而先提交头:设备可能先稳定COMMIT,payload仍旧;恢复得到错误内容。省略home的flush而清头:恢复见EMPTY,却只有部分home新,没有可用日志补齐。省略清头的flush而复用payload:旧COMMIT可能配上新payload,恢复一个从未提交的混合事务。
这些错误分别破坏“提交证据完整”“清除前结果已安装”“复用前旧身份已失效”。一次顺序运行恰好没遇到乱序不能证明它们安全。
推论与应用
证明分两种稳定头。H为空时,未提交事务不曾写home;或者先前home已全部稳定,因此有完整状态。H为COMMIT时,先行flush保证其所有payload稳定,恢复写完整after-image得到新状态。after-image重复写幂等,所以恢复过程中再次掉电仍可从同一日志继续;只有home全部稳定后才可能持久清头。归纳覆盖任意有限次恢复中再崩溃。
对n个不同home块,本协议通常需n次payload写、1次提交头写、n次home写、1次清头写,总2n+2次块写及4次flush;n=4即10次块写。可用组提交、合并同块更新等优化,但要重证顺序。这里不把延迟home写的性能收益说成没有额外写放大。
真实xv6 rev5 §10.5–10.6有日志吸收和分块write;较大的write可能跨多个事务,不能由“有日志”推出整次write原子。ext4也有metadata-only、ordered及data-journal等模式;本页特意日志化这4块完整内容,不能把其数据原子性直接赋给默认ext4模式。底层设备flush契约是本模型另加的保证,不从教材中的同步函数名自动推出。
参考资料
- Cox、Kaashoek、Morris,xv6教材 rev5,§10.4–10.6,日志事务、提交、安装与容量边界。
- Remzi与Andrea Arpaci-Dusseau,OSTEP: Crash Consistency—FSCK and Journaling,第42章。
- Linux Kernel Documentation,ext4 Journal (jbd2),2026-10-08访问的滚动文档,metadata/data模式对照;本文不是jbd2格式实现。