linux bible 第九章 文件系統

火星人 @ 2014-03-09 , reply:0
←手機掃碼閱讀

第九章 文件系統


本章主要描敘Linux核心對文件系統的支持,虛擬文件系統(VFS)以
及Linux核心對實際文件系統的支持.

Linux的最重要特徵之一就是支持多種文件系統.這樣它更加靈活並
可以和許多其它種操作系統共存.在本文寫作時Linux已經支持15種
文件系統:ext,ext2,xia,minix,umsdos,msdos,vfat,proc,smb,ncp,
iso9660,sysv,hpfs,affs以及ufs.毫無疑問,今後支持的文件系統類
型還將增加.

Linux和Unix並不使用設備標誌符(如設備號或驅動器名稱)來訪問獨
立文件系統,而是通過一個將整個文件系統表示成單一實體的層次樹
結構來訪問它.Linux每安裝(mount)一個文件系統時都會其加入到文
件系統層次樹中.不管是文件系統屬於什麼類型,都被連接到一個目
錄上且此文件系統上的文件將取代此目錄中已存在的文件.這個目錄
被稱為安裝點或者安裝目錄.當卸載此文件系統時這個安裝目錄中原
有的文件將再次出現.

當磁碟初始化時(使用fdisk),磁碟中將添加一個描敘物理磁碟邏輯
構成的分區結構.每個分區可以擁有一個獨立文件系統如EXT2.文件
系統將文件組織成包含目錄,軟連接等存在於物理塊設備中的邏輯層
次結構.包含文件系統的設備叫塊設備.Linux文件系統認為這些塊設
備是簡單的線性塊集合,它並不關心或理解底層的物理磁碟結構.這個
工作由塊設備驅動來完成,由它將對某個特定塊的請求映射到正確的
設備上去;此塊所在硬碟的對應磁軌、扇區及柱面數都被保存起來.不
管哪個設備持有這個塊,文件系統都使用相同的方式來尋找並操縱
此塊.Linux文件系統不管(至少對系統用戶來說)系統中有哪些不同
的控制器控制著哪些不同的物理介質且這些物理介質上有幾個不同的文


件系統.文件系統甚至還可以不在本地系統而在通過網路連接的遠程硬
盤上.設有一個根目錄內容如下的SCSI硬碟:

A E boot etc lib opt tmp usr
C F cdrom fd proc root var sbin
D bin dev home mnt lost found

此時不管是用戶還是程序都無需知道他們現在操縱的這些文件中的/C實
際上是位於系統第一個IDE硬碟上並已安裝VFAT文件系統.在此例中/E表
示系統中第二個IDE控制器上的主IDE硬碟.至於第一個IDE控制器是PCI
控制器和第二個則是控制IDE CDROM的ISA控制器無關緊要.當使用modem
通過PPP網路協議來撥入網路時,可以將Alpha AXP Linux文件系統安裝到
/mnt/remote目錄下.

文件系統中的文件是數據的集合;包含本章內容的文件是一個名叫
filesystems.tex的ASCII文件.文件系統不僅包含著文件中的數據
有文件系統的結構.所有Linux用戶和程序看到的文件、目錄、軟連接及
文件保護信息等都存儲在其中.此外文件系統中包含安全信息以便
保持操作系統的基本完整性.沒人願意使用一個動不動就丟失數據和文件
的操作系統.

Linux最早的文件系統是Minix,它受限甚大且性能低下.其文件名最長不
能超過14個字元(雖然比8.3文件名要好)且最大文件大小為64M位元組.64M
位元組看上去很大,但實際上一個中等的資料庫將超過這個尺寸.第一個專
門為Linux設計的文件系統被稱為擴展文件系統(Extended File System)
或EXT.它出現於1992年四月,雖然能夠解決一些問題但性能依舊不好.
1993年擴展文件系統第二版或EXT2被設計出來並添加到Linux中.它是本
章將詳細討論的文件系統.

將EXT文件系統添加入Linux產生了重大影響.每個實際文件系統從操作系
統和系統服務中分離出來,它們之間通過一個介面層:虛擬文件系統或VFS


來通訊.

VFSLinux可以支持多個不同的文件系統,每個表示一個VFS的通用介面.
軟體將Linux文件系統的所有細節進行了轉換,Linux核心的其它部
分及系統中運行的程序將看到統一的文件系統.Linux的虛擬文件系統允許
用戶同時能透明地安裝許多不同的文件系統.

虛擬文件系統的設計目標是為Linux用戶提供快速且高效的文件訪問服務.
同時它保證文件及其數據的正確性.這兩個目標相互間可能存在衝突.
當安裝一個文件系統並使用時,Linux VFS為其緩存相關信息.此緩存中數
據在創建、寫入和刪除文件與目錄時如果被修改,則謹慎地更新文件
系統中對應內容.如果能夠在運行核心內看到文件系統的數據結構,那麼
就可以看到那些正被文件系統讀寫的數據塊.描敘文件與目錄的數據結構
被不斷的創建與刪除而設備驅動將不停地讀取與寫入數據.這些緩存中最
重要的是Buffer Cache,它被集成到獨立文件系統訪問底層塊設備的常式
中.當進行塊存取時數據塊將被放入Buffer Cache里並根據其狀態保
存在各個隊列中.此Buffer Cache不僅緩存數據幫助管理塊設備驅動
中的非同步介面.

9.1 第二代擴展文件系統(EXT2)


第二代擴展文件系統由Rey
Card設計,其目標是為Linux提供一個強大的可擴展文件系統.它同時也
是Linux界中設計最成功的文件系統.

象很多文件系統一樣,EXT2建立在數據被保存在數據塊中的文件內這個前
提下.這些數據塊長度相等且這個長度可以變化,某個EXT2文件系統的塊
大小在創建(使用mke2fs)時設置.每個文件的大小和剛好大於它的塊大
小正數倍相等.如果塊大小為1024位元組而一個1025位元組長的文件將佔據兩


個1024位元組大小的塊.這樣你不得不浪費差不多一般的空間.我們通常需
要在CPU的內存利用率和磁碟空間使用上進行折中.而大多數操作系統,包
括Linux在內,為了減少CPU的工作負載而被迫選擇相對較低的磁碟空間利
用率.並不是文件中每個塊都包含數據,其中有些塊被用來包含描敘此文
件系統結構的信息.EXT2通過一個inode結構來描敘文件系統中文件並確定
此文件系統的拓撲結構.inode結構描敘文件中數據佔據哪個塊以及文件的
存取許可權、文件修改時間及文件類型.EXT2文件系統中的每個文件用一個
inode來表示且每個inode有唯一的編號.文件系統中所有的inode都被保存
在inode表中.EXT2目錄僅是一個包含指向其目錄入口指針的特殊文件
(也用inode表示).

佔用一系列數據塊的EXT2文件系統的布局.對文件系統而言文件僅是一
系列可讀寫的數據塊.文件系統並不需要了解數據塊應該放置到物理介質
上什麼位置,這些都是設備驅動的任務.無論何時只要文件系統需要從包
含它的塊設備中讀取信息或數據,它將請求底層的設備驅動讀取一個基本
塊大小整數倍的數據塊.EXT2文件系統將它所使用的邏輯分區劃分成數據
塊組.每個數據塊組將那些對文件系統完整性最重要的信息複製出來,同時
將實際文件和目錄看作信息與數據塊.為了發生災難性事件時文件系統的
修復,這些複製非常有必要.以下一節將著重描敘每個數據塊組的內容.

9.1.1 The EXT2 Inode

在EXT2文件系統中inode是基本塊;文件系統中的每個文件與目錄由唯一的
inode來描敘.每個數據塊組的EXT2inode被保存在inode表中,同時還有一
個點陣圖被系統用來跟蹤已分配和未分配的inode.


inode的格式,它包含以下幾個域:

mode
它包含兩類信息;inode描敘的內容以及用戶使用許可權.EXT2中的
inode可以表示一個文件、目錄、符號連接、塊設備、字元設備或FIFO.
Owner Information
表示此文件或目錄所有者的用戶和組標誌符.文件系統根據它可以
進行正確的存取.
Size 以位元組計算的文件尺寸.
Timestamps
inode創建及一次被修改的時間.
Datablocks
指向此inode描敘的包含數據的塊指針.前12個指針指向包含由inode
描敘的物理塊,三個指針包含多級間接指針.例如兩級間接指針
指向一塊指針,而這些指針又指向一些數據塊.這意味著訪問文件尺
寸小於或等於12個數據塊的文件將比訪問大文件快得多.

EXT2 inode還可以描敘特殊設備文件.雖然它們不是真正的文件,但可以通
過它們訪問設備.所有那些位於/dev中的設備文件可用來存取Linux設備.
例如mount程序可把設備文件作為參數.

9.1.2 EXT2 超塊

超塊中包含了描敘文件系統基本尺寸和形態的信息.文件系統管理器利用
它們來使用和維護文件系統.通常安裝文件系統時只讀取數據塊組0中的超
塊,但是為了防止文件系統被破壞,每個數據塊組都包含了複製拷貝.超塊
包含如下信息:

Magic Number
文件系統安裝軟體用來檢驗是否是一個真正的EXT2文件系統超塊.當
前EXT2版本中為0xEF53.
Revision Level
這個主從修訂版本號讓安裝代碼能判斷此文件系統是否支持只存在於
某個特定版本文件系統中的屬性.同時它還是特性兼容標誌以幫助安
裝代碼判斷此文件系統的新特性是否可以安全使用.
Mount Count and Maximum Mount Count
系統使用它們來決定是否應對此文件系統進行全面檢查.每次文件系


統安裝時此安裝記數將遞增,當它等於最大安裝記數時系統將顯示一
條警告信息「maxumal mount count reached, running e2fsck is recommended」.
Block Group Number
超塊的拷貝.
Block Size
以位元組記數的文件系統塊大小,如1024位元組.
Blocks per Group
每個組中塊數目.當文件系統創建時此塊大小被固定下來.
Free Blocks
文件系統中空閑塊數.
Free Inodes
文件系統中空閑Inode數.
First Inode
文件系統中第一個inode號.EXT2根文件系統中第一個inode將是指
向/目錄的目錄入口.

9.1.3 EXT2 組標誌符

每個數據塊組都擁有一個描敘它結構.象超塊一樣,所有數據塊組中的組描
敘符被複制到每個數據塊組中以防文件系統崩潰.每個組描敘符包含以下信息:



Blocks Bitmap
對應此數據塊組的塊分配點陣圖的塊號.在塊分配和回收時使用.
Inode Bitmap
對應此數據塊組的inode分配點陣圖的塊號.在inode分配和回收時使用.
Inode Table
對應數據塊組的inode表的起始塊號.每個inode用下面的EXT2
inode結構來表示.
Free blocks count, Free Inodes count, Used directory count

組描敘符放置在一起形成了組描敘符表.每個數據塊組在超塊拷貝后包含整
個組描敘符表.EXT2文件系統僅使用第一個拷貝(在數據塊組0中).其它拷
貝都象超塊拷貝一樣用來防止主拷貝被破壞.

9.1.4 EXT2 目錄


在EXT2文件系統中目錄是用來創建和包含文件系統中文件存取路徑的特殊文件.

目錄文件是一組目錄入口的鏈表,它們包含以下信息:

inode
對應每個目錄入口的inode.它被用來索引儲存在數據塊組的Inode表中
的inode數組.

name length
以位元組記數的目錄入口長度.


name
目錄入口的名稱

每個目錄的前兩個入口總是"."和"..".它們分別表示當前目錄和父目錄.

9.1.5 在EXT2文件系統中搜尋文件

Linux文件名的格式與Unix類似,是一系列以"/"隔開的目錄名並以文件名結尾.
/home/rusling/.cshrc中/home和/rusling都是目錄名而文件名為.cshrc.象
Unix系統一樣,Linux並不關心文件名格式本身,它可以由任意可列印字元組
成.為了尋找EXT2文件系統中表示此文件的inode,系統將文件名從目錄
名中分離出來.

我們所需要的第一個inode是根文件系統的inode,它被存放在文件系統的超
塊中.為讀取某個EXT2 inode,我們在適當數據塊組的inode表中進行搜
尋.如果根inode號為42則我們需要數據塊組0 inode表的第42個inode.此
根inode對應於一個EXT2目錄,即根inode的mode域將它描敘成目錄且其數據
塊包含EXT2目錄入口.home目錄是許多目錄的入口同時此目錄給我們提供了
大量描敘/home目錄的inode.我們讀取此目錄以找到rusling目錄入口,
此入口又提供了許多描敘/home/rusling目錄的inode.讀取由/home/rusling
目錄描敘的inode指向的目錄入口以找出.cshrc文件的inode號並從中取得包
含在文件中信息的數據塊.



9.1.6 改變EXT2文件系統中文件的大小

文件系統普遍存在的一個問題是碎塊化.一個文件所包含的數據塊遍布整個
文件系統,這對文件數據塊的順序訪問越來越慢.EXT2文件系統試圖通
過分配一個和當前文件數據塊在物理位置上鄰接或者至少位於同一個數據塊
組中的新塊來解決這個問題.只有在這種分配策略失敗時才在其它數據塊組
中分配空間.

當進程準備寫某文件時,
Linux文件系統檢查數據是否已經超出了文件一個被分配的塊空間.


如果是則為此文件分配一個新數據塊.進程將一直等待到此分配完成;
然後將其餘數據寫入此文件.EXT2塊分配常式所作的第一件事是對此文件系
統的EXT2超塊加鎖.這是塊分配和回收將導致超塊中某些域的改變,
Linux文件系統不能在同一時刻為多個進程進行此類服務.如果另外一個進程
需要分配更多的數據塊時它等到此進程完成分配操作為止.
在超塊上等待的進程將被掛起直到超塊的控制權被其當前使用者釋放.對超
塊的訪問遵循先來先服務原則,一旦進程取得了超塊的控制則它保持到
操作結束為止.如果系統中空閑塊不多則此分配的將失敗,進程會釋放對文
件系統超塊的控制.

如果EXT2文件系統被設成預先分配數據塊則我們可以從中取得一個.預先分
配塊實際上並不存在,它們僅僅包含在已分配塊的點陣圖中.我們試圖為之分
配新數據塊文件所對應的VFS inode包含兩個EXT2特殊域:prealloc_block和
prealloc_count,它們分別代表第一個預先分配數據塊的塊號以及各自的數
目.如果沒有使用預先分配塊或塊預先分配數據塊策略,則EXT2文件系統必
須分配一個新塊.它檢查此文件一個塊后的數據塊是否空閑.從邏
輯上來說這是讓其順序訪問更快的最有效塊分配策略.如果此塊已被使用則
它會在理想塊周圍64個塊中選擇一個.這個塊雖然不是最理想但和此文件的
其它數據塊都位於同一個數據塊組中.

如果此塊還是不空閑則進程將在所有其它數據塊組中搜尋,直到找到一空閑
塊.塊分配代碼將在某個數據塊組中尋找一個由8個空閑數據塊組成的簇.如
果找不到那麼它將取更小的尺寸.如果使用了塊預先分配則它將更新相應的


prealloc_block和prealloc_count.

找到空閑塊后塊分配代碼將更新數據塊組中的點陣圖並在buffer
cache中為它分配一個數據緩存.這個數據緩存由文件系統支撐設備的標誌符
以及已分配塊的塊號來標誌.緩存中的數據被置0且緩存被標記成dirty以顯
示其內容還沒有寫入物理磁碟.超塊也被標記為dirty以表示它已被更新
並解鎖了.如果有進程在等待這個超塊則隊列中的第一個進程將得到運行並
取得對超塊的獨佔控制.如果數據塊被填滿則進程的數據被寫入新數據塊中,
以上的整個過程將重複且另一個數據塊被分配.

9.2 虛擬文件系統(VFS)

Linux核心中虛擬文件系統和實際文件系統間的關係.此虛擬文
件系統能夠管理在任何時刻mount到系統的不同文件系統.它通過維護一
個描敘整個虛擬文件系統和實際已安裝文件系統的結構來完成這個工作.

容易讓人混淆的是VFS使用了和EXT2文件系統類似的方式:超塊和inode來描
敘文件系統.象EXT2inode一樣 VFSinode描敘系統中的文件和目錄以及VFS中
的內容和拓撲結構.從現在開始我將用VFSinode和VFS超塊來將它們和
EXT2 inode和超塊進行區分.

文件系統初始化時將其自身註冊到VFS中.它發生在系統啟動和操作系統初
始化時.這些實際文件系統可以構造到核心中也可以設計成可載入模塊.
文件系統模塊可以在系統需要時進行載入,例如VFAT就被實現成一個核心
模塊,當mount VFAT文件系統時它將被載入.mount一個基於塊設備且包含
根文件系統的文件系統時,VFS讀取其超塊.每個文件系統類型的超塊
讀取常式了解文件系統的拓撲結構並將這些信息映射到VFS超塊結構中.
VFS在系統中保存著一組已安裝文件系統的鏈表及其VFS超塊.每個VFS


超塊包含一些信息以及一個執行特定功能的函數指針.例如表示一個已安裝
EXT2文件系統的超塊包含一個指向EXT2相關inode讀常式的指針.這個EXT2
inode讀常式象所有文件系統相關讀常式一樣填充了VFS inode中的域.每個
VFS超塊包含此文件系統中第一個VFS inode的指針.對於根文件系統此inode
表示的是"/"目錄.這種信息映射方式對EXT2文件系統非常有效但是對其它
文件系統要稍差.

系統中進程訪問目錄和文件時將使用系統調用遍歷系統的VFS inode.

例如鍵入ls或cat命令則會引起虛擬文件系統對錶示此文件系統的VFS inode
的搜尋.系統中每個文件與目錄都使用一個VFS inode來表示,
多inode會被重複訪問.這些inode被保存在inode cache中以加快訪問速度.
如果某個inode不在inode cache中則調用一個文件系統相關常式來讀取
此inode.對這個inode的讀將把此它放到inode cache中以備下一次訪問.
不經常使用的VFS inode將會從cache中移出.

所有Linux文件系統使用一個通用buffer cache來緩衝來自底層設備的數
據以便加速對包含此文件系統的物理設備的存取.

這個buffer
cache與文件系統無關並被集成到Linux核心分配與讀寫數據緩存的機制中.
讓Linux文件系統獨立於底層介質和設備驅動好處很多.所有的塊結構設備
將其自身註冊到Linux核心中並提供基於塊的一致性非同步介面.象SCSI設備
這種相對複雜的塊設備也是如此.當實際文件系統從底層物理磁碟讀取數
據時,塊設備驅動將從它們所控制的設備中讀取物理塊.buffer cache也
被集成到了塊設備介面中.當文件系統讀取數據塊時它們將被保存在由?nbsp;
有文件系統和Linux核心共享的全局buffer cache中.這些buffer由其塊


號和讀取設備的設備號來表示.當某個數據塊被頻繁使用則它很可能
能從buffercache而不是磁碟中讀取出來,後者顯然將花費更長的時間.有
些設備支持通過預測將下一次可能使用的數據提前讀取出來.

VFS還支持一種目錄cache以便對經常使用的目錄對應的inode進行快速查
找.我們可以做一個這樣的實驗,我們對一個最近沒有執行過列目錄
操作的目錄進行列目錄操作.第一次列目錄時你可能發現會有較短的停頓
但第二次操作時結果會立刻出現.目錄cache不存儲目錄本身的inode;這
些應該在inodecache中,目錄cache 僅僅保存全目錄名和其inode號之間的
映射關係.

9.2.1 VFS 超塊

每個已安裝的文件系統由一個VFS超塊表示;它包含如下信息:

Device
表示文件系統所在塊設備的設備標誌符.例如系統中第一個IDE硬碟的
設備標誌符為0x301.
Inode pointers
這個mounted inode指針指向文件系統中第一個inode.而covered
inode指針指向此文件系統安裝目錄的inode.根文件系統的VFS超塊不
包含covered指針.
Blocksize
以位元組記數的文件系統塊大小,如1024位元組.
Superblock operations
指向此文件系統一組超塊操縱常式的指針.這些常式被VFS用來讀寫
inode和超塊.
File System type
這是一個指向已安裝文件系統的file_system_type結構的指針.
File System specific
指向文件系統所需信息的指針.

9.2.2 The VFS Inode

和EXT2文件系統相同,VFS中的每個文件、目錄等都用且只用一個VFS
inode表示.每個VFS
inode中的信息通過文件系統相關常式從底層文件系統中得到.VFS
inode僅存在於核心內存並且保存只要對系統有用,它們就會被保存在在VFS
inode cache中.每個VFS inode包含下列域:



device
包含此文件或此VFS inode代表的任何東西的設備的設備標誌符.
inode number
文件系統中唯一的inode號.在虛擬文件系統中device和inode號的組
合是唯一的.
mode
和EXT2中的相同, 表示此VFS inode的存取許可權.
user ids
所有者的標誌符.
times
VFS inode 創建、修改和寫入時間.
block size
以位元組計算的文件塊大小,如1024位元組.
inode operations
指向一組常式地址的指針.這些常式和文件系統相關且對此inode執行
操作,如截斷此inode表示的文件.
count
使用此VFS
inode的系統部件數.一個count為0的inode可以被自由的丟棄或重新使用.
lock 用來對某個VFS inode加鎖,如用於讀取文件系統時.
dirty 表示這個VFS inode是否已經被寫過,如果是則底層文件系統需要更新.
file system specific information

9.2.3 註冊文件系統


當重新建立Linux核心時安裝程序會詢問是否需要所有可支持的文件系統.核
心重建時文件系統啟動代碼包含了所有那些編入核心的文件系統的初始化常式.

Linux文件系統可構造成模塊,此時它們會僅在需要時載入或者使用insmod來載
入.當文件系統模塊被載入時,它將向核心註冊並在卸載時撤除註冊.每個文件
系統的初始化常式還將向虛擬文件系統註冊,它用一個包含文件系統名稱和
指向其VFS超塊讀常式的指針的file_system_type結構表示.每個file_system_type
結構包含下列信息:

Superblock read routine
此常式載文件系統的一個實例被安裝時由VFS調用.
File System name
文件系統的名稱如ext2.
Device needed
文件系統是否需要設備支持.並不是所有的文件系統都需要設備來保存
它.例如/proc文件系統不需要塊設備支持.



你可以通過查閱/proc/filesystems可找出已註冊的文件系統,如:

ext2
nodev proc
iso9660

9.2.4 安裝文件系統

當超級用戶試圖安裝一個文件系統時,Linux核心使系統調用中的參數有效
化.儘管mount程序會做一些基本的檢查,但是它並不知道核心構造時已經支持
那些文件系統,同時那些建議的安裝點的確存在.看如下的一個mount命令:

$ mount -t iso9660 -o ro /dev/cdrom /mnt/cdrom

mount命令將傳遞三個參數給核心:文件系統名,包含文件系統的物理塊設備以
及此新文件系統要安裝到的已存在的目錄名.

虛擬文件系統做的是找到此文件系統.它將通過由鏈指針file_systems
指向的file_system_type結構來在所有已知文件系統中搜尋.

如果找到了一個相匹配的文件系統名,那麼它就知道核心支持此文件系統
並可得到讀取此文件系統超塊相關常式的指針.如果找不到,但文件系統
使用了可動態載入核心模塊,則操作仍可繼續.此時核心將請求核心後台
進程載入相應的文件系統模塊.

接下來如果由mount傳遞的物理設備還沒有安裝,則找到新文件系統
將要安裝到的那個目錄的VFS inode. 這個VFSinode可能在inode
cache中也可能在支撐這個安裝點所在文件系統的塊設備中.一旦找到這
個inode則將對它進行檢查以確定在此目錄中是否已經安裝了其它類型的
文件系統.多個文件系統不能使用相同目錄作為安裝點.

此時VFS安裝代碼分配一個VFS超塊並將安裝信息傳遞到此文件系統
的超塊讀常式中.系統中所有的VFS超塊都被保存在由super_block結構
構成的super_blocks數組中,並且對應此安裝應有一個這種結構.超塊讀
常式將基於這些從物理設備中讀取的信息來填充這些VFS超塊域.對於


EXT2文件系統此信息的轉化過程十分簡便,僅需要讀取EXT2超塊並填充
VFS超塊.但其它文件系統如MS-DOS文件系統就不那麼容易了.不管哪種
文件系統,對VFS超塊的填充意味著文件系統從支持它的塊設備中讀
取描敘它的所有信息.如果塊設備驅動不能從中讀取或不包含這種類型
文件系統則mount命令會失敗.


每個文件系統用一個vfsmount結構來描敘.如圖9.6所示.它們被排入由
vfsmntlist指向的的鏈表中.

另外一個指針:vfsmnttail指向鏈表的一個入口,同時mru_vfsmnt指
針指向最近使用最多的文件系統.每個vfsmount結構中由以下部分組成:
包含此文件系統的塊設備的設備號,此文件系統安裝的目錄以及文件系統
安裝時分配的VFS超塊指針.VFS超塊指向這種類型文件系統和此文件系統
根inode的file_system_type結構.一旦此文件系統被載入,這個inode將
一直駐留在VFS inod cache中.

9.2.5 在虛擬文件系統中搜尋文件

為了在虛擬文件系統中找到某個文件的VFS inode,VFS依次解析此
文件名字中的間接目錄直到找到此VFSinode.每次目錄查找包括一個對
包含在表示父目錄VFS inode中的查找函數的調用.我們總是讓每
個文件系統的根可用並且由此系統的VFS超塊指向它,這是一個可行
方案.每次在實際文件系統中尋找inode時,文件系統將在目錄cache中
尋找相應目錄.如果在目錄cache中無相應入口則文件系統從底層文
件系統或inode cache中取得此VFS inode.

9.2.6 Creating a File in the Virtual File System

9.2.7 卸載文件系統

如果已安裝文件系統中有些文件還在被系統使用則不能卸載此文件系統.
例如有進程使用/mnt/cdrom或其子目錄時將不能卸載此文件系統.如果將


要卸載的文件系統中有些文件還在被使用,那麼在VFSinode cache中有與
其對應的VFS inode.通過在inode鏈表中查找此文件系統佔用設備的inode
來完成此工作.對應此已安裝文件系統的VFS超塊為dirty,表示它已被修
改過寫回到磁碟的文件系統中.一旦寫入磁碟,VFS超塊佔用的內
存將歸還到核心的空閑內存池中.對應的vfsmount結構將從vfsmntlist
中釋放.

9.2.8 The VFS Inode Cache

操縱已安裝文件系統時,它們的VFS inode將被連續讀寫.虛擬文件系
統通過維護一個inode cache來加速對所有已安裝文件系統的訪問.每
次VFS inode都可從inodecache中讀取出來以加速對物理設備的訪問.

VFS inode cache以散列表形式實現,其入口時指向具有相同散列值的VFS
inode鏈表.每個inode的散列值可通過包含此文件系統的底層物理設備標
志符和inode號計算出來.每當虛擬文件系統訪問一個inode時,系統將
在VFS inode cache中查找.為了在cache中尋找inode,系統先計算出其
散列值然後將其作為inode散列表的索引.這樣將得到指向一系列相同散
列值的inode鏈表.然後依次讀取每個inode直到找到那個具有相同inode
號以及設備標誌符的inode為止.

如果在cache中找到了此inode則它的count值遞增以表示用戶增加了一個,
同時文件操作將繼續進行.否則找到一個空閑VFSinode以便文件系統
能從內存中讀取此inode.VFS有許多種選擇來取得空閑inode.如果系統
可以分配多個VFSinode則它將按如下步驟進行:分配核心頁面並將其
打碎成新的空閑inode並將其放入inode鏈表中.系統所有的VFSinode都被
放到由first_inode指向的鏈表和inode散列表中.如果系統已經擁有所有
inode,則它找到便於重新使用的inode.那些inode最好count記數為0;


這種inode沒有誰在使用.很重要的VFSinode,如文件系統的根inode,
其count域總是大於0,它所使用的inode是不能被重新使用的.一旦找
到可重用inode則應清除之:其VFSinode可能為dirty,要寫入到文件系
統中或者需要加鎖,此時系統等到解鎖時才能繼續運行.

找到新的VFS
inode后調用文件系統相關常式使用從底層實際文件系統中讀出的內
容填充它.在填充過程中,此新VFSinode的count記數為1並被加鎖以排斥
其它進程對它的使用直到此inode包含有效信息為止.

為了取得真正需要的VFS
inode,文件系統可能需要存取幾類其它inode.我們讀取一個目錄時雖然
只需要一級目錄但是所有的中間目錄也被讀了出來.使用了VFS
inode cache,較少使用的inode將被丟棄而較多使用的inode將保存在cache
中.

9.2.9 目錄 Cache

為了加速對常用目錄的訪問,VFS維護著一個目錄入口cache.

當在實際文件系統尋找目錄時,有關此目錄的細節將被存入目錄cache中.
當再次尋找此目錄時,例如在此目錄中列文件名或打開文件,則這些信息
就可以在目錄cache中找到.在實際實現中只有短目錄入口(最多15個字
符)被緩存,這是那些較短目錄名的目錄正是使用最頻繁的.例如
/usr/X11R6/bin這個短目錄經常被Xserver所使用.

目錄cache也由散列表組成,每個入口指向具有相同散列值的目錄cache人
口鏈表.散列函數使用包含此文件系統的設備號以及目錄名稱來計算在此
散列表中的偏移值或者索引值,這樣能很快找到被緩存的目錄.
如果在cache中的搜尋消耗的時間太長或者甚至沒有找到則使用此cache用
處不大.

為了保證cache的有效性和及時更新,VFS保存著一個最近最少使用(LRU)


的目錄cache人口鏈表.當首次查找此目錄時其目錄入口被首次放入cache中
並添加到第一級LRU鏈表的尾部.在已經充滿的cache中它代替位於LRU鏈表
最前端的現存入口.此目錄入口被再次使用時它將被放到第二級LRUcache鏈
表的.此時需要將位於第二級LRU cache鏈表的最前端的那個替換掉.
入口在鏈表前端的唯一原因是它們已經很久沒被訪問過了.如果被訪問過那
么它們將位於此鏈表的尾部附近.位於第二級LRUcache鏈表中的入口要比
位於第一級LRU cache鏈表中的安全一些.

9.3 The Buffer Cache


操縱已安裝文件系統將產生大量對此塊設備的讀寫請求.這些塊讀寫請求
都是通過標準核心常式調用以buffer_head結構形式傳遞到設備驅動中.它
們提供了設備驅動所需的所有信息:表示設備的設備標誌符以及請求的塊號.
所有塊設備都被看成相同塊大小的線性塊集合.為了加速對物理塊設備的訪問,
Linux使用了一個塊buffer cache.系統中全部的塊緩衝,包括那些沒使用
過的新緩衝都保存在此buffercache中.這個cache被多個物理塊設備共享;
任何時刻此cache中都有許多屬於不同系統塊設備且狀態不同的塊緩衝.如果
有效數據可以從buffer cache中找到則將節省大量訪問物理設備的時間.任
何對塊設備讀寫的塊緩衝都被放入此cache中.隨時間的變化有些塊緩衝可能
將會被此cache中刪除以為更需要它的緩衝騰出空間,如果它被頻繁使用則可
以一直保存在此cache中.

此cache中的塊緩衝由設備標誌符以及緩衝對應的塊號來唯一的表示.它由兩
個功能部分組成.其一是空閑塊緩衝鏈表.它為每個可支持的塊大小提供了一
個鏈表並且系統中的空閑塊緩衝在創建或者被丟棄時都被排入此鏈表中.當前


可支持的塊大小為512、1024、2048、4096與8192位元組.其二是cache自身.它
是用一組指向具有相同散列索引值的緩衝鏈的散列表.這個散列索引值通過其
自身的設備標誌符與數據塊設備的塊號來產生.圖9.7給出了一個帶有一些入口
的散列表.塊緩衝要麼在空閑鏈表中要麼在此buffer cache中.如果在buffer
cache中則它們按照最近最少使用(LRU)鏈表來排列.對於每種緩衝類型都?nbsp;
一個LRU鏈表,系統使用它們來對某種緩衝進行操作,如將帶新數據的緩衝寫
入到磁碟上.緩衝的類型表示其當前狀態,Linux現在支持韻錄欣嘈停?nbsp;

clean 未使用的新緩衝
locked
等待寫入且加鎖的緩衝
dirty dirty緩衝.它們包含新的有效數據,但目前沒被調度執行寫操作.
shared
共享緩衝
unshared
以前被共享但現在沒有被共享的緩衝

當文件系統需要從其底層物理設備讀取一個緩衝塊時,它將在buffer
cache里尋找.如果在此buffercache中找不到則它將從適當大小的空閑鏈中
取得一個clean狀態的節點,同時將新緩衝添加到buffer cache 中去.如果
所需的緩衝位於buffercache中,那麼它可能已經或沒有更新.如果沒有被
更新或者它為新塊則文件系統請求相應的數據驅動從磁碟中讀取該數據塊.


為了讓此buffer cache運行更加有效並且在使用此buffercache的塊設備
之間合理的分配cache入口,系統對其進行維護.Linux使用bdflush
核心後台進行來對此cache執行許多瑣碎工作,但有時作為使用cache的結
構自動進行.

9.3.1 bdflush 核心後台進程

bdflush是對過多的dirty緩衝系統提供動態響應的簡單核心後台進程;這
些緩衝塊中包含被寫入到硬碟上的數據.它在系統啟動時作為一個核


心線程運行,其名字叫"kflushd".你可以使用ps命令看到此系統進程.通
常情況下此進程一直在睡眠直到系統中的dirty緩衝數目增大到一定數目.
當分配與丟棄緩衝時,系統中dirty緩衝的數目將做一個統計.如果其數目
超過某個數值則喚醒bdflush進程.預設的閥值為60%,但是如果系統急
需緩衝則任何時刻都可能喚醒bdflush.
使用update命令可以看到和改變這個數值.

# update -d

bdflush version 1.4
0: 60 Max fraction of LRU list to examine for dirty blocks
1: 500 Max number of dirty blocks to write each time bdflush activated
2: 64 Num of clean buffers to be loaded onto free list by refill_freelist
3: 256 Dirty block threshold for activating bdflush in refill_freelist
4: 15 Percentage of cache to scan for free clusters
5: 3000 Time for data buffers to age before flushing
6: 500 Time for non-data (dir, bitmap, etc) buffers to age before flushing
7: 1884 Time buffer cache load average constant
8: 2 LAV ratio (used to determine threshold for buffer fratricide).


但有數據寫入緩衝使之變成dirty時,所有的dirty緩衝被連接到一個BUF_DIRTY
LRU鏈表中,bdflush會將適當數目的緩衝塊寫到磁碟上.這個數值的預設值為500.

9.3.2 update進程

update命令不僅僅是一個命令;它還是一個後台進程.當作為超級用戶運行時
(在系統初始化時)它將周期性調用系統服務常式將老的dirty緩衝沖刷到磁碟上
去.它所完成的這個工作與bdflush類似.當一個dirty緩衝完成此操作后,它將
把本應寫入到各自磁碟上的時間標記到其中.update每次運行時它將在系統的所
有dirty緩衝中查找那些沖刷時間已過期的.這些過期緩衝都被寫入到磁碟.

9.4 /proc文件系統

/proc文件系統真正顯示了Linux虛擬文件系統的能力.事實上它並不存在-不管


時/proc目錄還是其子目錄和文件都不真正的存在.但是我們是如何能夠執行cat
/proc/devices命令的?/proc文件系統象一個真正的文件系統一樣將向虛擬文件
系統註冊.然而當有對/proc中的文件和目錄的請求發生時,VFS系統將從核心中
的數據中臨時構造這些文件和目錄.例如核心的/proc/devices文件是從描敘其
設備的內核數據結構中產生出來./proc文件系統提供給用戶一個核心內部工作的
可讀窗口.幾個Linux子系統,如在modules一章描敘的Linux核心模塊都在/proc
文件系統中創建入口.



9.5 設備特殊文件

和所有Unix版本一樣Linux將硬體設備看成特殊的文件.如/dev/null表示一個空
設備.設備文件不使用文件系統中的任何數據空間,它僅僅是對設備驅動的訪問
入口點.EXT2文件系統和Linux VFS都將設備文件實現成特殊的inode類型.有兩
種類型的設備文件:字元與塊設備特殊文件.在核心內部設備驅動實現了類似文
件的操作過程:我們可以對它執行打開、關閉等工作.字元設備允許以字元模式
進行I/O操作而塊設備的I/O操作需要通過buffer cache.當對一個設備文件發
出的I/O請求將被傳遞到相應的設備驅動.常常這種設備文件並不是一個真正的設
備驅動而僅僅是一個偽設備驅動,如SCSI設備驅動層.設備文件通過表示設備類
型的主類型標誌符和表示單元或主類型實例的從類型來引用.例如在系統中第一
個IDE控制器上的IDE硬碟的主設備號為3而其第一個分區的從標誌符為1.
行ls-l /dev/hda1將有如下結果:

$ brw-rw---- 1 root disk 3, 1 Nov 24 15:09 /dev/hda1

在核心內部每個設備由唯一的kdev_t結構來表示,其長度為兩位元組,首位元組包含
從設備號而尾位元組包含主設備號.


上例中的核心IDE設備為0x0301.表示塊或者字元設備的EXT2inode在其第一個
直接塊指針包含了設備的主從設備號.當VFS讀取它時,表示它的VFS inode結構
的i_rdev域被設置成相應的設備標誌符.





[火星人 via ] linux bible 第九章 文件系統已經有360次圍觀

http://www.coctec.com/docs/linux/show-post-57932.html