Linux内核splice()是零拷贝吗?

时间:2014-01-10 02:36:28

标签: c linux linux-kernel

我知道splice()是为零拷贝而设计的,并使用Linux内核管道缓冲来实现这一点。例如,如果我想将数据从一个文件描述符(fp1)复制到另一个文件描述符(fp2),则不需要从“内核空间 - >用户空间 - >内核空间”复制数据。相反,它只是复制内核空间中的数据,流程将类似于“fp1 - > pipe_read - > pipe_write - > fp2”。 我的问题是剂量内核需要在“fp1 - > pipe_read”和“pipe_write - > fp2”之间复制数据?

维基百科说:

Ideally, splice and vmsplice work by remapping pages and do not actually copy any data,    
which may improve I/O performance. As linear addresses do not necessarily correspond to
contiguous physical addresses, this may not be possible in all cases and on all hardware 
combinations.

我已经跟踪了kernel source(3.12)我的问题,我发现“fp1-> write_pipe”之间的流程,最后它会在fs/splice.c中调用kernel_readv()然后调用“do_readv_writev” ()“最后调用”aio_write()“

558 static ssize_t kernel_readv(struct file *file, const struct iovec *vec,
559                 unsigned long vlen, loff_t offset)
//*vec would point to struct page which belong to pipe

最后“read_pipe - > fp2”之间的流程会调用“__kernel_write()”,然后调用“fp2-> f_op-> write()”

430 ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
//*buf is the pipe buffer

我认为“aio_write()”和“file-> f_op_write()”都会执行真正的数据复制,所以splice()真的执行零拷贝吗?

2 个答案:

答案 0 :(得分:2)

据我了解splice(),它将读取fd1的页面,MMU将映射这些页面。映射创建的引用将被放入管道并移交给fd2。 只要每个参与者都有DMA可用,就不应该在过程中复制真实数据。 如果没有可用的DMA,则需要复制数据。

答案 1 :(得分:1)

splice最有可能是零拷贝(没有硬保证,但它几乎肯定适用于任何合理的近期硬件)。严格遵循文档,你需要用SPLICE_F_MOVE来调用它,所以没有制作实际的副本,但我不知道只要有DMA支持(这是一个相当的方式,它需要如何制作一个副本)公平的假设)。

对于vmsplice不一定为真,因为如果提供splice标志,它(或连续的SPLICE_F_GIFT)只能进行零拷贝(在这种情况下,我可以看到它不会如何工作,因为“源描述符”是主内存)但是这个标志在某些情况下被破坏而在其他Linux版本中不受支持,并且记录不完整在上面。
例如,之后不清楚如何处理内存。文档过去常常说你不允许触摸有天赋的记忆,这最近有点重写,但它并没有那么模糊。目前尚不清楚记忆区域会变成什么样。在文档之后,您必须泄漏内存。似乎没有通知机制可以告诉您何时可以安全地释放内存或重复使用它。

aio_write是异步I / O的userland(Glibc)实现,它使用线程和write系统调用。这通常至少执行一次从用户空间到内核空间的复制。