原文地址:
http://www.ibm.com/developerworks/cn/linux/l-linux-filesystem/
Linux 檔案系統剖析
按照分層結構討論 Linux 檔案系統
M. Tim Jones, 顧問工程師, Emulex Corp.
簡介: 在檔案系統方面,Linux 可以算得上作業系統中的 “瑞士軍刀”。Linux 支援許多種檔案系統,從日誌型檔案系統到叢集檔案系統和加密檔案系統。對於使用標準的和比較奇特的檔案系統以及開發檔案系統來說,Linux 是極好的平台。本文討論 Linux 核心中的虛擬檔案系統(VFS,有時候稱為虛擬檔案系統交換器),然後介紹將檔案系統串連在一起的主要結構。
標記本文!
發布日期: 2007 年 12 月 03 日
層級: 初級
訪問情況 13079 次瀏覽
建議: 0 (添加評論)
平均分 (共 22 個評分 )
基本的檔案系統體繫結構
Linux 檔案系統體繫結構是一個對複雜系統進行抽象化的有趣例子。通過使用一組通用的 API 函數,Linux 可以在許多種存放裝置上支援許多種檔案系統。例如,read
函數調用可以從指定的檔案描述符讀取一定數量的位元組。read
函數不瞭解檔案系統的類型,比如 ext3 或 NFS。它也不瞭解檔案系統所在的儲存媒體,比如 AT Attachment Packet Interface(ATAPI)磁碟、Serial-Attached SCSI(SAS)磁碟或 Serial Advanced Technology Attachment(SATA)磁碟。但是,當通過調用 read
函數讀取一個檔案時,資料會正常返回。本文講解這個機制的實現方法並介紹 Linux 檔案系統層的主要結構。
回頁首
什麼是檔案系統?
首先回答最常見的問題,“什麼是檔案系統”。檔案系統是對一個存放裝置上的資料和中繼資料進行組織的機制。由於定義如此寬泛,支援它的代碼會很有意思。正如前面提到的,有許多種檔案系統和媒體。由於存在這麼多類型,可以預料到 Linux 檔案系統介面實現為分層的體繫結構,從而將使用者介面層、檔案系統實現和操作存放裝置的驅動程式分隔開。
檔案系統作為協議另一種看待檔案系統的方式是把它看作一個協議。網路通訊協定(比如 IP)規定了互連網上傳輸的資料流的意義,同樣,檔案系統會給出特定儲存媒體上資料的意義。
掛裝
在 Linux 中將一個檔案系統與一個存放裝置關聯起來的過程稱為掛裝(mount)。使用 mount
命令將一個檔案系統附著到當前檔案系統階層中(根)。在執行掛裝時,要提供檔案系統類型、檔案系統和一個掛裝點。
為了說明 Linux 檔案系統層的功能(以及掛裝的方法),我們在當前檔案系統的一個檔案中建立一個檔案系統。實現的方法是,首先用 dd
命令建立一個指定大小的檔案(使用 /dev/zero 作為源進行檔案複製)—— 換句話說,一個用零進行初始化的檔案,見清單 1。
清單 1. 建立一個經過初始化的檔案
$ dd if=/dev/zero of=file.img bs=1k count=1000010000+0 records in10000+0 records out$ |
現在有了一個 10MB 的 file.img 檔案。使用 losetup
命令將一個迴圈裝置與這個檔案關聯起來,讓它看起來像一個塊裝置,而不是檔案系統中的常規檔案:
$ losetup /dev/loop0 file.img$ |
這個檔案現在作為一個塊裝置出現(由 /dev/loop0 表示)。然後用 mke2fs
在這個裝置上建立一個檔案系統。這個命令建立一個指定大小的新的 ext2 檔案系統,見清單 2。
清單 2. 用迴圈裝置建立 ext2 檔案系統
$ mke2fs -c /dev/loop0 10000mke2fs 1.35 (28-Feb-2004)max_blocks 1024000, rsv_groups = 1250, rsv_gdb = 39Filesystem label=OS type: LinuxBlock size=1024 (log=0)Fragment size=1024 (log=0)2512 inodes, 10000 blocks500 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/point1lost+found$ |
如清單 4 所示,還可以繼續這個過程:在剛才掛裝的檔案系統中建立一個新檔案,將它與一個迴圈裝置關聯起來,再在上面建立另一個檔案系統。
清單 4. 在迴圈檔案系統中建立一個新的迴圈檔案系統
$ dd if=/dev/zero of=/mnt/point1/file.img bs=1k count=10001000+0 records in1000+0 records out$ losetup /dev/loop1 /mnt/point1/file.img$ mke2fs -c /dev/loop1 1000mke2fs 1.35 (28-Feb-2004)max_blocks 1024000, rsv_groups = 125, rsv_gdb = 3Filesystem label=...$ mkdir /mnt/point2$ mount -t ext2 /dev/loop1 /mnt/point2$ ls /mnt/point2lost+found$ ls /mnt/point1file.img lost+found$ |
通過這個簡單的示範很容易體會到 Linux 檔案系統(和迴圈裝置)是多麼強大。可以按照相同的方法在檔案上用迴圈裝置建立加密的檔案系統。可以在需要時使用迴圈裝置臨時掛裝檔案,這有助於保護資料。
回頁首
檔案系統體繫結構
既然已經看到了檔案系統的構造方法,現在就看看 Linux 檔案系統層的體繫結構。本文從兩個角度考察 Linux 檔案系統。首先採用高層體繫結構的角度。然後進行深層次討論,介紹實現檔案系統層的主要結構。
回頁首
高層體繫結構
儘管大多數檔案系統代碼在核心中(後面討論的使用者空間檔案系統除外),但是圖 1 所示的體繫結構顯示了使用者空間和核心中與檔案系統相關的主要組件之間的關係。
圖 1. Linux 檔案系統組件的體繫結構
使用者空間包含一些應用程式(例如,檔案系統的使用者)和 GNU C 庫(glibc),它們為檔案系統調用(開啟、讀取、寫和關閉)提供使用者介面。系統調用介面的作用就像是交換器,它將系統調用從使用者空間發送到核心空間中的適當端點。
VFS 是底層檔案系統的主要介面。這個組件匯出一組介面,然後將它們抽象到各個檔案系統,各個檔案系統的行為可能差異很大。有兩個針對檔案系統對象的緩衝(inode 和 dentry)。它們緩衝最近使用過的檔案系統對象。
每個檔案系統實現(比如 ext2、JFS 等等)匯出一組通用介面,供 VFS 使用。緩衝區快取會快取檔案系統和相關塊裝置之間的請求。例如,對底層裝置驅動程式的讀寫請求會通過緩衝區快取來傳遞。這就允許在其中緩衝請求,減少訪問物理裝置的次數,加快訪問速度。以最近使用(LRU)列表的形式管理緩衝區快取。注意,可以使用 sync
命令將緩衝區快取中的請求發送到儲存媒體(迫使所有未寫的資料發送到裝置驅動程式,進而發送到存放裝置)。
什麼是塊裝置?塊裝置就是以塊(比如磁碟扇區)為單位收發資料的裝置,它們支援緩衝和隨機訪問(不必順序讀取塊,而是可以在任何時候訪問任何塊)等特性。塊裝置包括硬碟、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. 向核心註冊的檔案系統
VFS 中維護的另一個結構是掛裝的檔案系統(見圖 3)。這個結構提供當前掛裝的檔案系統(見 linux/include/linux/fs.h)。它連結下面討論的超級塊結構。
圖 3. 掛裝的檔案系統列表
超級塊
超級塊結構表示一個檔案系統。它包含管理檔案系統所需的資訊,包括檔案系統名稱(比如 ext2)、檔案系統的大小和狀態、塊裝置的引用和中繼資料資訊(比如空閑列表等等)。超級塊通常儲存在儲存媒體上,但是如果超級塊不存在,也可以即時建立它。可以在 ./linux/include/linux/fs.h 中找到超級塊結構(見圖 4)。
圖 4. 超級塊結構和 inode 操作
超級塊中的一個重要元素是超級塊操作的定義。這個結構定義一組用來管理這個檔案系統中的 inode 的函數。例如,可以用alloc_inode
分配 inode,用 destroy_inode
刪除 inode。可以用 read_inode
和 write_inode
讀寫 inode,用 sync_fs
執行檔案系統同步。可以在 ./linux/include/linux/fs.h 中找到 super_operations
結構。每個檔案系統提供自己的 inode 方法,這些方法實現操作並向 VFS 層提供通用的抽象。
inode 和 dentry
inode 表示檔案系統中的一個對象,它具有惟一標識符。各個檔案系統提供將檔案名稱映射為惟一 inode 標識符和 inode 引用的方法。圖 5 顯示 inode 結構的一部分以及兩個相關結構。請特別注意 inode_operations
和 file_operations
。這些結構表示可以在這個 inode 上執行的操作。inode_operations
定義直接在 inode 上執行的操作,而 file_operations
定義與檔案和目錄相關的方法(標準系統調用)。
圖 5. inode 結構和相關聯的操作
inode 和目錄緩衝分別儲存最近使用的 inode 和 dentry。注意,對於 inode 緩衝中的每個 inode,在目錄緩衝中都有一個對應的 dentry。可以在 ./linux/include/linux/fs.h 中找到 inode
和 dentry
結構。
緩衝區快取
除了各個檔案系統實現(可以在 ./linux/fs 中找到)之外,檔案系統層的底部是緩衝區快取。這個組件跟蹤來自檔案系統實現和物理裝置(通過裝置驅動程式)的讀寫請求。為了提高效率,Linux 對請求進行緩衝,避免將所有請求發送到物理裝置。緩衝中緩衝最近使用的緩衝區(頁面),這些緩衝區可以快速提供給各個檔案系統。
回頁首
有趣的檔案系統
本文沒有討論 Linux 中可用的具體檔案系統,但是值得在這裡稍微提一下。Linux 支援許多種檔案系統,包括 MINIX、MS-DOS 和 ext2 等老式檔案系統。Linux 還支援 ext3、JFS 和 ReiserFS 等新的日誌型檔案系統。另外,Linux 支援加密檔案系統(比如 CFS)和虛擬檔案系統(比如 /proc)。
最後一種值得注意的檔案系統是 Filesystem in Userspace(FUSE)。這種檔案系統可以將檔案系統請求通過 VFS 發送回使用者空間。所以,如果您有興趣建立自己的檔案系統,那麼通過使用 FUSE 進行開發是一種不錯的方法。
回頁首
結束語
分享這篇文章……
|
|
將本文提交到 Digg |
|
|
發布到 del.icio.us |
|
|
提交到 Slashdot! |
|
儘管檔案系統的實現並不複雜,但它是可伸縮和可擴充的體繫結構的好例子。檔案系統體繫結構已經發展了許多年,並成功地支援了許多不同類型的檔案系統和許多目標存放裝置類型。由於使用了基於外掛程式的體繫結構和多層的函數間接性,Linux 檔案系統在近期的發展很值得關注。
參考資料
學習
- 您可以參閱本文在 developerWorks 全球網站上的 英文原文。
- proc 檔案系統提供了一種通過虛擬檔案系統在使用者空間和核心之間進行通訊的新方式。“使用 /proc 檔案系統來訪問 Linux 核心的內容”(developerWorks,2006 年 3 月)介紹了 /proc 虛擬檔案系統並示範它的使用方法。
- Linux 系統調用介面可以在使用者空間和核心之間傳遞控制,從而調用核心 API 函數。“使用 Linux 系統調用的核心命令”(developerWorks,2007 年)介紹了 Linux 系統調用介面。
- Yolinux.com 維護 Linux 檔案系統、叢集檔案系統和效能計算叢集的列表。還可以在 File systems HOWTO 中找到 Linux 檔案系統的完整列表。Xenotime 也描述了許多檔案系統。
- 關於 Linux 使用者空間編程的更多資訊,請參考本文作者所著的 GNU/Linux Application Programming 。
- 在 developerWorks Linux 專區 中可以找到為 Linux 開發人員準備的更多參考資料,還可以查閱 最流行的文章和教程。
- 查閱 developerWorks 上的所有 Linux 技巧 和 Linux 教程。
- 隨時關注 developerWorks 技術活動和網路廣播。
獲得產品和技術
- Filesystem in Userspace(FUSE)是一個支援在使用者空間中開發檔案系統的核心模組。檔案系統驅動程式實現將來自 VFS 的請求發送回使用者空間。這是一種在不藉助核心開發的情況下開發檔案系統的好方法。如果您精通 Python,也可以通過LUFS-Python 用 Python 編寫檔案系統。
- 下載 IBM 產品評估版,試用來自 DB2、Lotus、Rational、Tivoli 和 WebSphere 的應用程式開發工具和中介軟體產品。
討論
- 通過 新的 developerWorks 空間 中的 blog、論壇、podcast 和社區主題,加入 developerWorks 社區。
關於作者
M. Tim Jones 是一名嵌入式軟體工程師,他是 GNU/Linux Application Programming、AI Application Programming以及 BSD Sockets Programming from a Multilanguage Perspective 等書的作者。他的工程背景非常廣泛,從同步宇宙飛船的核心開發到嵌入式架構設計,再到網路通訊協定的開發。Tim 是位於科羅拉多州 Longmont 的 Emulex Corp. 的一名顧問工程師。