2014-01-10 62 views
2

我知道splice()被設計爲零拷貝,並使用Linux內核管道緩衝區來實現。例如,如果我想將數據從一個文件描述符(fp1)複製到另一個文件描述符(fp2),則不需要從「內核空間 - >用戶空間 - >內核空間」複製數據。相反,它只是複製內核空間中的數據,流程將如同「fp1 - > pipe_read - > pipe_write - > fp2」。 我的問題是劑量內核需要在「fp1 - > pipe_read」和「pipe_write - > fp2」之間複製數據?Linux內核splice()是否零拷貝?

維基百科說:

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)我的問題,我發現「write_pipe fp1->」之間的流動,它到底會叫kernel_readv()在fs/splice.c然後稱爲 「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 - >寫()「

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

而且我認爲這兩個 「aio_write()」 和 「文件 - > f_op_write()」 將執行真正的數據拷貝,所以沒有拼接()真正執行零拷貝?

+0

請參考[答](http://stackoverflow.com/questions/17268826/splice-system-call-what-is-passed-to-the-pipe-data-or-whereabouts-info?answertab =票#標籤頂) –

+0

感謝responing但如果有FP和管 – VTxyer

回答

2

據我瞭解splice(),它會讀取fd1的頁面,MMU將映射這些頁面。映射創建的參考將被放入管道並交給fd2。 只要每個參與者都有DMA可用,就不應該在過程中複製實際數據。 如果沒有DMA可用,則需要複製數據。

1

splice很可能是零拷貝(對此沒有硬性保證,但對於任何合理的最新硬件,它幾乎肯定會以這種方式工作)。嚴格遵循文檔,您需要使用SPLICE_F_MOVE來調用它,所以沒有實際的副本,但只要有DMA支持(這是一個相當公平的假設),我不知道如何創建一個副本。

同樣是不一定vmsplice,因爲它涉及到(或連續splice)只適用零拷貝true,如果提供了SPLICE_F_GIFT標誌(在這種情況下,我可以看到它怎麼會不工作否則,因爲「源描述符」是主內存),但是這個標誌在某些中斷,在其他Linux版本中不受支持,並且在頂部記錄嚴重。
例如,之後不清楚如何處理內存。這些文檔曾經說過,你不允許觸及天才的記憶,最近這個記憶被稍微改了一下,但並不是那麼模棱兩可。目前還不清楚內存區域將變成什麼樣子。以下的文件,你將不得不泄漏的內存。似乎沒有通知機制可以告訴你什麼時候釋放內存或重用內存是安全的。

aio_write是使用線程和系統調用write的異步I/O的用戶空間(Glibc)實現。這通常執行至少一個從用戶空間到內核空間的副本。

+0

之間複製鏈接仍然沒有回答繼內核開發線程,可以重用內存只要你有一些協議的具體辦法知道所有數據已發送。例如對於一個套接字,另一方需要在協議級別檢查數據,並且當你看到你知道重用頁面是安全的。目前尚不清楚的是,它是否仍然以這種方式工作,如果它目前爲零拷貝或者沒有,因爲由於執行錯誤而暫時禁用。 – Eloff

+1

@Eloff:問題是,我怎麼會知道數據拼接到一個套接字(比方說TCP,所以實際上有一個確認)已被成功發送? 'splice'函數沒有告訴我(它只是告訴我它接受了多少,而不是它對它做了什麼,或者發生了什麼),並且等待'(E)POLLOUT'是徒勞的,因爲它會返回「就緒「,當有多達1個字節的發送緩衝區可用時,無論先前寫入的內容是否被確認或發送。 – Damon

+1

有趣的是,使用UDP套接字更容易,因爲您必須在應用程序級別自己進行確認,以便您能夠看到這些信息。一旦你在那裏收到一個ACK,你發送的內容肯定已經到達了另一端。 – Damon