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

时间:2010-09-21 21:57:38

标签: directory posix rename ext4 fsync

在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)

具体问题

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

提前致谢。

4 个答案:

答案 0 :(得分:15)

POSIX定义了rename function must be atomic

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

但这并不能解决确保rename()操作持久的问题。 POSIX answers this question

  

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

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

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

  

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

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

(更新了附加信息:Linux特定与便携行为)

答案 1 :(得分:12)

不幸的是戴夫的回答是错误的。

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

真正的问题应该是:

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

您需要在源目标目录上执行fsync(),因为fsync()应该执行的最小操作是源或目标目录应该是什么样的。< / p>

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

答案 2 :(得分:-1)

您的问题的答案将在很大程度上取决于所使用的特定操作系统,正在使用的文件系统的类型以及源和目录是否在同一设备上。

我首先阅读您正在使用的平台上的rename(2)手册页。

答案 3 :(得分:-4)

听起来像你正在尝试完成文件系统的工作。如果移动文件,则内核和文件系统负责原子操作和故障恢复,而不是代码。

无论如何,这篇文章似乎解决了有关fsync的问题: http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/