NFS協(xié)議端到端實例解析之寫數(shù)據(jù)流程
對于NFS來說,其寫模式包含同步寫,異步寫和直接寫等模式。模式的差異在于打開文件時指定的參數(shù)。限于篇幅,本文很難一一介紹所有模式,這里主要介紹一個核心流程。
NFS作為Linux下的文件系統(tǒng),為了實現(xiàn)與VFS的對接,NFS也要實現(xiàn)一套函數(shù)指針接口。以文件相關(guān)的操作為例,其實現(xiàn)的函數(shù)指針如下所示。對于寫數(shù)據(jù)來說,VFS會調(diào)用NFS的nfs_file_write函數(shù)。
圖片
在該函數(shù)中,如果有SYNC標(biāo)記則會觸發(fā)同步寫的流程,否則寫入緩存后就會返回給調(diào)用者。本節(jié)我們主要關(guān)注觸發(fā)同步寫的流程,也就是數(shù)據(jù)是如何從NFS文件系統(tǒng)發(fā)送到服務(wù)端的。
直接寫和同步寫都會觸發(fā)將數(shù)據(jù)發(fā)送到服務(wù)端的流程,本節(jié)以同步寫為例介紹數(shù)據(jù)是如何發(fā)送到服務(wù)端的。如果觸發(fā)同步刷寫,那么會調(diào)用nfs_file_fsync函數(shù),該函數(shù)是將緩存數(shù)據(jù)傳輸?shù)椒?wù)端的入口。該函數(shù)到后端訪問接口nfs_do_writepage的主線流程如下圖所示。
圖片
nfs_file_fsync主線流程
這里nfs_do_writepage用于將一個緩存頁發(fā)送到服務(wù)端,具體實現(xiàn)如下代碼所示。其中主要是功能由nfs_page_async_flush函數(shù)完成。這里比較重要的參數(shù)是pgio,在該參數(shù)中有頁數(shù)據(jù)傳輸相關(guān)的函數(shù)指針,關(guān)于該參數(shù)類型的詳細(xì)定義請參考內(nèi)核源代碼。
圖片
然后我們再從nfs_page_async_flush函數(shù)開始計數(shù)看一下主線流程,具體下圖所示。函數(shù)nfs_generic_pg_pgios就是在pgio初始化的函數(shù)指針,其在nfs_pageio_doio中被調(diào)用。該主線流程最終調(diào)用到nfs_initiate_pgio函數(shù),該函數(shù)完成PRC消息和參數(shù)的封裝,然后調(diào)用RPC服務(wù)的API函數(shù)完成請求。
nfs_page_async_flush主線流程
當(dāng)nfs_initiate_pgio調(diào)用rpc_run_task函數(shù)后,整個流程就進入RPC服務(wù)內(nèi)部了。也就是進入RPC服務(wù)狀態(tài)機的流程了。關(guān)于RPC狀態(tài)機的處理流程的介紹請參考本號相關(guān)內(nèi)容。
最后,我們將整個寫流程的簡圖展示一下,這里包括客戶端的函數(shù)調(diào)用流程和服務(wù)端的處理流程。其中客戶端的流程中省略了部分函數(shù)調(diào)用。
網(wǎng)絡(luò)文件系統(tǒng)訪問示意圖
服務(wù)端向RPC注冊了各種回調(diào)函數(shù),當(dāng)接收到客戶端的請求時會調(diào)用具體的回調(diào)函數(shù)進行處理。本例將調(diào)用nfsd3_proc_write函數(shù)。該函數(shù)最后調(diào)用VFS層的寫數(shù)據(jù)函數(shù),而VFS寫數(shù)據(jù)函數(shù)則調(diào)用具體文件系統(tǒng)(例如Ext4)的函數(shù)完成最終的寫數(shù)據(jù)操作。