不幸的是,戴夫的回答是错误的。
并非所有 POSIX 系统甚至都可能具有持久存储。如果他们这样做了,它仍然“允许”在系统崩溃后被冲洗。对于那些系统,无操作 fsync() 是有意义的,并且在 POSIX 下明确允许这样的 fsync()。可以在旧目录、新目录、两者或任何其他位置恢复文件也是合法的。POSIX 不保证系统崩溃或文件系统恢复。
真正的问题应该是:
如何在通过 POSIX API 支持的系统上进行持久重命名?
您需要在源目录和目标目录上都执行 fsync(),因为这些 fsync() 应该做的最低限度是保持源目录或目标目录的外观。
fsync(destdirfd) 是否也隐式地 fsync 源目录?
- 一般的POSIX:不,没有任何暗示
- ext3/4:我不确定源目录和目标目录的更改是否最终都出现在日志中的同一事务中。如果他们这样做,他们就会一起承诺。
或者我可能会在电源循环(“崩溃”)后在两个目录中显示文件,即不可能保证持久的原子移动操作?
- 一般的 POSIX:没有保证,但你应该 fsync() 两个目录,这可能不是原子持久的
- ext3/4:你最少需要多少 fsync() 取决于挂载选项。例如,如果使用“dirsync”挂载,则不需要这两个 fsync() 中的任何一个。最多你需要两个 fsync(),但我几乎可以肯定一个就足够了(那么原子耐用)。
如果我 fsync 源目录而不是目标目录,那是否也会隐式 fsync 目标目录?
- POSIX:没有
- ext3/4:我真的相信两者都会在同一个事务中结束,所以你 fsync() 中的哪一个并不重要
- 较旧的内核 ext3:(如果它们不在同一个事务中)一些不太理想的实现在 fsync() 上进行了太多同步,我敢打赌它确实提交了之前的每个事务。是的,正常的实现会首先将其链接到目标,然后将其从源中删除。所以 fsync(srcdirfd) 也会触发目标的 fsync() 。
- ext4/latest ext3:如果它们不在同一个事务中,您可能能够完全独立地同步它们(两者都这样做)
是否有任何有用的相关测试/调试/学习工具(故障注入器、自省工具、模拟文件系统等)?
对于真正的崩溃,不。顺便说一句,真正的崩溃超出了内核的观点。硬件可能会重新排序写入(并且无法写入所有内容),从而破坏文件系统。Ext4 对此做好了更好的准备,因为它默认启用写屏障(挂载选项)(ext3 没有),并且可以使用日志校验和检测损坏(也是挂载选项)。
并且为了学习:找出这两个变化是否在日志中以某种方式联系起来!:-P