本文参考了: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 对象,而不须要设计底层的文件系统。