1. 程式人生 > >Ext4檔案系統架構分析(一)

Ext4檔案系統架構分析(一)

  • 本文描述Ext4 檔案系統磁碟佈局和元資料的一些分析,同樣適用於ext2,ext3檔案系統,除了它們不支援的ext4的特性。整個分析分兩篇博文,分別概述佈局和詳細介紹各個佈局的資料結構及組織定址方式等。

1.Ext4 檔案系統佈局綜述

一個Ext4 檔案系統被分成一系列塊組。為減少磁碟碎片產生效能瓶頸,塊分配器儘量保持每個檔案的資料塊都在同一個塊組中,從而減少尋道時間。以4KB的資料塊為例,一個塊組可以包含32768個數據塊,也就是128MB。

在這裡插入圖片描述

1.1 磁碟佈局

Ext4 檔案系統的標準磁碟佈局如下:
在這裡插入圖片描述

  • Ext4檔案系統主要使用塊組0中的超級塊和塊組描述符表,在其他一些特定的塊組中有超級塊和塊組描述符表的冗餘備份。如果塊組中不含冗餘備份,那麼塊組就以資料塊點陣圖開始。當格式化磁碟成為ext4 檔案系統的時候,mkfs 將在塊組描述符表後面分配預留GDT表資料塊(“Reverse GDT blocks”)以用來將來擴充套件檔案系統。緊接在預留GDT表資料塊後的是資料塊點陣圖與inode表點陣圖,這兩個點陣圖分別表示本塊組內的資料塊與inode表的使用,inode表資料塊之後就是儲存檔案的資料塊了。在這些各種各樣的塊中超級塊,GDT,塊點陣圖、inode點陣圖都是整個檔案系統的元資料,當然inode表也是檔案系統的元資料,但是inode表是與檔案一一對應的,我更傾向於將inode當做檔案的元資料,因為在實際格式化檔案系統的時候,除了已經使用的十來個外,其他的inode表中實際上是沒有任何資料的,指導建立了相應的檔案才會分配inode表,檔案系統才會在inode表中寫入與檔案相關的inode資訊。

1.2 Flexible 塊組(flex_bg)

  • Flexible 塊組(flex_bg)是從Ext4開始引入的新特性。在一個flex_bg中,幾個塊組在一起組成一個邏輯塊組flex_bg. Flex_bg的第一個塊組中的點陣圖空間和inode表空間擴大為包含了flex_bg中其他塊組上點陣圖和inode表。

  • 比如flex_bg包含4個塊組,塊組0將按序包含超級塊、塊組描述符表、塊組0-3的資料塊點陣圖、塊組0-3的inode點陣圖、塊組0-3的inode表,塊組0中的其他空間用於儲存檔案資料。同時,其他塊組上的資料塊點陣圖、inode點陣圖、inode表元資料就不存在了,但是SB和GDT還是存在的。
    在這裡插入圖片描述

Flexible塊組的作用是:

  1. 聚集元資料,加速元資料載入;
  2. 使得大檔案在磁碟上儘量連續;
  • 即使開啟flex_bg特性,超級塊和塊組描述符的冗餘備份仍然位於塊組的開頭。 Flex_bg中塊組的個數由2^ext4_super_block.s_log_groups_per_flex 給出。

1.3 元塊組(Meta Block Groups)

通常,在每個冗餘備份的超級塊的後面是一個完整的(包含所有塊組描述符的)塊組描述符表的備份。這樣會產生一個限制,以Ext4的塊組描述符大小64 Bytes計算,檔案系統中最多隻能有2^21個塊組,也就是檔案系統最大為256TB。

  • 使用元塊組Meta Block Groups特性,每個塊組都包含該塊組自己的描述符的冗餘備份。因此可以建立233個塊組,也就是檔案系統最大1EB。48位資料塊,每個塊組128MB,因而可以建立233個塊組。

  • 元塊組實際上是可以用一個塊組描述符塊來進行描述的塊組集,簡單的說,它由一系列塊組組成,同時這些塊組對應的塊組描述符儲存在一個塊中。它的出現使得Ext3和Ext4的磁碟佈局有了一定的變化,以往超級塊後緊跟的是變長的GDT塊,現在是超級塊依然決定於是否是3,5,7的冪,而一個塊組描述符塊則儲存在元塊組的第一個,第二個和最後一個塊組的開始處(見下圖)
    在這裡插入圖片描述

  • 在兩種情況下我們可能會使用到這種新佈局:

  1. 檔案系統建立時,使用者可以指定使用這種佈局。
  2. 當檔案系統增長而且預留的組描述符塊耗盡時。目前超級塊中有一個域s_first_meta_bg用於描述第一個使用元塊組的塊組。當增加新塊組時,我們不需要給組描述符表預留空間,而是在當前檔案系統後面直接新增新的元塊組就可以了。

1.4 Lazy塊組初始化

如果塊組中的相應標誌已設定,那麼塊組中的inode點陣圖和inode表將不被初始化。這樣可以減少mkfs時間,如果開啟了塊組描述符校驗和功能,甚至連塊組都可以不初始化。

1.5特殊inodes

Ext4預留了一些inode做特殊特性使用,見下表:

表 1 Ext4的特殊inode

Inode號 用途

0 不存在0號inode

1 損壞資料塊連結串列

2 根目錄

3 ACL索引

4 ACL資料

5 Boot loader

6 未刪除的目錄

7 預留的塊組描述符inode

8 日誌inode

11 第一個非預留的inode,通常是lost+found目錄

1.6 資料塊和Inode分配策略

在機械磁碟上,保持相關的資料塊相互接近可以總的磁頭移動時間,因而可以加速磁碟IO。在SSD上雖然沒有磁頭轉動,資料區域性性可以增加每次IO請求的傳輸的資料大小,因而減少響應IO請求的傳輸次數。資料的區域性性對單個擦除塊的寫入產生影響,可以加速檔案重寫的速度。因而儘可能減少碎片是必要的。inode和資料塊的分配策略可以保證資料的區域性集中。以下為inode和資料塊的分配策略:

(1) 多塊分配可以減少磁碟碎片。當檔案初次建立的時候,塊分配器預測性地分配8KB的磁碟空間給檔案。當檔案關閉的時候,未使用的空間當然也就釋放了。但是如果推測是正確的,那麼檔案資料將寫到一個多個塊的extent中。

(2) 延遲分配。當一個檔案需要更多的資料塊引起寫操作時,檔案系統推遲決定新資料在磁碟上的存放位置,直到髒的buffer寫到磁碟為止。

(3) 儘量保持檔案的資料塊與其inode在同一個塊組中。可以減少磁碟尋道時間.

(4) 儘量保持同一個目錄中的所有inodes與目錄位於同一個塊組中。這樣的假設前提是一個目錄中的檔案是相關的。

(5) 磁碟卷被分成128MB的塊組。當在根目錄中建立目錄時,inode分配器掃描塊組並將新目錄放到它找到的使用負荷最小的塊組中。這可以保證目錄在磁碟上的分散性。

(6) 即使上述機制無效,仍然可以使用e4defrag整理碎片檔案。

1.7 超級塊

  • 超級塊記錄整個檔案系統的大量資訊,如資料塊個數、inode個數、支援的特性、管理資訊,等待。

  • 如果設定sparse_super特性標誌,超級塊和塊組描述符表的冗餘備份僅存放在編號為0或3、5、7的冪次方的塊組中。如果未設定sparse_super特性標誌,冗餘備份存在與所有的塊組中。以下是2.6.32.18核心中對Ext4超級塊的描述:
    在這裡插入圖片描述
    在這裡插入圖片描述
    在這裡插入圖片描述

3.0的核心中,Ext4的超級塊加入了以下相關元資料:快照、檔案系統錯誤處理相關、掛載選項、配額檔案inode、超級塊校驗和等,見下圖。目前沒有深入研究這些新的元資料。
在這裡插入圖片描述

1.8塊組描述符

一個塊組中,具有固定位置的資料結構是超級塊和塊組描述符。其他資料結構位置都可以不固定。Flex_bg機制使用這個性質將幾個塊組聚合成一個flex塊組,將flex_bg中所有點陣圖和inode 表放到flex_bg的第一個塊組中。詳細情況可以參考我的上一篇Ext4分析博文的Flexible 塊組(flex_bg)部分。
在這裡插入圖片描述

  • 如果設定了meta_bg特性標誌,幾個塊組結合成一個meta group。在meta_bg的情況下,在meta group中的第一個和最後兩個塊組中僅包含meta group中的塊組的塊組描述符。Flex_bg和Meta_bg互斥因而不能共同出現。

1.9 資料塊點陣圖與inode 點陣圖

  • 資料塊點陣圖跟蹤塊組中資料塊使用情況。Inode點陣圖跟蹤塊組中Inode使用情況。每個點陣圖一個數據塊,每一位用0或1表示一個塊組中資料塊或inode表中inode的使用情況。如果一個數據塊大小是4KB的話,那一個位圖塊可以表示410248個數據塊的使用情況,這也是單個塊組具有的最大資料塊個數。這樣可以算出一個塊組大小是128MB。當然一個位圖塊也可以表示410248個inode的使用情況,但是實際上一個塊組中即使存滿了檔案,也不會用到這麼多的inode,因為實際系統中基本不會出現所有檔案大小都小於等於1個數據塊大小的情況。實際上一個塊組中有多少個inode,在塊組描述符中是確定的,在檔案系統格式化過程中也會看到這個數值,如果沒記錯的話,大概是每4個還是8個數據塊分配一個inode空間。

1.10 Inode 表

  • 為了找到與一個檔案相關的資訊,必須遍歷目錄檔案找到與檔案相關的目錄項,然後載入inode找到該檔案的元資料。Ext4在目錄項中用一位儲存了檔案型別(通常儲存在inode中)的拷貝,這對效能提升有益。Inode表的大小為ext4_super_block.s_inode_size * ext4_super_block.s_inodes_per_group Bytes。
    在這裡插入圖片描述
    在這裡插入圖片描述
    Ext4的inode的資料結構大小為156 bytes,但是Ext4的標準inode的大小是256 bytes。

1.11 查詢inode

每個塊組包含ext4_super_block.s_inodes_per_group個inodes。因為0號inode不存在,可以通過如下的算式計算inode所在的塊組:

bg=(inode_num -1)/ ext4_super_block.s_inodes_per_group

inode在塊組中inode表中的索引index可以通過如下的算式計算:

index=(inode_num -1) % ext4_super_block.s_inodes_per_group

inode在inode表中的地址偏移為:

offset=index * ext4_super_block.s_inode _size

1.12 inode.i_block0[]s的內容

  • 取決於檔案型別,inode.i_blocks[]使用的方式不同。一般來說,常規檔案和目錄用inode.i_blocks[]作為檔案資料塊索引資訊,特殊檔案將inode.i_blocks[]用於特殊用途。常規檔案用inode.i_blocks[]作為檔案資料塊索引資訊的三級索引結構會在後面直接、間接塊地址中詳細介紹。

1.13 符號連結

  • 如果符號連結的目標字串長度小於60位元組,那麼就將其儲存在inode.i_blocks[]中,inode中inode.i_blocks[]佔據的大小剛好是60KB。這裡要注意到的是,有些檔案其內容是跟檔案的元資料放在一起的,因而就沒有了資料塊。也就是說不是每個檔案資料都必然佔據著一個數據塊。

1.14 直接/間接塊地址

Ext2/Ext3中資料塊對映方式如下表
在這裡插入圖片描述
在這裡插入圖片描述

1.15 Extent 樹

  • Ext4中用extent樹代替了邏輯塊對映。使用extents,用一個struct ext4_extent結構就可以對映多個數據塊,減少元資料塊的使用。如果設定了flex_bg,甚至可以用一個extent分配一個非常大的檔案。使用extent特性,inode必須設定extents flag。

  • Extents以樹的方式安排。Extent樹的每個節點都以一個ext4_extent_header開頭,如果節點是內部節點(ext4_extent_header.eh_depth>0),ext4_extent_header後面緊跟的是ext4_extent_header .eh_entries個索引項struct ext4_extent_idx,每個索引項指向該extent樹中一個包含更多的節點的資料塊。如果節點是葉子節點(ext4_extent_header.eh_depth==0),ext4_extent_header後面緊跟的是ext4_extent_header .eh_entries個struct ext4_extent資料結構。這些ext4_extent結構指向檔案資料塊。Extent樹的根結點儲存在inode.i_blocks中,可以儲存檔案的前4個extents而不需額外的元資料塊。

  • 在這裡插入圖片描述

  • 在這裡插入圖片描述

  • 在這裡插入圖片描述

1.16 Extent樹資料塊校驗和:可能加入的新元資料

由於extent樹的根在inode中,因而Extent樹資料塊指extent樹的除根據節點外的所有內部節點和葉子節點。Extent的樹根節點和葉子節點的資料塊中儲存完xt4_extent_idx和xt4_extent資料結構後至少會留下4 ((2^x%12)>=4) bytes的空間。因而可以加入一個結構struct ext4_extent_tail,其中儲存32位的校驗和。位於inode中的4個extents無需校驗和,因為inode已經做了校驗和。

1.17 目錄項

  • Ext4檔案系統中,一個目錄差不多是一個平面檔案,對映任意長度的字串到檔案系統中的一個inode。檔案系統中存在多個目錄項引用同一個inode——硬連結,這也是硬連結不能連結其他檔案系統中的檔案的原因。

1.18 線性(經典)目錄

預設地,目錄檔案中包含一個線性的目錄項陣列。未使用的目錄項標記為inode =0。Ext4檔案系統預設地使用struct ext4_dir_entry_2記錄目錄項,除非沒有設定filetype特性標誌。在沒有設定filetype特性標誌的情況下,使用struct ext4_dir_entry記錄目錄項。
在這裡插入圖片描述

1.19 雜湊樹目錄

  • 線性目錄項不利於系統性能提升。因而從ext3開始加入了快速平衡樹雜湊目錄項名稱。如果在inode中設定EXT4_INDEX_FL標誌,目錄使用雜湊的B樹(hashed btree ,htree)組織和查詢目錄項。為了向後只讀相容Ext2,htree實際上隱藏在目錄檔案中。

  • Ext2的慣例,樹的根總是在目錄檔案的第一個資料塊中。“.”和“…”目錄項必須出現在第一個資料塊的開頭。因而這兩個目錄項在資料塊的開頭存放兩個struct ext4_dir_entry_2結構,且它們不存到樹中。根結點的其他部分包含樹的元資料,最後一個hash->block map查詢到htree中更低的節點。如果dx_root.info.indirect_levels不為0,那麼htree有兩層;htree根結點的map指向的資料塊是一個內部節點,由一個minor hash索引。Htree中的內部節點的minor_hash->block map之後包含一個零化的(zeroed out) structext4_dir_entry_2找到葉子節點。葉子節點包括一個線性的struct ext4_dir_entry_2陣列;所有這些項都雜湊到相同的值。如果發生溢位,目錄項簡單地溢位到下一個葉子節點,雜湊的least-significant位(內部節點的map)做相應設定。

  • 以htree的方式遍歷目錄,計算要查詢的目錄檔名稱的雜湊值,然後使用雜湊值找到對應的資料塊號。如果樹是flat,該資料塊是目錄項的線性陣列,因而可被搜尋到;否則,計算檔名稱的minor hash,並使用minor hash查詢相應的第三個資料塊號。第三個資料塊是目錄項線性陣列。
    在這裡插入圖片描述
    在這裡插入圖片描述

1.20 擴充套件屬性EA

  • 擴充套件屬性(xattrs)通常儲存在磁碟上的一個單獨的資料塊中,通過inode.i_file_acl*引用。擴充套件屬性的第一應用是儲存檔案的ACL以及其他安全資料(selinux)。使用user_xattr掛載選項就可為使用者儲存以“user”開頭的所有擴充套件屬性。這樣的限制在3.0核心中已經消失。

  • 可以在兩個地方找到擴充套件屬性:一是在一個inode項結尾到下一個inode項開頭的地方;二是inode.i_file_acl指向 的資料塊之中,到3.0為止,這個資料塊中不包含指向第二個擴充套件屬性資料塊的指標。理論上可以將每個屬性值儲存到一個單獨的資料塊中,但是3.0核心為止仍然沒有這樣做。

  • 當擴充套件屬性不儲存在一個inode之後的時候,就會有一個頭部ext4_xattr_ibody_header
    在這裡插入圖片描述

擴充套件屬性值可以緊跟在ext4_xattr_entry項表後面。考慮4 bytes對齊。擴充套件屬性值從擴充套件屬性資料塊的末尾開始向ext4_xattr _header / ext4_xattr_entry表的方向增長。當發生溢位時,溢位的部分放到一個單獨的磁碟資料塊上。