目前XFS已成為Linux主流的檔案系統,是以有必要了解下其資料結構和原理。
XFS檔案系統
XFS是一個日志型的檔案系統,能在斷電以及作業系統崩潰的情況下保證資料的一緻性。XFS最早是針對IRIX作業系統開發的,後來移植到linux上,目前CentOS 7已将XFS作為預設的檔案系統。使用XFS已成為了潮流,是以很有必要了解下其資料結構和原理。
XFS官方說明文檔參考:https://xfs.org/docs/xfsdocs-xml-dev/XFS_Filesystem_Structure//tmp/en-US/html/index.html
接下來将介紹XFS的一些概念,包括配置設定組、超級塊、inode等等,過程中會結合xfs_db(xfs提供的輸出檔案系統資訊的工具)列印一些資訊,了解目前XFS的實時資料。
配置設定組(Allocation Group)
XFS将空間分為若幹個配置設定組,每個配置設定組大小相等(最後一個可能不等)。配置設定組包含有超級塊、inode管理和剩餘空間管理等,是以配置設定組可以認為是一個單獨的檔案系統。正是配置設定組這樣的設計,使得XFS擁有了并行IO的能力。在單個分區上使用XFS展現不了這種并行IO能力,但是如果檔案系統跨越多個實體硬體比如ceph,并行IO将大大提高吞吐量使用率。

上圖為配置設定組的結構圖,重點關注前面4個扇區,從上到下分别為超級塊、空閑塊資訊、inode資訊和内部空閑清單。
超級塊(superblock)
超級塊位于配置設定組的第一個扇區,包含了配置設定組和檔案系統的全部中繼資料資訊,由于結構體比較大,這裡就不作列舉,可去官方文檔中檢視https://xfs.org/docs/xfsdocs-xml-dev/XFS_Filesystem_Structure//tmp/en-US/html/Allocation_Groups.html
xfs_db檢視超級塊内容,執行xfs_db -r /dev/xxx(xxx為XFS所在的分區),輸入sb再輸入p即可,如下圖所示(鑒于篇幅未盡列出輸出):
超級塊有幾個核心的中繼資料為:
blocksize:塊大小,一般為4KB;
dblocks:一個配置設定組含有的塊數目;
agcount:整個檔案系統含有的配置設定組數目;
sectsize:扇區大小,一般為512B;
inodesize:inode節點大小,一般為512B;
icount:整個檔案系統目前已經配置設定的inode數目;
ifree:整個檔案系統空閑的inode數目,由于XFS不是格式化的時候預配置設定所有的inode,而是根據使用情況動态構造inode,是以該值為動态值。
空閑塊資訊(AG free block info)
位于配置設定組的第二個扇區,主要描述兩個空閑空間B+樹和剩餘空間資訊,結構體如下:
核心成員如下:
agf_roots:XFS_BTNUM_AGF為2,指明了2棵空閑空間B+樹在哪個block,通過查找這兩棵樹找到合适的空閑block;
agf_levels:樹高;
agf_freeblks:配置設定組目前空閑block數目
xfs_db輸入agf可檢視空閑塊資訊,如下圖所示:
空閑空間B+樹
空閑塊資訊包含了兩顆空閑空間B+樹,分别以block序号和block數目為關鍵字,滿足兩種不同的需求。
B+樹貫徹了整個XFS,對其有所了解才能更好的了解XFS的運作,網上有很多關于B+樹的資料,請自行查閱,這裡隻描述一些核心概念:
屬于多叉平衡排序樹;
有m個關鍵字的中間節點有m個子節點;
m個子節點的關鍵字集合包含父節點的關鍵字,B+樹有點像跳表;
中間節點隻含有關鍵字不含資料,葉子節點含有所有的關鍵字和資料;
葉子節點含有左右節點指針,所有葉子節點實際上是一條有序連結清單。
B+樹在基于磁盤查找的軟體中應用廣泛,如資料庫,檔案系統也一樣,這些軟體都要讀取磁盤資料再查找,是以一次讀取盡量多的關鍵字尤為重要,B+樹的單節點多關鍵字可滿足該需求。
接下來将通過xfs_db去探索這兩棵樹的内容,從agf的列印資訊可看到bnoroot=1和cntroot=2,它們分别是以block序号和block數目為關鍵字的B+樹的根節點所在的block序号。
跟蹤以block序号為關鍵字的B+樹操作如下:
由于agf中level為1,是以該B+樹沒有中間節點,直接就是葉子節點,包含有空閑block資料,圖中的recs數組便是,可見目前有3大塊空閑空間。
跟蹤以block數目為關鍵字的B+樹操作如下:
Inode B+樹資訊
位于配置設定組的第三個扇區,主要描述inode B+樹的根block、已構造的inode個數以及空閑個數,資料結構如下:
agi_root:inode B+樹的根block;
agi_level:樹高;
agi_count:已構造的inode數目;
agi_freecount:空閑的inode數目。
xfs_db輸入agi可讀取到Inode B+樹資訊,如下圖所示:
由上圖可知B+樹的根block為root=3,跟蹤該block便可找到具體的inode資料。
Inode資訊
每一個檔案或目錄都對應一個inode,用于描述檔案的基本資訊,除了目錄或連結,inode不攜帶檔案資料。
inode分為3部分,如下;
xfs_dinode_core_t:固定資訊,描述檔案類型、屬性、通路時間等;
data fork:存放資料位置資訊;
extended attribute fork:存放擴充資料位置資訊;
Inode Core
描述檔案的基本資訊,資料結構定義如下:
di_mode:指定檔案類型和通路權限,具體解析參考https://www.xuebuyuan.com/1106749.html
di_format:指定data fork的資料格式,有以下類型:
di_uid:擁有者id;
di_gid:擁有者的組id;
di_atime、di_mtime、di_ctime:通路時間、修改時間、修改屬性時間;
di_size:資料大小,比如檔案的大小;
di_forkoff:實際值要乘以8,是data fork和extended attribute fork的分界線,以data fork為起始,初始值為0,代表沒有extend attribute fork。
Inode number
Inode有個唯一表明身份的number,有兩種格式:相對格式(32位)和絕對格式(64位)。
從上圖可見,絕對格式比相對格式多了AG number部分,中間部分為block序号,右側部分為inode在該block内的序号,可見根據inode number便可得到inode在磁盤的具體位置。sb_agblklog和sb_inoplog的值位于超級塊中。
計算inode所在位置方法:
假設block序号為A,inode序号為B,AG number為C,每個配置設定組的block數目為D,Inode大小為E,block大小為F(這些值可以計算或通過超級塊得到)
則inode所在的block序号 x = C D + A,則inode位址為 y = x F + E * B
data fork
不同檔案類型的data fork形式有所不同,同樣類型的檔案根據大小也會有不同的資料結構,接下來将一一描述。
普通檔案
普通檔案的資料不會放在data fork中,視extent數目大小,有兩種資料形式:
Extent List:每個extent指明存放資料的block位址,周遊該list便可得到全部檔案資料;
B+tree Extent List:由于data fork的容量有限,如果extent數量太多,将采用B+樹的形式存放extent,亦即采用額外的block存放extent。
目錄
有四種形式的目錄:
Shortform目錄:目錄下檔案不多或者檔案名短,也就是data fork能容納下檔案名和檔案inode,則目錄的資料放在data fork中;
Block目錄:data fork存放不下目錄的内容,采用額外的一個block存放;
Leaf目錄:一個block存放不下目錄的内容,把索引資訊從block中抽離,索引資訊用額外一個block存放;
Node目錄:一個block存放不下索引資訊,采用多個block存放索引資訊;
B+樹目錄:data fork已經存放不下資料block extent,采用B+樹方式存放block extent。
連結
有兩種形式的連結:
Shortform連結:data fork能存放下連結的内容,内容即目标檔案的路徑;
Extent連結:采用額外的block存放連結的内容,extent存放block資訊。
結束語
以上就是XFS檔案系統的一些基本資料結構,了解了基本的資料結構使我們能更深入的了解和探索XFS系統,當系統出現問題時也可以更好地分析原因。