“共享文件页通常通过页缓存合并普通文件I/O与映射访问。OS 16明确采用同一缓存对象;真实系统的具体一致性、直接I/O混用和跨机器文件系统行为,应另查其契约。”
形式陈述
页缓存以(文件对象,文件页号)为键保存文件理路文件对象、目录与路径名Inode directory and pathname · Hard link and symbolic link · 硬链接与符号链接把名称到文件对象的映射与对象本身分开,执行逐分量路径解析、硬链接计数、符号链接与删除后的存活。内容的内存副本。OS-16普通read与write以及shared文件映射使用同一个页缓存对象。buffered write将实际接受的字节复制到缓存,更新必要的文件内存元数据;返回表示该次调用已接受这些字节,不要求设备块此刻稳定。
页缓存中的dirty表示内容相对于已经完成的下层写回尚有更新。writeback表示某一内容版本正由设备请求理路设备I/O、DMA与完成边界Device I/O and DMA · Polling interrupt DMA给设备请求建立提交、数据搬运、命令完成和稳定存储四个边界,核验描述符所有权、DMA地址与缓冲生命周期。发送;两者可同时成立。为精确说明再变脏窗口,本页使用单页教学状态(g,c,w):g是当前内容代际,c是已成功完成下层写回的代际,w是当前在途代际或空。每次缓存写递增g,dirty定义为g>c;提交时冻结该代内容快照并置w=g,完成时推进c到该在途代际并清w。
这是OS-16的版本化解释模型,不宣称Linux直接用三个同名计数器。真实实现可使用dirty/writeback位、页锁及重新标脏协议。这里每页至多一个在途回写,设备保持该页版本顺序,失败完成不推进c。
另外记录稳定设备版本s。c推进只表示普通设备命令完成;若设备有易失写缓存,s仍可小于c。页缓存干净不等于数据跨过掉电边界。
直觉
一层缓存完成自己的责任,只说明更新已交给下一层按合同处理。应用的stdio缓冲交给内核、内核页缓存交给设备、设备缓存交给稳定介质,是三个不同的交接点。每个“成功”都应问清它在回答哪一层的问题。
回写也不是暂停世界后拍一张永久照片。设备正在写昨天的版本,应用可以已经改出今天的版本;旧请求完成只能证明昨天那份已送到下层。
例子与边界
一次write和两次回写
inode42稳定内容为abcdefgh,初始g=c=s=0。P在共享offset2处write XY返回2,页缓存为abXYefgh,g=1、c=0、dirty=true;稳定内容仍旧。
| 事件 | 当前缓存 | (g,c,w) | dirty | 设备稳定版本s |
|---|---|---|---|---|
write XY返回 |
abXYefgh | (1,0,空) | 是 | 0 |
| 提交代1快照 | abXYefgh | (1,0,1) | 是 | 0 |
| 应用又把第0B写Z | ZbXYefgh | (2,0,1) | 是 | 0 |
| 代1设备完成 | ZbXYefgh | (2,1,空) | 是 | 0 |
| 提交并完成代2 | ZbXYefgh | (2,2,空) | 否 | 0 |
| 相应flush成功 | ZbXYefgh | (2,2,空) | 否 | 2 |
在第四行无条件清dirty会丢掉代2的回写责任;在第五行把干净当持久,会忽略设备易失缓存。若第五行后掉电且设备尚未自行稳定,最终仍可能恢复abcdefgh;第六行后则必须恢复代2。
返回前后可见性与错误不同步
在表第一行write返回后、尚未写Z之前,另一个进程按顺序read同一inode相同区域,OS-16从缓存可读到abXYefgh,即使设备还完全没处理它。这验证了可见性,不验证持久性。反之,设备后来写回失败,错误可能直到fsync才由应用获知;write早先成功不能排除延迟错误。
fwrite还可能仅写到用户态库缓冲,尚无系统调用。调用fsync之前,若所需字节仍在该缓冲中,内核根本无从同步它们;必须先按库接口成功flush,且仍检查后续持久化错误。fflush本身只完成这一层交接。
推论与应用
回写快照要么独立复制,要么通过锁/所有权保证设备看到提交的那一代。若设备DMA读取期间应用直接改同一内存,没有合适同步,就可能发送不同代际混合的字节,不能仅用一个版本号宣称整页一致。
OS-16分别保持0≤s≤g和0≤c≤g,在途w来自提交时g且完成只推进c到w。s和c没有固定大小关系:设备可以在通知完成之前先稳定代1,使s=1而c=0;也可以先通知接收完成而仍未稳定,使c=1而s=0。应用写增加g,回写完成推进c,设备稳定写推进s;成功flush保证所覆盖的写都已稳定,在无新写且最新代已提交的场景得到s=g。这个证明依赖同页写顺序及完整快照;若允许多代在途乱序稳定,就需要阻止旧代覆盖新代的协议。
CPU的缓存dirty块理路缓存写策略与脏块回写Write-back and write-through · Write allocation policy · Dirty cache line分开写命中传播与写缺失分配两条策略轴,追踪脏块逐出和终末flush,区分回写与持久化。和文件页dirty不处在同一层:CPU回写到DRAM可以让内核看到新字节,却仍没有启动文件I/O。数据库缓冲池也可在用户态再加一层,自己的脏页、pin和事务LSN须与OS页缓存分别记账。
参考资料
- Remzi与Andrea Arpaci-Dusseau,OSTEP: File System Implementation,缓存与写缓冲;本文代际状态机及redirty轨迹独立构造。
- Linux man-pages 6.19,write(2)、fsync(2)、fflush(3),成功返回、延迟错误与用户缓冲边界。