代码之家  ›  专栏  ›  技术社区  ›  Some Name

复制加速与复制文件范围

  •  0
  • Some Name  · 技术社区  · 6 年前

    我正在学习Linux中两个文件描述符之间的内核数据传输,遇到了一些我无法理解的问题。这是引自 copy_file_range 参考页

    copy_file_range() 使文件系统有机会实现“复制” 加速”技术,例如使用回流(即两个或两个 在写磁盘上共享指向同一副本的指针的更多i节点 块)或服务器端拷贝

    我曾经认为索引节点是由 stat / statx 系统调用。这个 st_ino 类型是 typedef here 作为

    typedef unsigned long   __kernel_ulong_t;
    

    那么,“在写磁盘块上共享指向同一拷贝的指针的两个或多个i节点”是什么意思呢?

    1 回复  |  直到 6 年前
        1
  •  2
  •   SergGr    6 年前

    根据我的理解 copy_file_range 不需要通过用户模式传递数据意味着内核根本不需要从磁盘加载数据(它仍然可能,但不必加载),这允许通过将操作向下推到文件系统堆栈来进一步优化。这涵盖了通过NFS进行服务器端复制的情况。

    关于其他优化的实际答案从如何存储文件的介绍开始,如果您已经知道了,可以跳过它。

    在典型的Linux FS中,文件的存储方式有三层:

    1. 某些目录中的文件项(它本身就是一个包含此类项列表的文件)。这样的条目基本上将文件名映射到某个inode。它是通过存储inode编号aka来完成的。 st_ino 它实际上是指向某个表中inode的指针。

    2. 这个 inode 其中包含一些共享(请参阅进一步的)元数据(如 stat )以及一些指向存储实际文件内容的数据块的指针。

    3. 实际数据块

    例如,硬链接是某个目录中的记录,它指向与“原始”文件相同的inode(并增加inode中的“链接计数器”)。这意味着只有文件名(可能还有目录)是不同的,其余的数据和元数据在硬链接之间共享。请注意,创建硬链接是一种非常快速的文件复制方法。唯一的缺点是两个文件现在都必须永远共享它们的内容,所以这不是真正的副本。但是如果我们用一些 copy-on-write 方法修复“write”部分,效果会很好。这就是一些金融服务机构(如 Btrfs )通过回流进行支撑。

    这种在写时复制的技巧的思想是,您可以使用新的适当元数据创建一个新的inode,但仍然共享相同的数据块。您还可以在inode元数据的“不可见”部分的两个inode之间添加交叉引用,这样它们就知道它们共享数据块。显然,与真正的拷贝相比,这个操作非常快。再说一次,只要文件是只读的,所有的工作都是完美的。但与硬链接不同的是,我们可以处理写操作,并将它们视为独立的。执行某些写入操作时,fs会检查文件(或者更确切地说,inode)是否是数据块的唯一所有者,否则会在写入数据块之前复制数据。根据FS实现的不同,它可以在第一次写入时复制整个文件,也可以存储一些更详细的元数据,只复制必须修改的块,其余的块仍在文件之间共享。在以后的情况下,如果写大小大于块,则可能根本不需要复制块。

    所以最简单的技巧 copy_file_range() 可以做的是检查整个文件是否确实被复制,如果是这样,执行上面描述的回流技巧(显然,如果fs支持它的话)。

    如果fs支持数据块上更详细的元数据,那么还可以进行一些更高级的优化。假设您将文件开头的前n个字节复制到一个新文件中。然后,fs可以共享起始块,可能只需要复制最后一个未完全复制的块。