我知道 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() 真的执行零复制吗?
最佳答案
据我了解,splice() 会读取 fd1 的页面,MMU 会映射这些页面。映射创建的引用将被放入管道并交给fd2。 在此过程中不应复制真实数据,只要每个参与者都有可用的 DMA。 如果没有可用的 DMA,则需要复制数据。
关于c - Linux 内核 splice() 是零拷贝吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21035237/