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