理解EXT4,第三部分 extent樹

轉載:http://blog.csdn.net/vah101/article/details/8487670

http://computer-forensics.sans.org/blog/2011/03/28/digital-forensics-understanding-ext4-part-3-extent-trees


在我們解讀EXT4文件系統之前,有一個很重要的概念需要講解。在第一個部分中,提到了過在一個inode中,最多隻能存4個extent結構,更進一步說,每個extent結構中只有16個bit用來保存塊號,實際上,最高位被保存了下來(最高位用來表示這個externt是“保存?預分?”還是已經初始化, 部分用於EXT4的預分配功能)。這意味着,一個extent最大隻能包含2的15次方個塊,當一個block爲4k大小的時候,128MB。

128MB看起來足夠大了,但是當你的文件大於0.5G的時候,這個文件就需要大於4個extent來保存整個block的索引。或者,當你的文件很小,但是由很多不連續的片段組成。這些情況下,就需要用大於4個extent來組織文件。

在這篇文章裏,我將展示這些情況下EXT4的細節。我將使用/var/log/message文件作爲範例。這個文件已經被反覆追加寫入了一個星期以上,並且相當的不連續。當日志文件在一個共享的目錄中,並且與其他文件同時更新,就會表現出這種狀態。


分析這個inode

使用第一部分中介紹的方法,將/var/log/message文件的inode導出,並用16進制編輯器打開。在下圖中,用藍色標出了extent的頭,紫色的是第一個extent:



仔細觀察extent的頭,以magic數0xF30A起始。下一個區域告訴我們,這是一個inode中的extent。這之後的數字4,說明inode中最多隻能有4個extent。之後,我們會發現與第一部分的例子中,有所區別的地方:“樹深度”區爲1,而不是0。最後,我們會發現generation ID一項,同樣也是0

先忽略“樹深度”這一項,只看第一個extent的結構,這個extent的頭告訴我們它正在被使用。對這個extent解碼之後,我們可以知道它從0起始,0x0012 = 18個塊的長度,這些塊的起始位置是0x000200020000 = 8590065664。但是,這個塊號肯定是錯誤的,因爲這已經超過了32TB的EXT4文件系統容量的限制了,並且這臺機器上的/var分區只有2GB大小。那這是爲什麼呢?

實際上,inode中的第一個“extent”並非標準的extent結構上面解讀extent的方法是錯誤的。當EXT4需要大於4個extent時,它會創建一個在磁盤上創建一個樹(b樹)用來保存必須的extent數據,這就是extent頭上的“樹深度”一項表達的含義。在樹最底層的葉子節點上,放置的是規則的extent結構,就像第一部分裏展示的那樣。但是在樹的中間節點上,是不同的結構,稱爲extent索引。我們已經知道,“樹深度”一項爲1,說明這裏的並不是樹的葉子。

這裏有一張不同的圖片,其中extent索引被標記爲綠色:



這裏是偏移和他們對應的區域功能描述:

Bytes 52-55: Logical block number (0x0000)  邏輯塊
      56-59: Lower 32 bits of physical block address (0x00020012)   低32位的邏輯塊地址
      60-61: Upper 16 bits of physical block address (0x0000)   高16邏輯塊地址
      62-63: Not used

實質上,extent頭包含了兩個值。第一個部分是,這個extent在tree中的位置(個人理解,即以塊號爲單位,該extent在樹起始位置的偏移)——這是extent索引結構的前4個。在這個例子中,這個extent位於字數的0塊,即意味着處於文件的開始位置。

extent索引中的剩餘值是擁有下一層樹信息的數據塊的物理塊號。就像EXT4中的塊地址,這個48位的值被拆成兩部分:32位的低位和16位的高位。這樣,0x000000020012 = 131090,這是一個正常的塊偏移。

還有16位的值在extent索引中沒有被使用。你可能期望它們是0,但是在這裏我們看到它被設置爲0x0002。實際上,即使inode中的extent頭結構聲明,只有使用了第一個extent索引,你也會發現另外一個extent結構域在64~69bit處,也是非0。具體原因將會稍後一點給出,這裏先看一下131090這個塊。


解讀數據塊

每個用來保存extent樹信息的數據塊的起始位置都它自身的extent頭結構,就像inode內部的extent一樣。這裏,16進制編輯器顯示了第131090塊的前256,其中extent頭域被標成了高亮:



我們可以看到象徵extent的magic數0xF30A,如果我們觀察“樹深度”域,就會發現值爲0說明我們已經在樹的結構中下移了一層,這裏我們看到的是規則的extent,而不是extent索引。

第2~3位告訴我們,實際上這個文件包括6個extent。但是檢查第4~5位的“最大extent數量”域,其值爲0x0154 = 340!這是因爲我們用了一整個4k的數據塊來保存extent信息。位於數據塊起始部分的extent頭消耗了12位,但是仍然有4084位可以用了保存extent結構。結果就是340個12位的extent結構一共佔用了4080位的數據。

這看起來很不容易發生,對一個文件進行不常規的操作,導致它不連續,所以需要大於340個extent來對其進行描述。並且,每個extent最大能表示128MB的數據,340個extent會使你的表示的文件達到42.5GB。如果文件比這個還要大,我們就需要增大extent樹。

但是現在,讓我們對這個extent進行解讀。在下圖中,我們標記出6個extent:


通過上圖可以解讀出如下結果:
  1. 邏輯塊號: 0, 塊數量: 1, 起始塊號: 147979
  2. 邏輯塊號: 1, 塊數量: 1, 起始塊號: 148517
  3. 邏輯塊號: 2, 塊數量: 1, 起始塊號: 147476
  4. 邏輯塊號: 3, 塊數量: 1, 起始塊號: 147481
  5. 邏輯塊號: 4, 塊數量: 124, 起始塊號: 132119
  6. 邏輯塊號: 128, 塊數量: 124, 起始塊號: 132608
檢查一下實際文件的情況:
# blkcat /dev/mapper/RD-var 147979 >ext1-blks
# blkcat /dev/mapper/RD-var 148517 >ext2-blks
# blkcat /dev/mapper/RD-var 147476 >ext3-blks
# blkcat /dev/mapper/RD-var 147481 >ext4-blks
# blkcat /dev/mapper/RD-var 132119 124 >ext5-blks
# blkcat /dev/mapper/RD-var 132608 124 >ext6-blks
# cat ext* | tr -d 0 >newmess
# md5sum newmess /var/log/messages
8e8c9445d8ff3e17a22ef5a3034422a9  newmess
8e8c9445d8ff3e17a22ef5a3034422a9  /var/log/messages

首先,使用blkcat將解讀出的塊導出.最後一個extent將會有一定數量的空字符,這是因爲文件不一定佔用整個塊所以使用tr命令去掉文件最後的空字符。md5sum校驗以後,顯示通過dump將extent手動拷貝出來創建的文件,跟/var/log/message下的文件相符合。


最後

在前面,我指出了在inode中那個沒有使用的extent結構看起來表示了某些數據。如果你仔細觀察會發現,在inode中第64~99比特位處,保存了第2~4個extent的信息,跟第131090中的第2~4個extent相同。

我也指出了,在inode結構中extent索引結構的高2位,通常是不用的,但是看起來有一些其中有一些數據。如果你對比一下,就會發現在extent樹的索引中的最後兩個字節(原文是bytes,但是我覺得有可能是bits)“02 00”,與131090塊中的第一個extent結構體中的最後兩個字節一致。

那其中有何奧祕?看起來ext4的程序有些懶惰。/var/log/messages這個文件不斷地變大,並且別分成多個段落進行保存所以文件系統會不斷的在inode中增加extent結構。當需要使用第15個extent時,在extent頭中的“樹的深度”值就會被改寫,inode中的第一個extent也會被extent樹的索引結構取代。然而,ext4程序沒有同時將inode中沒有用到的extent樹填0清除掉。實際上,它也沒有將extent樹的index同步清空。但願這樣做可以提高性能,但是看上去確實比較詭異。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章