本文參考了:node
Linux 的成功有一部分緣由在於可以很好的支持不一樣的文件系統,你可以輕鬆透明地把 Windows、其餘 Unix 系統、甚至是佔有極小份額的 Amiga 使用的文件系統 mount
到Linux 的文件系統中。這是經過Virtual Filesystem
(如下簡稱 VFS)實現的。bash
VFS 背後的 idea 是在 kernel 中抽象出不一樣文件系統,針對具體的文件系統,Linux kernel 實現具體的操做方法。當系統調用read
、write
發生時,kernel 根據操做的具體文件系統,好比 native Linux文件系統、NTFS(Windows NT)等,調用相對應的函數。數據結構
cp
要執行一個cp
指令:ide
cp /floppy/TEST /tmp/test
複製代碼
其中/floppy
是一個 mount 的MS-DOS文件系統,而/tmp
是 ext2。VFS 就是應用程序和底層文件系統實現之間的一個抽象層,cp
不須要知道/floppy/TEST
個/tmp/test
的文件系統類型,它只須要調用標準的系統調用,好比read
、write
這些,把底層文件系統不一樣帶來的複雜度交給 kernel。函數
示例的代碼以下:ui
inf = open("/floppy/TEST", O_RDONLY, 0);
outf = open("/tmp/test",
O_WRONLY|O_CREAT|O_TRUNC, 0600);
do {
i = read(inf, buf, 4096);
write(outf, buf, i);
} while (i);
close(outf);
close(inf);
複製代碼
示意圖:編碼
代碼和截圖來源於 《Understanding the Linux Kernel, Third Edition》 P457idea
VFS 支持嗯文件系統一共分爲下面三大類:spa
本地的 disk。包括:翻譯
這一類支持訪問遠程的文件系統,好比 NFS、Coda、AFS 等。
如/proc
虛擬文件系統。
一般來講,root 目錄爲 Linux 原生的ext2
、ext3
、ext4
,其餘類型的文件系統經過mount
形式 mount 到某個特定子目錄。
VFS 背後的核心idea: 用common file model表示全部現實中的FS。這個模型嚴格使用原生Unix FS 模型,每一個特定的 FS 都須要將本身的硬件結構翻譯成 common file model。
好比在 common file model 中,目錄也被看作文件,包含其餘的文件盒目錄。然而,一些非 Unix 的 FS,使用的是 file allocation table(FAT),這種狀況下,目錄不是文件。可是爲了遵循 common file model的規則,Linux 對這種 FAT-based 的 FS,必須可以抽象出一個遵循common file model 的接口。
更加具體點,Linux kernel 在處理read
、ioctl
這些系統調用的時候,不能直接硬編碼,使用某個特定的底層函數。kernel實際上針對每個操做,使用的是一個指針,這個指針指向了針對此文件系統專門的處理函數。
讓咱們來看看kernel 是如何完成上面提到的cp
操做的。
應用層調用read()
,kernel 實際上會調用sys_read()
service routine(其餘的系統調用也同樣)。MS-DOS FS 的文件被 kernel memory 中的一個數據結構表示,這個數據結構包含一個f_op
字段,指向的是針對 MS-DOS 的 read 函數。sys_read()
找到這個函數而後調用它。因此整個過程能夠看做是:
read() -> sys_read() -> file data structure -> f_op -> read_for_msdos()
複製代碼
調用write()
也同樣,這個系統調用會觸發針對ext2
FS 的寫調用。
簡要來講,對於每一個 open()建立的 file object,kernel 須要負責正確賦值此 file object的指針,指向針對此文件系統的特定函數,而後調用這些函數。
VFS 是應用和特定文件系統之間的一層抽象,有些操做可以直接在 VFS 層完成,不須要涉及到底層的具體文件系統。好比說,當進程close file的時候,disk 上的文件自己是不會改變的,因此 VFS 只要把對應的 file 對象釋放掉就好了。再好比說,lseek()
系統調用,改變的也是內存中的 file 對象,而不須要設計底層的文件系統。