Linux 檔案系統剖析

tengrid發表於2009-05-18
在檔案系統方面,Linux® 可以算得上作業系統中的 “瑞士軍刀”。Linux 支援許多種檔案系統,從日誌型檔案系統到叢集檔案系統和加密檔案系統。對於使用標準的和比較奇特的檔案系統以及開發檔案系統來說,Linux 是極好的平臺。本文討論 Linux 核心中的虛擬檔案系統(VFS,有時候稱為虛擬檔案系統交換器),然後介紹將檔案系統連線在一起的主要結構。

[@more@]

基本的檔案系統體系結構

Linux 檔案系統體系結構是一個對複雜系統進行抽象化的有趣例子。通過使用一組通用的 API 函式,Linux 可以在許多種儲存裝置上支援許多種檔案系統。例如,read 函式呼叫可以從指定的檔案描述符讀取一定數量的位元組。read 函式不瞭解檔案系統的型別,比如 ext3 或 NFS。它也不瞭解檔案系統所在的儲存媒體,比如 AT Attachment Packet Interface(ATAPI)磁碟、Serial-Attached SCSI(SAS)磁碟或 Serial Advanced Technology Attachment(SATA)磁碟。但是,當通過呼叫 read 函式讀取一個檔案時,資料會正常返回。本文講解這個機制的實現方法並介紹 Linux 檔案系統層的主要結構。


Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析回頁首


什麼是檔案系統?

首先回答最常見的問題,“什麼是檔案系統”。檔案系統是對一個儲存裝置上的資料和後設資料進行組織的機制。由於定義如此寬泛,支援它的程式碼會很有意思。正如前面提到的,有許多種檔案系統和媒體。由於存在這麼多型別,可以預料到 Linux 檔案系統介面實現為分層的體系結構,從而將使用者介面層、檔案系統實現和操作儲存裝置的驅動程式分隔開。

Linux 檔案系統剖析
檔案系統作為協議
另一種看待檔案系統的方式是把它看作一個協議。網路協議(比如 IP)規定了網際網路上傳輸的資料流的意義,同樣,檔案系統會給出特定儲存媒體上資料的意義。

掛裝

在 Linux 中將一個檔案系統與一個儲存裝置關聯起來的過程稱為掛裝(mount)。使用 mount 命令將一個檔案系統附著到當前檔案系統層次結構中(根)。在執行掛裝時,要提供檔案系統型別、檔案系統和一個掛裝點。

為了說明 Linux 檔案系統層的功能(以及掛裝的方法),我們在當前檔案系統的一個檔案中建立一個檔案系統。實現的方法是,首先用 dd 命令建立一個指定大小的檔案(使用 /dev/zero 作為源進行檔案複製)—— 換句話說,一個用零進行初始化的檔案,見清單 1。


清單 1. 建立一個經過初始化的檔案
                
$ dd if=/dev/zero of=file.img bs=1k count=10000
10000+0 records in
10000+0 records out
$

現在有了一個 10MB 的 file.img 檔案。使用 losetup 命令將一個迴圈裝置與這個檔案關聯起來,讓它看起來像一個塊裝置,而不是檔案系統中的常規檔案:

$ losetup /dev/loop0 file.img
$

這個檔案現在作為一個塊裝置出現(由 /dev/loop0 表示)。然後用 mke2fs 在這個裝置上建立一個檔案系統。這個命令建立一個指定大小的新的 ext2 檔案系統,見清單 2。


清單 2. 用迴圈裝置建立 ext2 檔案系統
                
$ mke2fs -c /dev/loop0 10000
mke2fs 1.35 (28-Feb-2004)
max_blocks 1024000, rsv_groups = 1250, rsv_gdb = 39
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
2512 inodes, 10000 blocks
500 blocks (5.00%) reserved for the super user
...
$

使用 mount 命令將迴圈裝置(/dev/loop0)所表示的 file.img 檔案掛裝到掛裝點 /mnt/point1。注意,檔案系統型別指定為 ext2。掛裝之後,就可以將這個掛裝點當作一個新的檔案系統,比如使用 ls 命令,見清單 3。


清單 3. 建立掛裝點並通過迴圈裝置掛裝檔案系統
                
$ mkdir /mnt/point1
$ mount -t ext2 /dev/loop0 /mnt/point1
$ ls /mnt/point1
lost+found
$

如清單 4 所示,還可以繼續這個過程:在剛才掛裝的檔案系統中建立一個新檔案,將它與一個迴圈裝置關聯起來,再在上面建立另一個檔案系統。


清單 4. 在迴圈檔案系統中建立一個新的迴圈檔案系統
                
$ dd if=/dev/zero of=/mnt/point1/file.img bs=1k count=1000
1000+0 records in
1000+0 records out
$ losetup /dev/loop1 /mnt/point1/file.img
$ mke2fs -c /dev/loop1 1000
mke2fs 1.35 (28-Feb-2004)
max_blocks 1024000, rsv_groups = 125, rsv_gdb = 3
Filesystem label=
...
$ mkdir /mnt/point2
$ mount -t ext2 /dev/loop1 /mnt/point2
$ ls /mnt/point2
lost+found
$ ls /mnt/point1
file.img lost+found
$

通過這個簡單的演示很容易體會到 Linux 檔案系統(和迴圈裝置)是多麼強大。可以按照相同的方法在檔案上用迴圈裝置建立加密的檔案系統。可以在需要時使用迴圈裝置臨時掛裝檔案,這有助於保護資料。


Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析回頁首


檔案系統體系結構

既然已經看到了檔案系統的構造方法,現在就看看 Linux 檔案系統層的體系結構。本文從兩個角度考察 Linux 檔案系統。首先採用高層體系結構的角度。然後進行深層次討論,介紹實現檔案系統層的主要結構。


Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析回頁首


高層體系結構

儘管大多數檔案系統程式碼在核心中(後面討論的使用者空間檔案系統除外),但是圖 1 所示的體系結構顯示了使用者空間和核心中與檔案系統相關的主要元件之間的關係。


圖 1. Linux 檔案系統元件的體系結構
圖 1. Linux 檔案系統元件的體系結構

使用者空間包含一些應用程式(例如,檔案系統的使用者)和 GNU C 庫(glibc),它們為檔案系統呼叫(開啟、讀取、寫和關閉)提供使用者介面。系統呼叫介面的作用就像是交換器,它將系統呼叫從使用者空間傳送到核心空間中的適當端點。

VFS 是底層檔案系統的主要介面。這個元件匯出一組介面,然後將它們抽象到各個檔案系統,各個檔案系統的行為可能差異很大。有兩個針對檔案系統物件的快取(inode 和 dentry)。它們快取最近使用過的檔案系統物件。

每個檔案系統實現(比如 ext2、JFS 等等)匯出一組通用介面,供 VFS 使用。緩衝區快取會快取檔案系統和相關塊裝置之間的請求。例如,對底層裝置驅動程式的讀寫請求會通過緩衝區快取來傳遞。這就允許在其中快取請求,減少訪問物理裝置的次數,加快訪問速度。以最近使用(LRU)列表的形式管理緩衝區快取。注意,可以使用 sync 命令將緩衝區快取中的請求傳送到儲存媒體(迫使所有未寫的資料傳送到裝置驅動程式,進而傳送到儲存裝置)。

Linux 檔案系統剖析
什麼是塊裝置?
塊裝置就是以塊(比如磁碟扇區)為單位收發資料的裝置,它們支援緩衝和隨機訪問(不必順序讀取塊,而是可以在任何時候訪問任何塊)等特性。塊裝置包括硬碟、CD-ROM 和 RAM 盤。與塊裝置相對的是字元裝置,字元裝置沒有可以進行物理定址的媒體。字元裝置包括串列埠和磁帶裝置,只能逐字元地讀取這些裝置中的資料。

這就是 VFS 和檔案系統元件的高層情況。現在,討論實現這個子系統的主要結構。

主要結構

Linux 以一組通用物件的角度看待所有檔案系統。這些物件是超級塊(superblock)、inode、dentry 和檔案。超級塊在每個檔案系統的根上,超級塊描述和維護檔案系統的狀態。檔案系統中管理的每個物件(檔案或目錄)在 Linux 中表示為一個 inode。inode 包含管理檔案系統中的物件所需的所有後設資料(包括可以在物件上執行的操作)。另一組結構稱為 dentry,它們用來實現名稱和 inode 之間的對映,有一個目錄快取用來儲存最近使用的 dentry。dentry 還維護目錄和檔案之間的關係,從而支援在檔案系統中移動。最後,VFS 檔案表示一個開啟的檔案(儲存開啟的檔案的狀態,比如寫偏移量等等)。

虛擬檔案系統層

VFS 作為檔案系統介面的根層。VFS 記錄當前支援的檔案系統以及當前掛裝的檔案系統。

可以使用一組註冊函式在 Linux 中動態地新增或刪除檔案系統。核心儲存當前支援的檔案系統的列表,可以通過 /proc 檔案系統在使用者空間中檢視這個列表。這個虛擬檔案還顯示當前與這些檔案系統相關聯的裝置。在 Linux 中新增新檔案系統的方法是呼叫 register_filesystem。這個函式的引數定義一個檔案系統結構(file_system_type)的引用,這個結構定義檔案系統的名稱、一組屬性和兩個超級塊函式。也可以登出檔案系統。

在註冊新的檔案系統時,會把這個檔案系統和它的相關資訊新增到 file_systems 列表中(見圖 2 和 linux/include/linux/mount.h)。這個列表定義可以支援的檔案系統。在命令列上輸入 cat /proc/filesystems,就可以檢視這個列表。


圖 2. 向核心註冊的檔案系統
 圖 2. 向核心註冊的檔案系統

VFS 中維護的另一個結構是掛裝的檔案系統(見圖 3)。這個結構提供當前掛裝的檔案系統(見 linux/include/linux/fs.h)。它連結下面討論的超級塊結構。


圖 3. 掛裝的檔案系統列表
 圖 3. 掛裝的檔案系統列表

超級塊

超級塊結構表示一個檔案系統。它包含管理檔案系統所需的資訊,包括檔案系統名稱(比如 ext2)、檔案系統的大小和狀態、塊裝置的引用和後設資料資訊(比如空閒列表等等)。超級塊通常儲存在儲存媒體上,但是如果超級塊不存在,也可以實時建立它。可以在 ./linux/include/linux/fs.h 中找到超級塊結構(見圖 4)。


圖 4. 超級塊結構和 inode 操作
 圖 4. 超級塊結構和 inode 操作

超級塊中的一個重要元素是超級塊操作的定義。這個結構定義一組用來管理這個檔案系統中的 inode 的函式。例如,可以用 alloc_inode 分配 inode,用 destroy_inode 刪除 inode。可以用 read_inodewrite_inode 讀寫 inode,用 sync_fs 執行檔案系統同步。可以在 ./linux/include/linux/fs.h 中找到 super_operations 結構。每個檔案系統提供自己的 inode 方法,這些方法實現操作並向 VFS 層提供通用的抽象。

inode 和 dentry

inode 表示檔案系統中的一個物件,它具有惟一識別符號。各個檔案系統提供將檔名對映為惟一 inode 識別符號和 inode 引用的方法。圖 5 顯示 inode 結構的一部分以及兩個相關結構。請特別注意 inode_operationsfile_operations。這些結構表示可以在這個 inode 上執行的操作。inode_operations 定義直接在 inode 上執行的操作,而 file_operations 定義與檔案和目錄相關的方法(標準系統呼叫)。


圖 5. inode 結構和相關聯的操作
 圖 5. inode 結構和相關聯的操作

inode 和目錄快取分別儲存最近使用的 inode 和 dentry。注意,對於 inode 快取中的每個 inode,在目錄快取中都有一個對應的 dentry。可以在 ./linux/include/linux/fs.h 中找到 inodedentry 結構。

緩衝區快取

除了各個檔案系統實現(可以在 ./linux/fs 中找到)之外,檔案系統層的底部是緩衝區快取。這個元件跟蹤來自檔案系統實現和物理裝置(通過裝置驅動程式)的讀寫請求。為了提高效率,Linux 對請求進行快取,避免將所有請求傳送到物理裝置。快取中快取最近使用的緩衝區(頁面),這些緩衝區可以快速提供給各個檔案系統。


Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析回頁首


有趣的檔案系統

本文沒有討論 Linux 中可用的具體檔案系統,但是值得在這裡稍微提一下。Linux 支援許多種檔案系統,包括 MINIX、MS-DOS 和 ext2 等老式檔案系統。Linux 還支援 ext3、JFS 和 ReiserFS 等新的日誌型檔案系統。另外,Linux 支援加密檔案系統(比如 CFS)和虛擬檔案系統(比如 /proc)。

最後一種值得注意的檔案系統是 Filesystem in Userspace(FUSE)。這種檔案系統可以將檔案系統請求通過 VFS 傳送回使用者空間。所以,如果您有興趣建立自己的檔案系統,那麼通過使用 FUSE 進行開發是一種不錯的方法。


Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析
Linux 檔案系統剖析回頁首


結束語

Linux 檔案系統剖析
分享這篇文章……

Linux 檔案系統剖析
digg 將本文提交到 Digg
Linux 檔案系統剖析
del.icio.us 釋出到 del.icio.us
Linux 檔案系統剖析
Slashdot 提交到 Slashdot!
Linux 檔案系統剖析

儘管檔案系統的實現並不複雜,但它是可伸縮和可擴充套件的體系結構的好例子。檔案系統體系結構已經發展了許多年,併成功地支援了許多不同型別的檔案系統和許多目標儲存裝置型別。由於使用了基於外掛的體系結構和多層的函式間接性,Linux 檔案系統在近期的發展很值得關注。



參考資料

學習

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10130206/viewspace-1037581/,如需轉載,請註明出處,否則將追究法律責任。

相關文章