與其它系統完美共存是linux的成功之處之一,linux可以透明掛載其它系統檔案格式的磁碟或分區,如Windows的FAT32、NTFS等;
linux使用虛擬檔案系統VFS(Virtual Filesystem Switch)來支援多種類型的檔案系統。
VFS的思想是:將不同類型檔案系統資訊存放到核心中,linux所有檔案系統支援的每個操作都有一個域與之對應,當讀、寫或其它功能調用時核心將該域替換成具體檔案系統的操作。
如ext4_file_open表示EXT4檔案開啟操作,ntfs_file_open表示NTFS檔案開啟操作;域open表示所有檔案系統的檔案開啟操作,在開啟EXT4檔案系統檔案時將open替換成ext4_file_open,在開啟NTFS檔案系統檔案時將open替換成ntfs_file_open;這樣就能實現統一介面open開啟不同格式檔案系統的檔案。
I.VFS作用
VFS提供不同檔案系統的統一介面,將檔案系統相關的系統調用與具體檔案系統操作分開,系統調用通過VFS來操作具體檔案系統的檔案。
如,使用以下命令:
$ cp /floppy/TEST /tmp/test
/floppy是MS-DOS盤的掛載點,/tmp是EXT2目錄;因為VFS是系統調用(應用程式)與檔案系統實現之間的抽象層,所以cp不需要知道/floppy/TEST與/tmp/test的檔案系統類型,只會與VFS互動。
VFS在檔案拷貝過程中作用如下圖:
i.通用檔案模型
VFS使用通用檔案模型來表示所有的檔案系統,所有檔案系統的實現都必須將自己的物理結構轉換成VFS通用檔案模型。
例如,通用檔案模型將目錄當作內容是一系統檔案和目錄的檔案;但是,有些非UNIX檔案系統使用FAT來隱藏檔在分類樹中的位置,這些檔案系統中目錄不是檔案;為了遵循通用檔案模型,基於FAT的檔案系統必須構造目錄對應的檔案(這些檔案只存在核心記憶體中)。
核心不能寫入程式碼某個函數來處理read,ioctl等操作,必須使用指標指向具體檔案系統相應的函數,來實現這些操作。
如系統調用read,核心會調用sys_read;進而會調用file的讀操作,file->f_op->read(...),而f_op就是指向具體檔案系統檔案操作的指標,這樣就能使用統一的檔案系統介面來操作檔案。
有些情況,VFS自己就能完成檔案操作,而不需要依賴底層具體的檔案系統;如關閉開啟的檔案,VFS只需要釋放記憶體中的file對象,而不需要磁碟檔案操作;同樣,lseek只是改變file對象中的指標,也不需要磁碟檔案操作。所以可以把VFS當做通用檔案系統,如有必要VFS才會使用具體的檔案系統。
可以把通用檔案模型視作是物件導向的,使用包含資料與函數指標的結構體來實現物件導向編程。
通用檔案模型主要有以下物件類型:
superblock:儲存掛載的檔案系統資訊;基於磁碟的檔案系統,superblock通常對應磁碟上的檔案系統控制塊
dentry:儲存目錄項與檔案的關聯資訊;基於磁碟的檔案系統,使用不同的方式儲存該資訊
inode:儲存檔案的資訊;基於磁碟的檔案系統,inode通常對應檔案控制區;每個inode有一個唯一的inode number,用來標識檔案系統中的檔案。
file:儲存進程與開啟檔案的互動資訊;只有在進程開啟檔案時,核心記憶體中才會有file對象
下圖闡述進程操作檔案時這幾種對象之間的關係:
三個進程開啟了相同的檔案,有兩個硬串連指向該檔案(兩個目錄項指向該檔案),其中兩個進程使用其中一個硬串連,另一進程使用另外一個硬串連。
每個進程使用自己的file對象,2個硬串連使用2個dentry對象,2個dentry使用同一個inode;inode標識出superblock,並與superblock一起標識出磁碟檔案。
ii.緩衝加速
VFS除了提供統一的檔案系統介面外,同時在系統效能上也有重要作用。
1.將最近使用的dentry對象放在dentry緩衝中,來加速檔案的尋找;
2.將檔案內容儲存在頁緩衝中,來加速檔案操作;
II.VFS資料結構
VFS對象儲存在相應的資料結構中,既包含對象屬性,也包含對象方法列表指標;核心會動態修改對象方法列表指標,進而實現對象的多態。
下圖是VFS涉及的主要對象結構及它們之間的關係: