您的位置:首页 > 运维架构 > Linux

LINUX内核设计与实现之虚拟文件系统

2013-11-08 11:41 295 查看
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_struct、fs_struct和namespace.

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_bdev和i_cdev等.

索引节点的操作由inode_operations项表示.对索引节点的调用方式如下:

I->i_op->truncate(i)

I指向给定的索引节点,truncate()函数由索引节点i所在的文件系统提供操作.如下:



可见,这里封装了我们常见的一些对目录或文件的操作方法.比如说创建一个目录,mkdir.

12.7 目录项对象

VFS把目录当作文件对待,比如说路径/bin/vi中,bin和vi都属于文件--bin是特殊的目录文件而vi是一个普通的文件,路径中的每个组成部分都由一个索引节点对象表示.

目录项对象的出现是LINUX为了方便对文件的查找.由结构体struct dentry表示.上述中/,bin和vi都属于目录项对象.因此,在路径中,包括普通文件在内,每一部分都是目录项对象.如下:



目录项状态

目录项状态有三种:被使用、未被使用和负状态.

被使用:一个被使用的目录项对应一个有效的索引节点且表明该对象存在一个或多外使用者;

未使用:对应一个有效对象,但是VFS没使用它,且被保存在缓存中以便需要时再使用它;

负状态:没有对应的有效索引节点,该节点有可能已经被删除或路径不正确了.

目录项缓存

如果VFS层遍历路径名中所有元素并将它们逐个解析成目录项对象,是一件很费时费力的工作.所以内核将目录项对象缓存在目录项缓存中.是一种提高目录项查找的策略.

目录项操作集



12.8 文件对象

文件对象表示进程已经打开的文件在内存中的表示.该对象(不是物理文件)由相应的open()系统调用创建,由close()系统调用销毁.目录项对象才对应一个实际的物理文件.因此,一个文件对应的文件对象不是唯一的,但对应的索引节点和目录项对象是唯一的.

文件对象由结构体struct file表示.如下:



文件对象的操作由结构体struct file_operations表示.



我们熟悉的open(),close(),read(),write()等函数都是基于文件对象操作的.

12.9 和文件系统相关的数据结构

LINUX之所以可以支持多种不同的文件系统,必须有一定的标准接口让具体的文件系统去接入.LINUX用struct file_system_type来表征一个文件系统.如下:



当一个文件系统被实际安装时,将有一个vfsmount结构体在安装点被创建.该结构体用来代表文件系统的实例.定义于<linux/mount.h>如下:



12.10 和进程相关的数据结构

系统中每一个进程都有自己的一组打开的文件,像根文件系统、当前工作目录、安装点等.有三个数据结构将VFS层和系统的进程紧密联系一起的,它们分别是:files_struct、fs_struct和namespace结构体.

Files_struct:定义于<linux/file.h>中,该结构体由进程描述符中的files域指向.如下:



Struct fs_struct结构体由进程描述符fs域指向.它包含文件系统和进程相关信息.定义在文件<linux/fs_struct.h>中.如下:



该结构包含了当前进程的当前工作目录(pwd)和根目录.

Struct namespace定义于<linu/namespce.h>中.由进程描述符中的namespace域指向.

意为进程的名字空间.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: