1. 程式人生 > >(十三)linux檔案系統詳解(基於ext2檔案系統)

(十三)linux檔案系統詳解(基於ext2檔案系統)


  我們知道,一個磁碟可以劃分成多個分割槽,每個分割槽必須先用格式化工具(例如某種mkfs命令)格式化成某種格式的檔案系統,然後才能儲存檔案,格式化的過程會在磁碟上寫一些管理儲存佈局的資訊。下圖是一個磁碟分割槽格式化成ext2檔案系統後的儲存佈局
ext2檔案系統儲存佈局


  檔案系統中儲存的最小單位是塊(Block),一個塊究竟多大是在格式化時確定的,例如mke2fs的-b選項可以設定塊大小為1024、2048或4096位元組。而上圖中啟動塊(BootBlock)的大小是確定的,就是1KB,啟動塊是由PC標準規定的,用來儲存磁碟分割槽資訊和啟動資訊,任何檔案系統都不能使用啟動塊。啟動塊之後才是ext2檔案系統的開始,ext2檔案系統將整個分區劃成若干個同樣大小的塊組(Block Group),每個塊組都由以下部分組成:

  • 超級塊(Super Block) 描述整個分割槽的檔案系統資訊,例如塊大小、檔案系統版本號、上次mount的時間等等。超級塊在每個塊組的開頭都有一份拷貝。

  • 塊組描述符表(GDT,Group Descriptor Table) 由很多塊組描述符組成整個分割槽分成多少個塊組就對應有多少個塊組描述符。每個塊組描述符(Group Descriptor)儲存一個塊組的描述資訊例如在這個塊組中從哪裡開始是inode表,從哪裡開始是資料塊,空閒的inode和資料塊還有多少個等等。和超級塊類似,塊組描述符表在每個塊組的開頭也都有一份拷貝,這些資訊是非常重要的,一旦超級塊意外損壞就會丟失整個分割槽的資料,一旦塊組描述符意外損壞就會丟失整個塊組的資料,因此它們都有多份拷貝。通常核心只用到第0個塊組中的拷貝,當執行e2fsck檢查檔案系統一致性時,第0個塊組中的超級塊和塊組描述符表就會拷貝到其它塊組,這樣當第0個塊組的開頭意外損壞時就可以用其它拷貝來恢復,從而減少損失。

  • 塊點陣圖(Block Bitmap) 一個塊組中的塊是這樣利用的:資料塊儲存所有檔案的資料,比如某個分割槽的塊大小是1024位元組,某個檔案是2049位元組,那麼就需要三個資料塊來存,即使第三個塊只存了一個位元組也需要佔用一個整塊;超級塊、塊組描述符表、塊點陣圖、inode點陣圖、inode表這幾部分儲存該塊組的描述資訊。那麼如何知道哪些塊已經用來儲存檔案資料或其它描述資訊,哪些塊仍然空閒可用呢?塊點陣圖就是用來描述整個塊組中哪些塊已用哪些塊空閒的,它本身佔一個塊,其中的每個bit代表本塊組中的一個塊,這個bit為1表示該塊已用,這個bit為0表示該塊空閒可用。

  • 注1:
    為什麼用df命令統計整個磁碟的已用空間非常快呢?因為只需要檢視每個塊組的塊點陣圖即可,而不需要搜遍整個分割槽。相反,用du命令檢視一個較大目錄的已用空間就非常慢,因為不可避免地要搜遍整個目錄的所有檔案。

  • 注2:
    與此相聯絡的另一個問題是:在格式化一個分割槽時究竟會劃出多少個塊組呢?主要的限制在於塊點陣圖本身必須只佔一個塊。用mke2fs格式化時預設塊大小是1024位元組,可以用-b引數指定塊大小,現在設塊大小指定為b位元組,那麼一個塊可以有8b個bit,這樣大小的一個塊點陣圖就可以表示8b個塊的佔用情況,因此一個塊組最多可以有8b個塊,如果整個分割槽有s個塊,那麼就可以有s/(8b)個塊組。格式化時可以用-g引數指定一個塊組有多少個塊,但是通常不需要手動指定,mke2fs工具會計算出最優的數值。

  • inode點陣圖(inode Bitmap) 和塊點陣圖類似,本身佔一個塊,其中每個bit表示一個inode**是否空閒可用**。

  • inode表(inode Table) 我們知道,一個檔案除了資料需要儲存之外,一些描述資訊也需要儲存,例如檔案型別(常規、目錄、符號連結等),許可權,檔案大小,建立/修改/訪問時間等,也就是ls -l命令看到的那些資訊,這些資訊存在inode中而不是資料塊中。每個檔案都有一個inode,一個塊組中的所有inode組成了inode表。

  • 注3:inode表佔多少個塊在格式化時就要決定並寫入塊組描述符中,mke2fs格式化工具的預設策略是一個塊組有多少個8KB就分配多少個inode。由於資料塊佔了整個塊組的絕大部分,也可以近似認為資料塊有多少個8KB就分配多少個inode,換句話說,如果平均每個檔案的大小是8KB,當分割槽存滿的時候inode表會得到比較充分的利用,資料塊也不浪費。如果這個分割槽存的都是很大的檔案(比如電影),則資料塊用完的時候inode會有一些浪費,如果這個分割槽存的都是很小的檔案(比如原始碼),則有可能資料塊還沒用完inode就已經用完了,資料塊可能有很大的浪費。如果使用者在格式化時能夠對這個分割槽以後要儲存的檔案大小做一個預測,也可以用mke2fs的-i引數手動指定每多少個位元組分配一個inode。

  • 資料塊(Data Block) 根據不同的檔案型別有以下幾種情況:
    1)對於常規檔案,檔案的資料儲存在資料塊中。
    2)對於目錄,該目錄下的所有檔名和目錄名儲存在資料塊中,注意檔名儲存在它所在目錄的資料塊中,除檔名之外,ls -l命令看到的其它資訊都儲存在該檔案的inode中。注意這個概念:目錄也是一種檔案,是一種特殊型別的檔案。
    3)對於符號連結,如果目標路徑名較短則直接儲存在inode中以便更快地查詢,如果目標路徑名較長則分配一個數據塊來儲存。
    4)裝置檔案、FIFO和socket等特殊檔案沒有資料塊,裝置檔案的主裝置號和次裝置號儲存在inode中。

注*:目錄中記錄項檔案型別

編碼   檔案型別
0     Unknown
1     Regular file
2     Directory
3     Character device
4     Block device
5     Named pipe
6     Socket
7     Symbolic link

這裡寫圖片描述

注**:資料塊定址
這裡寫圖片描述

  從上圖可以看出,索引項Blocks[13]指向兩級的間接定址塊,最多可表示(b/4)2+b/4+12個數據塊,對於1K的塊大小最大可表示64.26MB的檔案。索引項Blocks[14]指向三級的間接定址塊,最多可表示(b/4)3+(b/4)2+b/4+12個數據塊,對於1K的塊大小最大可表示16.06GB的檔案。
  可見,這種定址方式對於訪問不超過12個數據塊的小檔案是非常快的,訪問檔案中的任意資料只需要兩次讀盤操作,一次讀inode(也就是讀索引項)一次讀資料塊。而訪問大檔案中的資料則需要最多五次讀盤操作:inode、一級間接定址塊、二級間接定址塊、三級間接定址塊、資料塊。實際上,磁碟中的inode和資料塊往往已經被核心快取了,讀大檔案的效率也不會太低。

總結圖:(請下載後檢視,或放大)
這裡寫圖片描述