如何在POSIX中持久重命名文件?

Yan*_*ang 18 directory posix rename fsync ext4

在POSIX文件系统中持久重命名文件的正确方法是什么?特别想知道目录上的fsyncs .(如果这取决于OS/FS,我问的是Linux和ext3/ext4).

注意:在StackOverflow上还有关于持久重命名的其他问题,但是AFAICT它们没有解决fsync-ing目录(这对我来说很重要 - 我甚至不修改文件数据).

我目前有(在Python中):

dstdirfd = open(dstdirpath, O_DIRECTORY|O_RDONLY)
rename(srcdirpath + '/' + filename, dstdirpath + '/' + filename)
fsync(dstdirfd)
Run Code Online (Sandbox Code Playgroud)

具体问题:

  • 这是否也暗含fsync源目录?或者我可能会在电源循环后最终显示两个目录中的文件(意味着我必须检查硬链接计数并手动执行恢复),即不可能保证持久的原子移动操作?
  • 如果我fsync源目录而不是目标目录,那还会隐式fsync目标目录吗?
  • 是否有任何有用的相关测试/调试/学习工具(故障喷射器,内省工具,模拟文件系统等)?

提前致谢.

Dav*_*eco 15

POSIX定义重命名函数必须是原子的.

因此,如果重命名(A,B),在任何情况下都不应该在两个目录或两个目录中都看到该文件的状态.无论你使用fsync()做什么或系统是否崩溃,总会有一个.

但这并不能解决确保rename()操作持久的问题. POSIX回答了这个问题:

如果定义了_POSIX_SYNCHRONIZED_IO,则fsync()函数将强制与文件描述符fildes指示的文件关联的所有当前排队的I/O操作进入同步I/O完成状态.所有I/O操作都应按照同步I/O文件完整性完成的定义完成.

因此,如果您对目录执行fsync(),则必须在挂起的重命名操作返回时将其传输到磁盘.任一目录的fsync()都应该足够了,因为rename()操作的原子性要求两个目录的更改以原子方式同步.

最后,与另一个答案中提到的博客文章中的声明相反,其理由解释如下:

fsync()函数用于强制从缓冲区高速缓存中物理写入数据,并确保在系统崩溃或其他故障之后,直到fsync()调用时的所有数据都记录在磁盘上.由于这里没有定义"缓冲区缓存","系统崩溃","物理写入"和"非易失性存储"的概念,因此措辞必须更加抽象.

声称符合POSIX并且认为完成fsync()并且不会在系统崩溃中持续存在这些更改的正确行为(即不是错误或硬件故障)的系统必须故意歪曲自己的规范.

(更新了附加信息:Linux特定于可移植行为)


Rob*_*mer 12

不幸的是,戴夫的回答是错误的.

并非所有POSIX系统都可能具有持久存储.如果他们这样做,它仍然被"允许"在系统崩溃后被冲洗.对于那些系统,no-op fsync()是有意义的,并且在POSIX下明确允许这样的fsync().在旧目录,新目录,两者或任何其他位置可以恢复文件也是合法的.POSIX不保证系统崩溃或文件系统恢复.

真正的问题应该是:

如何在通过POSIX API支持的系统上进行持久重命名?

您需要在源目录目标目录上执行fsync(),因为fsync()s应该执行的最小值是持久化源目标或目标目录应该是什么样子.

fsync(destdirfd)是否也隐式fsync源目录?

  • POSIX一般:不,没有任何暗示
  • ext3/4:我不确定源和目标dir的更改是否都会在日志中的同一事务中结束.如果他们这样做,他们两个都会在一起.

或者我可能会在电源循环("崩溃")后最终显示两个目录中的文件,即不可能保证持久的原子移动操作?

  • POSIX一般:没有保证,但你应该fsync()两个目录,这可能不是原子持久的
  • ext3/4:你最低需要多少fsync()取决于挂载选项.例如,如果使用"dirsync"安装,则不需要任何这两个fsync().最多你需要两个fsync(),但我几乎可以肯定一个就足够了(原子耐用).

如果我fsync源目录而不是目标目录,那还会隐式fsync目标目录吗?

  • POSIX:没有
  • ext3/4:我真的相信两者都会在同一个事务中结束,所以你fsync中的哪一个并不重要()
  • 较旧的内核ext3 :(如果它们不在同一个事务中)某些不那么优化的实现在fsync()上实现了太多的同步,我敢打赌它确实提交了之前的每个事务.是的,正常的实现首先将它链接到目标,然后从源中删除它.所以fsync(srcdirfd)也会触发目标的fsync().
  • ext4/latest ext3:如果它们不在同一个事务中,您可以独立完全同步它们(两者都是如此)

是否有任何有用的相关测试/调试/学习工具(故障注入器,内省工具,模拟文件系统等)?

对于真正的崩溃,没有.顺便说一句,真正的崩溃超出了内核的观点.硬件可能会重新排序写入(并且无法写入所有内容),从而破坏文件系统.Ext4对此做了更好的准备,因为它默认启用写入barries(挂载选项)(ext3没有)并且可以使用日志校验和(也是挂载选项)检测损坏.

并且为了学习:找出两个变化是否在期刊中以某种方式相关联!:-P