引言:學習經典永不過期。html
咱們以前介紹過存儲介質主要是磁盤,先介紹過物理的,後又介紹了虛擬的。保存在磁盤上的信息通常採用文件(file)爲單位,磁盤上的文件必須是持久的,同時文件是經過操做系統管理的,其中包括文件的結構、文件的名稱、文件的使用、文件的保護、文件的實現等等,因此在一個操做系統中,負責處理與文件相關的各類事情的部分,叫作文件系統(File System)。node
如上所述,文件系統就是一種抽象。文件系統對於用戶而言,關心的是文件的訪問和操做;而對設計者或者相關開發者而言,更關心的是如何實現與之相關的內部結構和功能模塊,例如文件系統的佈局、空閒塊的管理、數據塊的大小、文件內容如何分配和查找等等。本文主要從開發者或者設計者角度出發,以linux經典的文件系統EXT2爲例介紹文件系統是如何組織以及實現的。linux
Linux下每一個分區上(LVM中對應邏輯卷LV)的文件系統是相互獨立的, 也就是說每一個分區都有本身的文件系統,mkfs格式化的時候能夠設置,每一個分區的文件系統能夠不一樣,固然也能夠相同。因此一個分區就表明了一個文件系統。下圖的第二層和第三層對應了一個文件系統EXT2的的分佈圖。工具
咱們首先介紹上圖中的第一層,這層表示計算機系統的整個磁盤空間,被劃分出了若干個分區。磁盤的扇區0(LBA0)稱爲主引導記錄(Master Boot Record,MBR),簡稱爲主引導,它主要用來啓動計算機。在MBR的末尾有一個分區表,裏面記錄了每個分區的起始地址和結束地址。MBR長度固定,即一個扇區的長度512B,而分區表的長度是64B,因此主引導程序長度就是446B。每一個分區信息的長度固定16B,因此MBR分區表只能保存4個分區,也被稱爲主分區,若是須要描述更多的分區,則須要將其中一個分區做爲擴展分區,指向更多的邏輯分區組成的鏈表。因此通常一個多(N)分區系統實際顯示的是三個主分區和N-3個邏輯分區。如今不少計算機系統採用新的分區方式GPT,沒有主分區個數的限制,並且分區容量也沒有2TB的限制。佈局
MBR程序所作的第一件事情是肯定活動分區,並讀入它的第一個磁盤塊,稱爲引導塊(Boot Block),而後裝入內存並執行它。引導塊是操做系統的引導程序和文件。每一個分區都保留了引導塊,無論這個分區是否已經安裝了操做系統。若是引導程序太長,一個塊放不下,也能夠指向其餘塊。在MBR分區的方式下,啓動的分區必須是主分區,不能是邏輯分區,邏輯分區只能是被管理。學習
一個EXT2文件系統,除了引導塊,其餘由多個塊組(Block Group)組成,如上圖第二層所示。ui
每個塊組的內部結構是同樣的,內容不一樣,如圖中第三層。這一層就是本文的重點介紹對象。spa
首先咱們介紹幾個基礎概念,而後再對上圖中第三層的結構進行分解。操作系統
邏輯塊((block)設計
block是在分區進行文件系統的格式化時所指定的"最小存儲單位",這個最小存儲單位以扇區的大小爲基礎,大小爲扇區的 2ⁿ 倍。此時,磁頭一次能夠讀取一個邏輯塊。指定邏輯塊的大小爲 4KB(即由連續的 8 個扇區構成的一個塊),那麼,一樣讀取一個 10M 的文件,磁頭要讀取的次數則大幅降低爲 2560 次,這樣就大大提升了文件的讀取效率。須要注意的是,邏輯塊也並非越大越好。由於一個邏輯塊最多僅能容納一個文件(這裏指 Linux 的 ext2 文件系統)。這有什麼問題呢?舉例來講,假如邏輯塊的大小爲 4KB,有一個文件大小爲 0.1KB,這個小文件將佔用掉一個塊的空間。也就是說,該塊雖然能夠容納 4KB 的容量,然而因爲文件只佔用了 0.1KB,實際上剩下的 3.9KB 空間就不能再被使用了(徹底浪費掉了)。因此好的方式是根據實際的使用場景來設置邏輯塊的大小。
inode
Linux 操做系統的文件數據除了文件實際內容外,一般含有很是多的屬性,例如文件權限(rwx)與文件屬性(擁有者、羣組、時間參數等)。文件系統一般會將這兩部份的數據分別存放在不一樣的區塊,權限與屬性放置到 inode 中,至於實際數據則放置到 Data Block 區塊中。inode的大小和block大小不一樣,tune2fs 能夠進行查看,以下所示。
[root@localhost lib]# tune2fs -l /dev/sda
tune2fs 1.42.9 (28-Dec-2013)
...........
Filesystem OS type: Linux
Inode count: 274661376
Block count: 2197291008
Reserved block count: 109864550
Free blocks: 842263996
Free inodes: 274643493
First block: 0
Block size: 4096
Fragment size: 4096
Group descriptor size: 64
Reserved GDT blocks: 1000
...........
First inode: 11
Inode size: 256
Required extra isize: 28
Desired extra isize: 28
Journal inode: 8
Default directory hash: half_md4
Directory Hash Seed: 24d40b7a-1dca-40ee-bd4f-e52b65070d01
Journal backup: inode blocks
[root@localhost lib]#
block與inode的關係
實際記錄文件的內容,若文件太大時,會佔用多個 block。
每一個文件都會佔用一個 inode,inode 內則有文件數據放置的 block 號碼。下面是 inode、block 數據存取的示意圖(此圖來自互聯網):
這種數據存取的方法咱們稱爲索引式文件系統(indexed allocation)。
接下來咱們再介紹文件系統EXT2的組織結構。
每一個文件系統開始位置的那個塊就稱爲超級塊。超級塊會記錄整個文件系統的總體信息,包括 inode 與 block 的總量、使用量、剩餘量等。
也就是說,要使用一個分區(或文件系統)來進行數據訪問時,第一個要通過的就是超級塊。
其實上除了第一個 block group 內會含有 super block 以外,後續的 block group 通常都包含了 super block,即作爲第一個 block group 內 super block 的備份。
因此,若是第一個超級塊損壞了,則能夠從後面的超級塊複製過來。
super block 記錄整個 filesystem 相關信息,主要信息有:
super block 的大小爲 1024 Bytes,它很是重要,由於分區上重要的信息都在上面。若是全部保存的 super block 掛掉了,分區上的數據就很難恢復了。
Group Description 用來描述每一個 group 的開始與結束位置的 block 號碼,以及說明每一個塊(super block、bitmap、inode bitmap、data block) 分別介於哪個 block 號碼之間。
組描述符信息和超級塊信息同樣,複製到其餘組塊的開頭。可是隻有組塊1中所包含的超級塊和組描述符才由內核使用。實際中,系統啓動時,修復工具e2fsck程序會對文件系統進行一致性檢查,當發現組塊1的超級塊和組描述符無效時,系統管理員能夠用e2fsck命令從後面的組塊中的這兩部分信息拷貝過來。
dumpe2fs命令顯示device中文件系統的超級塊和塊組信息,若是添加選項 -h,則只輸出 super block 中的信息。
在建立文件時須要爲文件分配 block,文件系統須要選擇空閒的 block ,如何查看 block 是否已經被使用了呢?藉助於 block bitmap。經過 block bitmap 能夠知道哪些 block 是空的,所以系統就可以很快地找到空閒空間來分配給文件。一樣的,在刪除某些文件時,文件本來佔用的 block 號碼就要釋放出來,此時在 block bitmap 當中相對應到該 block 號碼的標誌就須要修改爲"空閒"。這就是 block bitmap 的做用。
inode bitmap 與 block bitmap 的功能相似,只是 block bitmap 記錄的是使用與未使用的 block 號,而 inode bitmap 則記錄的是使用與未使用的 inode 號。
Inode table 中存放着一個個 inode,inode 的內容記錄文件的屬性以及該文件實際數據放置在哪些 block 內,inode 記錄的主要的文件屬性以下:
inode 的數量與大小也是在格式化時就已經固定了的,另外 inode 還有以下特色:
Data Block 是用來存放文件內容的地方,ext2 文件系統有 1K、2K 和 4K 大小的 block。在格式化文件系統時 block 的大小就肯定了,而且每一個 block 都有編號。須要注意的是,因爲 block 大小的差別,會致使文件系統可以支持的最大磁盤容量和最大單個文件的大小並不相同。下表描述了 block 大小與文件系統以及單個文件大小的關係:
此外 Ext2 文件系統的 block 還有下面一些限制:
上述對ext2的結構組成基本介紹完成,再補充幾個細節。
這取決於分區的大小和塊的大小。其主要限制在塊位圖,由於塊位圖必須存放在一個單獨的塊中(inode bitmap同樣),塊位圖用來標識一個組中塊的佔用和空閒情況。因此每組中至多有8*b個塊,b是以字節爲單位的塊大小。所以,塊組的總數大約是s/(8*b),這裏s是分區所包含的總塊數。
舉例說明,讓咱們考慮一個32GB的ext2分區,塊的大小爲4KB。在這種狀況下,每一個4KB的塊位圖描述32K個數據塊,即128MB。所以,最多須要256個塊組。顯然,塊的大小越小,塊組數越大。
從上面咱們知道,文件的內容存在data block中,可是一個文件只對應一個inode,而一個inode除了包含文件的屬性外只能指向15個磁盤塊。若是文件的大小超過了這個限制,則把最後一個(地址)指向一個間接塊,裏面存放了更多的磁盤塊地址。若是還不夠的話,還可使用二級間接塊和三級間接塊。以下圖所示(http://www.javashuo.com/article/p-klwssfxw-m.html)。
Unix/Linux系統中,目錄(directory)也是一種文件,因此也存在對應的inode。打開目錄,實際上就是打開目錄文件。
目錄文件的結構很是簡單,就是一系列目錄項(dirent)的列表。每一個目錄項,由兩部分組成:所包含文件的文件名,以及該文件名對應的inode號碼。
目錄只是將文件的名稱和它的索引節點號結合在一塊兒的一張表,目錄中每一對文件名稱和索引節點號稱爲一個鏈接。
目錄中的「..」表示父目錄索引節點的指針,以及「.」表當前目錄索引節點的指針;這兩種目錄是隱藏文件,不能刪除的。
對於一個文件來講有惟一的索引節點號與之對應,對於一個索引節點號,卻能夠有多個文件名與之對應。所以,在磁盤上的同一個文件能夠經過不一樣的路徑去訪問它。後續文章再來說述連接link。
不一樣層級的目錄構成了目錄樹,根節點即根目錄,Unix/Linux系統爲「/」。
超級塊中包含了inode節點所在的位置,而第一個inode節點指向的是根目錄。這樣就能夠對目錄樹進行搜索,從而找到所須要的目錄或文件。
注:文件名放在文件所在的目錄項中,而不是該文件對應的inode節點中。
參考資料:
《深刻理解LINUX內核》第三版。
《操做系統設計與實現》第三版 上冊。
《鳥哥的Linux私房菜》基礎篇 第四版。
http://www.javashuo.com/article/p-mljmrotu-ev.html
https://www.jianshu.com/p/41e206a9880d (fsck tune2fs dumpe2fs)