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