這個 syscall 能更有效的利用底層 file system 提供的機制加速 file 的 copy, 或更確切的說, 減少不必要的資源開銷.

File copy 說起來簡單, 舉 cp 命令而言, 一般的檔案內容的 copy 實現如下

$ strace cp src dest
...
open("src", O_RDONLY)                   = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1048576, ...}) = 0
open("dest", O_WRONLY|O_CREAT|O_EXCL, 0644) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc7977c3000
ioctl(3, FS_IOC_FIEMAP, 0x7ffd6f7c7370) = -1 EOPNOTSUPP (Operation not supported)
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 131072
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 262144
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 393216
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 524288
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 655360
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 786432
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 917504
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
lseek(4, 131072, SEEK_CUR)              = 1048576
read(3, "", 131072)                     = 0
ftruncate(4, 1048576)                   = 0
close(4)                                = 0
close(3)                                = 0
...

基本上就是從來源 read() 出資料後 write() 到目標. 這中間的問題有

  1. Buffer 的管理. 上面 cp 用的 buffer size 是最佳的嗎?
  2. 資料於 kernel <-> user space 間來回 copy 浪費 CPU 時間及 memory bandwidth
  3. 大量 context switch 帶來的額外負擔 - 尤其是 SSD 及 NVM 這樣的高速存儲
  4. 如何更高效的處理檔案上的洞 (hole)?
  5. 就算來源及目標檔案都在同一個 file system 中, 也不好實現 COW copy
  6. Buffer 經過了 user space, checksum 就得要重新計算
  7. 在 block level 是否有機會更高效的 dedup?
    (https://lwn.net/Articles/260795/)
  8. 在 NFS 上無法達成 server side copy, 造成資料在 client & server 間來回傳輸

基於以上需求及問題, kernel 社區經過多次討論及嘗試, 例如 reflink(), 最後成為即將進到 4.5 中的 copy_file_range(), 基本解決了上面提到的大部份問題, 當然, 這也需要 file system 內部實現的支持. 以後 cp 命令應該會比現在高效不少.