VFS作為核心子系統,為使用者空間程式提供了檔案系統的操作介面.VFS是使用者空間到具體檔案系統(EXT3)的一個介面中間層.

12.1 通用檔案系統介面

VFS最大的意義就是使用使用者空間可以直接使用open()read()write()等等函式而不需要考慮具體的檔案系統(YAFFS,ext2).

12.2 檔案系統抽象層

LINUX之所以可以做到對所有型別的檔案系統(比如ext3,yaffs)進行操作,是因為核心在它的底層檔案系統介面上建立了一個抽象層.VFS抽像層介面之所以銜接各種各樣的檔案系統,是因為它定義了所有檔案系統都支援的基本的、概念上的介面和資料結構.同時實際的檔案系統也將自身的諸如"如何開啟檔案""目錄是什麼"等概念在形式上與VFS的定義保持一致,一些建立檔案刪除目錄的介面與VFS的定義保持一致.

下面以一個簡單的使用者空間程式執行來看大致的流程:

Write(f,&buf,len);

該程式碼將&buf指標指向的、長度為len位元組的資料寫入檔案描述符f對應的檔案的當前位置.這個使用者呼叫首先被一個通用系統呼叫sys_write()處理,sys_write()函式要找到f所在的檔案系統實際給出的哪個寫操作,然後再執行該操作.實際檔案系統的寫方法是檔案系統實現的一部分,資料最終是通過該操作寫入介質的.一方面,系統呼叫是通用的VFS介面,提供使用者空間的前端;另一方面,系統呼叫的是具體檔案系統的後端,處理實現細節.

12.3 Unix檔案系統

Unix使用了四種和檔案系統相關的傳統抽象概念:檔案、目錄項、索引節點和安裝點.

檔案系統:本質上講是特殊的資料分層儲存結構,它包含檔案、目錄和相關的控制資訊.還有通用的操作,如建立、刪除和安裝等等;

檔案:可以看作是一個有序位元組串,位元組串中第一個位元組是檔案頭,最後一個位元組是檔案的尾.每一個檔案為了便於系統和使用者識別,都被分配了一個便於理解的名字.典型的檔案操作有讀、寫、建立和刪除等.

目錄項:LINUX中目錄、子目錄和檔案都統稱為目錄項;

索引節點:Unix系統將檔案的相關資訊和檔案本身這兩個概念加以區分,如訪問控制權限、大小、擁有者、建立時間等資訊.這些資訊被存放在結構體inode.

超級塊:檔案系統的控制資訊儲存在超級塊中,超級塊是一種包含檔案系統資訊的資料結構.

12.4 VFS物件及其資料結構

VFS中有四個主要的物件型別,它們分別是:

.超級塊物件,它程式碼一個已經安裝的檔案系統;

.索引節點物件,它代表一個檔案;

.目錄項物件,它代表一個目錄項,是路徑的一個組成部分;

.檔案物件,它代表由程序開啟的檔案

上述四個物件每個物件都對應一種操作方法:

.super_operations物件,其中包括核心針對特定檔案系統所能呼叫的方法,read_inode()sync_fs();

.inode_operations物件,其中包括核心針對特定檔案所能呼叫的方法,比如create()link()等方法;

.dentry_operations物件,其中包括核心針對特定目錄所能呼叫的方法,比如d_compare()d_delete()等方法;

.file物件,其中包括程序針對已開啟檔案所能呼叫的方法,比如read()write()等方法.

其他VFS物件

.file_system_type結構體來表示每個註冊的檔案系統;

.vfsmount結構體表示每一個安裝點.

.與程序相關的:file_structfs_structnamespace.

12.5 超級塊物件

各種檔案系統必須實現超級塊,該物件用於儲存特定的檔案系統的資訊,通常對存放於磁碟特定扇區中.像基於記憶體的檔案系統(sysfs)會在現場建立;

超級塊物件由super_block結構體表示,定義在檔案<linux/fs.h>,如下:

建立、管理和銷燬超級塊物件的程式碼位於fs/super.c.超級塊物件通過alloc_super()函式建立並初始化.

超級塊的操作

超級塊物件中最重要的一個域是s_op,它指向超級塊的操作函式表.super_operations結構體表示,定義在<linux/fs.h>.如下:

當檔案系統需要對其超級塊操作時,首先要在超級塊物件中尋找需要的操作方法.比如,如果一個檔案系統要寫自己的超級塊,需要呼叫:

Sb->s_op->write_super(sb);

12.6 索引節點物件

索引節點物件包含了核心在操作檔案或目錄時需要的全部資訊.

索引節點物件由結構體struct inode表示,定義於<linux/fs.h>.

一個索引節點代表檔案系統中(雖然索引節點僅當檔案被訪問時才在記憶體建立)的一個檔案,它可以是裝置或管道這樣的特殊檔案.比如i_pipe域就指向一個代表命名管道的資料結構.當然還有i_devices,i_bdevi_cdev.

索引節點的操作由inode_operations項表示.對索引節點的呼叫方式如下:

I->i_op->truncate(i)

I指向給定的索引節點,truncate()函式由索引節點i所在的檔案系統提供操作.如下:

可見,這裡封裝了我們常見的一些對目錄或檔案的操作方法.比如說建立一個目錄,mkdir.

12.7 目錄項物件

VFS把目錄當作檔案對待,比如說路徑/bin/vi,binvi都屬於檔案--bin是特殊的目錄檔案而vi是一個普通的檔案,路徑中的每個組成部分都由一個索引節點物件表示.

目錄項物件的出現是LINUX為了方便對檔案的查詢.由結構體struct dentry表示.上述中/,binvi都屬於目錄項物件.因此,在路徑中,包括普通檔案在內,每一部分都是目錄項物件.如下:

目錄項狀態

目錄項狀態有三種:被使用、未被使用和負狀態.

被使用:一個被使用的目錄項對應一個有效的索引節點且表明該物件存在一個或多外使用者;

未使用:對應一個有效物件,但是VFS沒使用它,且被儲存在快取中以便需要時再使用它;

負狀態:沒有對應的有效索引節點,該節點有可能已經被刪除或路徑不正確了.

目錄項快取

如果VFS層遍歷路徑名中所有元素並將它們逐個解析成目錄項物件,是一件很費時費力的工作.所以核心將目錄項物件快取在目錄項快取中.是一種提高目錄項查詢的策略.

目錄項操作集

12.8 檔案物件

檔案物件表示程序已經開啟的檔案在記憶體中的表示.該物件(不是物理檔案)由相應的open()系統呼叫建立,close()系統呼叫銷燬.目錄項物件才對應一個實際的物理檔案.因此,一個檔案對應的檔案物件不是唯一的,但對應的索引節點和目錄項物件是唯一的.

檔案物件由結構體struct file表示.如下:

檔案物件的操作由結構體struct file_operations表示.

我們熟悉的open(),close(),read(),write()等函式都是基於檔案物件操作的.

12.9 和檔案系統相關的資料結構

LINUX之所以可以支援多種不同的檔案系統,必須有一定的標準介面讓具體的檔案系統去接入.LINUXstruct file_system_type來表徵一個檔案系統.如下:

當一個檔案系統被實際安裝時,將有一個vfsmount結構體在安裝點被建立.該結構體用來代表檔案系統的例項.定義於<linux/mount.h>如下:

12.10 和程序相關的資料結構

系統中每一個程序都有自己的一組開啟的檔案,像根檔案系統、當前工作目錄、安裝點等.有三個資料結構將VFS層和系統的程序緊密聯絡一起的,它們分別是:files_structfs_structnamespace結構體.

Files_struct:定義於<linux/file.h>,該結構體由程序描述符中的files域指向.如下:

Struct fs_struct結構體由程序描述符fs域指向.它包含檔案系統和程序相關資訊.定義在檔案<linux/fs_struct.h>.如下:

該結構包含了當前程序的當前工作目錄(pwd)和根目錄.

Struct namespace定義於<linu/namespce.h>.由程序描述符中的namespace域指向.

意為程序的名字空間.