您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > Linux的虚拟文件系统及实例XORFS
Linux的虚拟文件系统及实例XORFSLinux的虚拟文件系统用户视角下的文件系统“一切皆是文件”,是UNIX和Linux的基本哲学之一。Linux对于文件I/O操作,实现了POSIX.1和SingleUNIXSpecification中的接口,包括open()、read()、write()、lseek()和close()等方法。正是由于Linux所实现的虚拟文件系统对具体文件系统进行了抽象,使得Linux可以方便地实现文件I/O操作接口。用户视角下的文件系统,就是一组系统调用接口,其与VFS的关系如下:每个进程在用户空间内都有一张filedescriptiontable,用于描述已打开的文件。当open()成功返回时,将返回文件描述符(filedescription),被插入到filedescriptiontable中。如下图所示,当用户进程调用write()方法读取文件时,将调用VFS的sys_write()方法,而在sys_write()方法中调用文件系统接口的具体方法进行硬盘读取。在Linux2.6.25以后,sys_write()为vfs_write()所替代。vfs_write()源代码如下:由此可见,write的调用过程为:→write()→vfs_write()→file-f_op-write(),由文件系统提供的VFSAPI进行实际的存取操作。硬盘视角下的文件系统Linux在硬盘上的文件系统与逻辑上的文件系统VFS完全不同。UFS(UNIXFileSystem)基于Berkeleyfastfilesystem,如下:UFS由许多分区构成,可以允许分区之间采取不同的文件系统,但同一个分区之内必须为同一文件系统。上图启动块(BootBlock)大小确定,为1KB,由PC标准规定,用来存储磁盘分区信息和启动信息,任何文件系统都不能使用启动块。UFS文件系统将整个分区划分成超级块(SuperBlock,除块组0之外的SuperBlock都为备份)、块描述符表、i-node位图、块位图、i-node表、data数据块。超级块包含了关于该硬盘或分区文件系统的整体信息,如文件系统大小等。索引结点,包含了针对某一具体文件几乎的全部信息,如文件存取权限、所有者、大小、建立时间以及对应的目录块和数据块等。数据块是真正存储文件内容的位置,但索引结点中不包括文件名,文件名存于目录块。目录块里包含文件名以及文件索引结点编号。上图中,位于数据块中存储目录数据的directoryentry均指向同一个i-node,而i-node中包括三个datablock。内核虚拟文件系统VFS内核文件系统主要的四个数据结构为:superblock,代表一个具体的已挂载的文件系统;inode,代表一个具体的文件;dentry,代表一个目录项,如/home/icanth,home和icanth都是一个目录项;file,代表一个进程已经打开的文件。图super_block、file、dentry和inode的关系每个file结构体都指向一个file_operations结构体,这个结构体的成员都是函数指针,指向实现各种文件操作的内核函数。比如在用户程序中read一个文件描述符,read通过系统调用进入内核,然后找到这个文件描述符所指向的file结构体,找到file结构体所指向的file_operations结构体,调用它的read成员所指向的内核函数以完成用户请求。在用户程序中调用lseek、read、write、ioctl、open等函数,最终都由内核调用file_operations的各成员所指向的内核函数完成用户请求。file_operations结构体中的release成员用于完成用户程序的close请求,之所以叫release而不叫close是因为它不一定真的关闭文件,而是减少引用计数,只有引用计数减到0才关闭文件。对于同一个文件系统上打开的常规文件来说,read、write等文件操作的步骤和方法应该是一样的,调用的函数应该是相同的,所以图中的三个打开文件的file结构体指向同一个file_operations结构体。如果打开一个字符设备文件,那么它的read、write操作肯定和常规文件不一样,不是读写磁盘的数据块而是读写硬件设备,所以file结构体应该指向不同的file_operations结构体,其中的各种文件操作函数由该设备的驱动程序实现。每个file结构体都有一个指向dentry结构体的指针,“dentry”是directoryentry(目录项)的缩写。我们传给open、stat等函数的参数的是一个路径,例如/home/akaedu/a,需要根据路径找到文件的inode。为了减少读盘次数,内核缓存了目录的树状结构,称为dentrycache,其中每个节点是一个dentry结构体,只要沿着路径各部分的dentry搜索即可,从根目录/找到home目录,然后找到akaedu目录,然后找到文件a。dentrycache只保存最近访问过的目录项,如果要找的目录项在cache中没有,就要从磁盘读到内存中。每个dentry结构体都有一个指针指向inode结构体。inode结构体保存着从磁盘inode读上来的信息。在上图的例子中,有两个dentry,分别表示/home/akaedu/a和/home/akaedu/b,它们都指向同一个inode,说明这两个文件互为硬链接。inode结构体中保存着从磁盘分区的inode读上来信息,例如所有者、文件大小、文件类型和权限位等。每个inode结构体都有一个指向inode_operations结构体的指针,后者也是一组函数指针指向一些完成文件目录操作的内核函数。和file_operations不同,inode_operations所指向的不是针对某一个文件进行操作的函数,而是影响文件和目录布局的函数,例如添加删除文件和目录、跟踪符号链接等等,属于同一文件系统的各inode结构体可以指向同一个inode_operations结构体。inode结构体有一个指向super_block结构体的指针。super_block结构体保存着从磁盘分区的超级块读上来的信息,例如文件系统类型、块大小等。super_block结构体的s_root成员是一个指向dentry的指针,表示这个文件系统的根目录被mount到哪里,在上图的例子中这个分区被mount到/home目录下。超级块对象superblocksuperblock是在linux/fs.h在下定义的结构体super_block.structsuper_block{//超级块数据结构structlist_heads_list;/*指向超级块链表的指针*/……structfile_system_type*s_type;/*文件系统类型*/structsuper_operations*s_op;/*超级块方法*/……structlist_heads_instances;/*该类型文件系统*/……};structsuper_operations{//超级块方法……//该函数在给定的超级块下创建并初始化一个新的索引节点对象structinode*(*alloc_inode)(structsuper_block*sb);……//该函数从磁盘上读取索引节点,并动态填充内存中对应的索引节点对象的剩余部分void(*read_inode)(structinode*);……};索引结点对象inode索引节点对象存储了文件的相关信息,代表了存储设备上的一个实际的物理文件。当一个文件首次被访问时,内核会在内存中组装相应的索引节点对象,以便向内核提供对一个文件进行操作时所必需的全部信息;这些信息一部分存储在磁盘特定位置,另外一部分是在加载时动态填充的。structinode{//索引节点结构……structinode_operations*i_op;/*索引节点操作表*/structfile_operations*i_fop;/*该索引节点对应文件的文件操作集*/structsuper_block*i_sb;/*相关的超级块*/……};structinode_operations{//索引节点方法……//该函数为dentry对象所对应的文件创建一个新的索引节点,主要是由open()系统调用来调用int(*create)(structinode*,structdentry*,int,structnameidata*);//在特定目录中寻找dentry对象所对应的索引节点structdentry*(*lookup)(structinode*,structdentry*,structnameidata*);……};目录项对象引入目录项的概念主要是出于方便查找文件的目的。一个路径的各个组成部分,不管是目录还是普通的文件,都是一个目录项对象。如,在路径/home/source/test.c中,目录/,home,source和文件test.c都对应一个目录项对象。不同于前面的两个对象,目录项对象没有对应的磁盘数据结构,VFS在遍历路径名的过程中现场将它们逐个地解析成目录项对象。structdentry{//目录项结构……structinode*d_inode;/*相关的索引节点*/structdentry*d_parent;/*父目录的目录项对象*/structqstrd_name;/*目录项的名字*/……structlist_headd_subdirs;/*子目录*/……structdentry_operations*d_op;/*目录项操作表*/structsuper_block*d_sb;/*文件超级块*/……};structdentry_operations{//判断目录项是否有效;int(*d_revalidate)(structdentry*,structnameidata*);//为目录项生成散列值;int(*d_hash)(structdentry*,structqstr*);……};文件对象structfile{……structlist_headf_list;/*文件对象链表*/structdentry*f_dentry;/*相关目录项对象*/structvfsmount*f_vfsmnt;/*相关的安装文件系统*/structfile_operations*f_op;/*文件操作表*/……};structfile_operations{……//文件读操作ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);……//文件写操作ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);……int(*readdir)(structfile*,void*,filldir_t);……//文件打开操作int(*open)(structinode*,structfile*);……};文件系统对象根据文件系统所在的物理介质和数据在物理介质上的组织方式来区分不同的文件系统类型的。file_system_type结构用于描述具体的文件系统的类型信息。被Linux支持的文件系统,都有且仅有一个file_system_type结构而不管它有零个或多个实例被安装到系统中。而与此对应的是每当一个文件系统被实际安装,就有一个vfsmount结构体被创建,这个结构体对应一个安装点。structfile_system_type{constchar*name;/*文件系统的名字*/structsubsystemsubsys;/*sysfs子系统对象*/intfs_flags;/*文件系统类型标志*//*在文件系统被安装时,从磁盘中读取超级块,在内存中组装超级块对象*/structsuper_block*(*get_sb)(structfile_system_type*,int,cons
本文标题:Linux的虚拟文件系统及实例XORFS
链接地址:https://www.777doc.com/doc-3266813 .html