天天看點

【ceph】CephFS 内部實作(二):示例--未消化

之前面試時被問到描述下一個請求的完整流程,當時的結果很不理想,今天嘗試重新組織下,記錄在這裡。
【ceph】CephFS 内部實作(二):示例--未消化

ceph-fuse1.png

這裡有篇​​文章​​通俗易懂地描述了VFS層頁緩存在cephfs中會有哪些“坑”以及相應政策。

mount後發生了什麼?

ceph-fuse在不指定rootpath參數時,client端的root inode和mds的root一樣。如果指定了rootpath參數,那麼client端的root inode則是rootpath中的最後一個dentry的inode,不過從這個inode的往上一直到mds root inode的路徑上的所有inode也都會在client端存一份副本(下圖紅色圓圈節點),這些父節點是為了計算quota時使用,比如quota可能設定在了mds root inode上,這時client端如果沒有mds root inode則無法正确得到quota值,除此之外這些父節點inode别無他用。

【ceph】CephFS 内部實作(二):示例--未消化

rootpath=/dir時

ceph-fuse接收到的請求一定是關于一個inode的,這點可以通過​

​Client::ll_xxx​

​函數定義看出。而且這個inode必須是已經從mds擷取過的。舉例來說,剛mount完成時,client端的中繼資料資訊隻有root inode(及其父節點inode),這時FUSE是不會直接向client(即ceph-fuse)請求一個非root inode直接子節點的,這一點是由VFS+FUSE子產品保證的。

打開檔案

通過​

​open()​

​​系統調用打開檔案時,傳入參數是一個路徑,FUSE子產品會從root節點一個dentry一個dentry地周遊(通過​

​Client::ll_lookup()​

​​)路徑,確定每個節點對應的inode都已經存在client端。如果在一個剛mount好的client中請求一個目錄深度很深的路徑,在系統調用上看隻是一個請求,但實際上在client和mds間會産生多次通信,路徑越深通信往返次數越多。

打開檔案是需要給​​

​open()​

​​傳入​

​flat_t​

​​表示讀寫權限,這些系統flag在client端會先轉換成​

​CEPH_FILE_MODE_xxx​

​​,然後每個​

​CEPH_FILE_MODE_xxx​

​​對應到一組CAP ​

​CEPH_CAP_xxx​

​,如果client已經擁有所需CAP,則成功傳回,否則向mds發起請求。

【ceph】CephFS 内部實作(二):示例--未消化

client側看open()

在隻有一個client時,client會作為loner擁有全部cap,這種情況比較簡單,通常在一次請求内就能完成。稍微複雜些的是多個client的情況。

【ceph】CephFS 内部實作(二):示例--未消化

第二個client調用open(path,O_RDWR)時mds中的處理

當client2 向mds發送OP_OPEN後,MDS端由​

​Server::handle_client_open()​

​​來進行處理。處理過程主要是圖中的四步。

第一步加鎖是正常操作,為了防止父節點被删除。

第二步​​

​issue_new_caps()​

​​在mds端記錄client2 聲稱需要的cap,通過​

​eval()​

​​驅動鎖的狀态進行轉換,因為有新的client加入,且兩個client都需要對檔案進行寫操作,這時IFILE lock從之前的EXCL狀态向MIX轉換,在本例的情況下(client1成功打開檔案後,client2發起打開請求),EXCL到MIX的狀态無法直接在MDS端完成,因為client1在之前作為loner被授予了過多cap,這些cap要先收回,才能繼續向MIX轉換。回收cap的是異步的,是以不會阻塞後續步驟。

第三步​​

​check_inode_max_size()​

​​是為了記錄client2 對檔案可寫入的範圍,這個資料作為client range被記錄到日志中,用于故障恢複時使用。這一步需要對IFILE進行​

​wrlock​

​​,這次加寫鎖時不會有問題的,因為根據狀态機,EXCL->MIX狀态下是允許EXL角色進行​

​wrlock​

​​的,剛好client1作為loner是XCL角色,是以加鎖不會失敗。等日志落盤後鎖會被釋放,這時再根據目前狀态判斷是否發送新的cap給各個client,如果這時對client1的revoke cap還未完成,那麼不會有新的cap發送給client,因為鎖的狀态沒有改變,需要繼續等對client1 cap的收回(當然這個等待是異步的)。整個第三步也不會阻塞後續步驟。

第四步将inode資訊發回給client2。隻有inode資訊,沒有cap,cap會在其他過程中單獨發給client2(當mds完成對client1 的cap revoke時)。

讀寫檔案

檔案打開後在系統層隻是擁有了檔案句柄,在實際調用​

​read()​

​​或​

​write()​

​​前,檔案的CAP可能還并沒有完全授予給client,是以不論是​

​Client::ll_read()​

​​還是​

​Client::ll_write()​

​​都會先進行​

​get_caps()​

​​,確定已經有相應cap,如果沒有,就等待(通常情況下并不會向MDS發請求,因為沒有cap說明之前的​

​open()​

​​調用還沒有真正結束,​

​open()​

​​調用完成時需要有兩個結果:1.inode資訊被發回 2.cap被授予)。

讀寫檔案需要的cap包括:

cap 用途
CEPH_CAP_FILE_RD 讀檔案需要
CEPH_CAP_FILE_WR 寫檔案需要
CEPH_CAP_FILE_CACHE 從本client的cache中讀檔案需要
CEPH_CAP_FILE_CACHE 從本client的cache中寫檔案需要

繼續閱讀