当使用 rename() 替换现有文件时,哪些文件系统需要 fsync() 来保证崩溃安全?

当使用 rename() 替换现有文件时,哪些文件系统需要 fsync() 来保证崩溃安全?

auto_da_alloc在受到广泛投诉后,ext4 获得了默认启用的碰撞安全保证。其他文件系统呢?在最著名的文件系统中,哪些提供相同的保证(哪些不提供)?

就我个人而言,我有兴趣听到有关的信息

  • XFS - 红帽企业 Linux 默认文件系统。
  • btrfs - SuSE Enterprise 默认文件系统。
  • bcachefs- 树外 Linux 文件系统,源自 bcache。 “Linux 的 COW 文件系统不会占用您的数据。”

根据下面的历史记录,这个问题主要涉及 Linux。了解 ZFS 的行为方式也很有趣,但我倾向于假设它不会实现这一点。

什么是auto_da_alloc

fsync() 被充分记录为写入文件数据的正确方法,例如当您在文本编辑器中点击“保存”时。人们普遍认为,例如文本编辑器必须使用 rename() 以原子方式替换现有文件。这是为了防止断电,确保您始终保留旧文件或获取新文件(在重命名之前经过 fsync() 处理)。您不希望只留下新文件的半写入版本。

但存在一个问题,在最流行的 Linux 文件系统 ext3 上调用 fsync() 可能会导致整个系统挂起数十秒。由于应用程序对此无能为力,因此乐观地使用 rename() 而不使用 fsync() 是很常见的。即使系统断电,这种模式似乎在该文件系统上运行得相当好。

因此,存在未正确使用 fsync() 的应用程序。

文件系统的下一个版本 ext4 通常避免了 fsync() 挂起。与此同时,它开始更多地依赖于 fsync() 的正确使用。

这一切都很糟糕。可以说,许多相互冲突的内核开发人员使用的轻蔑短语无助于理解这段历史。

这个问题在 ext4 中得到了解决,支持 rename() 模式,无需 fsync() 以实现崩溃安全提供与旧的 ext3 文件系统相同的崩溃行为。如果使用选项挂载,可以再次禁用此行为noauto_da_alloc

答案1

这个问题有一个错误。这个问题暗示这个场景是这样的完全碰撞安全auto_da_alloc。对于 ext4 来说情况并非如此。我认为在旧的 ext3 中也不是这样。然而它对于 btrfs 和 bcachefs 都是如此。

最近的 ext4 确实有一个特殊的解决方法,通过在重命名时强制删除新数据块来减少通过重命名替换产生零长度文件的机会。然而,重命名不会等待刷新完成,因此不提供原子性保证——崩溃后可能只得到部分新内容。在我们测试的文件系统中,btrfs 是唯一提供替换通过重命名原子性保证的系统。

https://homes.cs.washington.edu/~lijl/papers/ferrite-asplos16.pdf


btrfs文档表示使用 rename() 替换文件将提供完整的原子性,并且不需要显式的 fsync() 来保护数据免遭崩溃。我认为这是添加的与 ext4 大约同时auto_da_alloc。我们还看到一种说法,即 btrfs 实现避免了性能下降,因为它不会导致 rename() 调用等待。但是我注意到在最近的内核中,至少如果您使用 fsync(),以下 rename() 将fsync() 父目录并等待整个“日志树”被写入

bcachefs目前似乎提供了全面的保护,尽管我没有找到任何文档。检查代码。 我看到对函数“filemap_write_and_wait_range”的调用

XFS拒绝为 rename() 添加崩溃安全解决方法。它显然获得了可以降低(但不会消除)不同情况下数据丢失风险的代码。

UBIFS(例如在许多 Openwrt 设备上使用)不包括 rename() 的任何崩溃安全解决方法。它可以被接受,但需要做很多工作。 http://www.linux-mtd.infradead.org/doc/ubifs.html#L_sync_exceptions

相关内容