檔案系統的原理

2021-10-10 06:57:49 字數 3328 閱讀 2220

永續性的資料是儲存在外部磁碟上的【注1】,如果沒有檔案系統,訪問這些資料就需要直接讀寫磁碟的sector,實在太不方便了。而檔案系統存在的意義,就是能更有效的組織、管理和使用磁碟上的這些raw data。

檔案系統的組成

要管理,就得先劃分,那按照什麼粒度劃分呢?因為磁碟上的資料要和記憶體互動,而記憶體通常是以4kb為單位的,所以從邏輯上,把磁碟按照4kb劃分比較方便(稱為乙個block)。現在假設由乙個檔案系統管理64個blocks的乙個磁碟區域:

empty disk

那在這些blocks中應該儲存些什麼?檔案系統的基礎要素自然是檔案,而檔案作為乙個資料容器的邏輯概念,本質上是一些位元組構成的集合,這些位元組就是檔案的user data(對應下圖的"d")。

user data

除了檔案本身包含的資料,還有檔案的訪問許可權、大小和建立時間等控制資訊,這些資訊被稱為meta data。meta data可理解為是關於檔案user data的data,這些meta data儲存的資料結構就是inode(對應下圖的"i",有些檔案系統稱之為dnode或fnode)。

inode是"index node"的簡稱,在早期的unix系統中,這些nodes是通過陣列組織起來的,因此需要依靠index來索引陣列中的node。假設乙個inode佔據256位元組,那麼乙個4kb的block可以存放16個inodes,使用5個blocks可以存放80個inodes,也就是最多支援80個檔案。

meta data + user data

同記憶體分配一樣,當有了新的資料產生時,我們需要選擇乙個空閒的block來存放資料,此外還需要乙個空閒的inode。所以,需要追蹤這些inodes和data blocks的分配和釋放情況,以判斷哪些是已用的,哪些是空閒的。

最簡單的辦法就是使用bitmap,包括記錄inode使用情況的bitmap(對應下圖的"i"),和記錄data block使用情況的bitmap(對應下圖的"d")。空閒就標記為0,正在使用就標記為1。

bitmap + meta data + user date

因為block是最小劃分單位,所以這裡使用了兩個blocks來分別儲存inode bitmap和data block bitmap,每個block可以容納的bits數量是4096*8。而這裡我們只有80個inodes和56個data blocks,所以是綽綽有餘的。

還剩下開頭的乙個block,這個block是留給superblock的(對應下圖的"s")。

superblock + bitmap + meta data + user date

這個superblock包含了乙個檔案系統所有的控制資訊,比如檔案系統中有多少個inodes和data blocks,inode的資訊起始於哪個block(這裡是第3個),可能還有乙個區別不同檔案系統型別的magic number。因此,superblock可理解為是檔案系統的meta data。

檔案定址

這5個blocks中的80個inodes構成了乙個inode table。假設乙個inode的大小是256位元組,現在我們要訪問第32個檔案,那就要先找到這個檔案的控制資訊,也就是第32個inode所在的磁碟位置。它應該在相對inode table起始位址的8kb處(32*256=8192),而inode table的起始位址是12kb,所以實際位置是20kb。

inode table

磁碟同記憶體不同,它在物理上不是按位元組定址的,而是按sector。乙個sector的大小通常是512位元組,因此換算一下就是第40個sector(20*1024/512)。

對於ext2/3/4檔案系統,以上介紹的這些inode bitmap, data block bitmap和inode table,都可以通過乙個名為"dumpe2fs"的工具來檢視其在磁碟上的具體位置:

如果只需要檢視inode的使用情況,那麼直接使用"df -i"命令即可:

inode usage

【定址方式】

那通過inode如何找到對應的檔案呢?根據大小的不同,乙個檔案需要佔據若干個blocks,這些blocks可能是磁碟上連續分布的,也可能不是。所以,比較好的辦法是使用指標,指標儲存在inode中,乙個指標指向乙個block。

不過,在這個簡化的示例裡,並不需要c語言裡那種指標,只需要乙個block的編號就可以了。如果檔案比較小,占有的blocks數目就比較少,那麼乙個256位元組的inode就能儲存這些指標。假設乙個inode最多能包含12個指標,那麼檔案的大小不能超過48kb。

那如果超過了怎麼辦?可由inode先指向乙個block,這個block再指向分散的data block,這種方法稱為multi-level index。inode在指向中間block的同時,也可以直接指向data block。假設乙個指標佔據4個位元組,那麼乙個中間block可儲存1024個指標,二級index的定址範圍就可超過4mb,**index則可超過4gb。

有沒有覺得很像記憶體管理中的多級頁表?事實上,它們的原理可以說是一樣的,檔案在磁碟上的實際block分布對等於記憶體的實體地址,而各級index就對等於記憶體的虛擬位址。

這種只使用block指標的方式被ext2和ext3檔案系統所採用,但它存在乙個問題,對於各種大小的檔案,都需要較多的meta data。而在實際的應用中,大多數檔案的體積都很小,meta data相對user data的佔比就較大。

另一種實現是使用乙個block指標加上乙個length來表示一組物理上連續的blocks(稱為乙個extent,其中length以block為單位計),乙個檔案由若干個extents構成。這樣,小檔案所需要的meta data就較少,這種更靈活的實現方式被後來的ext4檔案系統所採用。

struct ext4_extent ;

目錄和路徑

各級目錄構成了訪問檔案的路徑,不同於windows作業系統的drive分割槽,類unix系統中的"mount"操作讓所有的檔案系統的掛載點都是乙個路徑,形成了樹形結構。從抽象的角度,目錄也可視作一種檔案,只是這種檔案比較特殊,它的user data儲存的是該路徑下的普通檔案的inode編號。

所以,如下圖所示的這樣乙個路徑結構,假設要在"/foo"目錄下建立乙個檔案"bar.txt",那麼需要從inode bitmap中分配乙個空閒的inode,並在"/foo"這個目錄中分配乙個entry,以關聯這個inode號。

接下來,我們要讀取剛才建立的這個"/foo/bar.txt"檔案,那麼先得找到"/"這個目錄檔案的inode號(這必須是事先知道的,假設是2)。然後訪問這個inode指向的data block,從中找到乙個名為"foo"的entry,得到目錄檔案"foo"的inode號(假設是44)。重複此過程,按圖索驥,直到找到文字檔案"bar.txt"的inode號。

小結現代檔案系統的實現是很龐雜的,但檔案系統的原理本身並不深奧,基本的構成要素就是file data,管理各個檔案的inode和管理整個檔案系統的superblock。基於這些要素,下文將開始介紹讀寫乙個檔案的具體方式和介面。

根檔案系統的原理

1 linuxrc是應用層的,和核心原始碼沒有關係 2 linuxrc在開發板當前核心系統下是可執行的。3 linuxrc如果是靜態編譯連線的,則直接可以執行 如果是動態編譯連線的,必須提供必要的庫檔案才能執行。1 使用者操作介面由 linuxrc帶出來。2 應用程式是直接或者間接的被 linuxr...

根檔案系統的原理

1 linuxrc是應用層的 和核心原始碼沒有關係 2 linuxrc在開發板當前核心系統下是可執行的。3 linuxrc如果是靜態編譯連線的,則直接可以執行 如果是動態編譯連線的,必須提供必要的庫檔案才能執行。1 使用者操作介面由 linuxrc帶出來。2 應用程式是直接或者間接的被 linuxr...

linux 檔案系統原理

linux 預設是ext2檔案系統 檔案系統中,檔案除了實際內容外,還有很多不同的屬性 所以檔案系統把這兩部分分別儲存 檔案屬性儲存在inode中,乙個文件占用乙個inode,同時記錄文件的block號碼 檔案內容儲存在datablock中,根據文件內容可以占用多個block 而記憶體中還有乙個超級...