FICLONE 与 FICLONERANGE 与 copy_file_range 的区别(用于写时复制支持)

Difference of FICLONE vs FICLONERANGE vs copy_file_range (for copy-on-write support)

我想知道复制文件的有效方法(在 Linux,在支持 copy-on-write (COW) 的 FS 上)。 具体来说,我希望我的实现尽可能使用写时复制,否则回退到其他有效的变体。具体来说,我还关心服务器端复制(由SMB, NFS and others), and also zero-copy支持(即如果可能绕过CPU或内存)。

(这个问题并不是真正特定于任何编程语言。它可以是 C 或 C++,也可以是任何其他语言,例如 Python、Go 或任何与 OS 系统调用有绑定的东西,或者有任何方法可以进行系统调用。如果这让您感到困惑,请用 C 回答。)

看起来像 ioctl_ficlonerange, ioctl_ficlone (i.e. ioctl with FICLONE or FICLONERANGE) support copy-on-write (COW). Specifically FICLONE is used by GNU cp (here,来自 --reflink)。

然后还有copy_file_range,好像也支持COW,和server-side-copy。 (LWN about copy_file_range.)

听起来好像 copy_file_range 更通用(例如,它支持服务器端复制;不确定 FICLONE 是否支持)。

但是,copy_file_range 似乎有一些问题。 例如。 here,Paul Eggert 评论:

[copy_file_range]'s man page says it uses a size_t (not off_t) to count the number of bytes to be copied, which is a strange choice for a file-copying API.

是否存在 FICLONEcopy_file_range better/different 更有效的情况?

是否存在 FICLONEFICLONERANGE better/different 更有效的情况?

具体来说,假设底层 FS 支持这个,并假设你想复制一个文件。我问一下这些函数的支持功能为:

他们(FICLONEFICLONERANGEcopy_file_range)是否总是执行完全相同的操作? (假设底层FS支持写时复制,and/or服务器端复制。)

或者是否存在使用 copy_file_range 而不是 FICLONE 有意义的情况? (例如,COW 只适用于 copy_file_range 但不适用于 FICLONE。或者反过来。或者这永远不会发生?)

或者以不同的方式表述相同的问题:copy_file_range 总是没问题,还是在某些情况下我想改用 FICLONE

为什么 GNU cp 使用 FICLONE 而不是 copy_file_range? (是否有技术原因,或者这只是历史原因?)

相关:GNU cp 原来默认不使用reflink(参见comment by the GNU coreutils maintainer Pádraig Brady)。 但是,最近发生了变化 (this commit, bug report 24400),即 COW 行为现在是默认行为(如果可能的话)(--reflink=auto)。

相关.

相关discussion about FICLONE vs copy_file_range by Python developers。 IE。这似乎是一个有效的问题,并且不完全清楚是使用 FICLONE 还是 copy_file_range.

相关 Syncthing documentation about the choice of methods for copying data between files,以及 Syncthing issue about copy_file_range and others for efficient file copying, e.g. with COW support。 它还表明,FICLONE 是否会与 copy_file_range 做同样的事情还不是很清楚,因此他们的解决方案是只尝试所有这些,然后按以下顺序回退到下一个: ioctl(使用 FICLONE),copy_file_range,sendfile,duplicate_extents,标准。

相关issue by Go developers on the usage of copy_file_range。 听起来好像他们同意 copy_file_range 总是优于 sendfile

(从here复制的问题,但我看不出这太不集中了。这个问题非常集中,问了一个非常具体的事情(FICLONE和copy_file_range的行为是否相同), 并且应该非常清楚。我以多种不同的方式提出问题,使问题更加清楚。这个问题也得到了非常好的研究,并且应该已经对社区非常有价值,因为所有参考资料都是如此。当我开始研究 FICLONE 和 copy_file_range 之间的差异时,如果我能自己找到这样一个问题,即使没有答案,我也会很高兴。)

参见 Linux vfs doc 关于 copy_file_rangeremap_file_rangeFICLONERANGEFICLONEFIDEDUPERANGE

接着看 vfs_copy_file_range。如果可能,这将首先尝试调用 remap_file_range

FICLONE 调用 ioctl_file_clone (here), FICLONERANGE 呼叫 ioctl_file_clone_rangeioctl_file_clone_range 调用更通用的 ioctl_file_clone (here)。 ioctl_file_clone 呼叫 vfs_clone_file_range (here)。 vfs_clone_file_range 调用 do_clone_file_range 并且调用 remap_file_range (here).

即这回答了问题。 copy_file_range 更通用,无论如何都会首先在内部尝试调用 remap_file_range(即与 FICLONE/FICLONERANGE 相同)。

我认为 copy_file_range 系统调用比 FICLONE 稍新,也就是说,copy_file_range 可能在您的内核中不可用,但 FICLONE 可用。

无论如何,如果copy_file_range可用,那应该是最好的解决方案。

Syncthing (ioctl (with FICLONE), copy_file_range, sendfile, duplicate_extents, standard) 完成的命令是有意义的。