VFS

时间:2021-11-13 15:43:32

VFS的作用:为文件系统提供通用的接口。

通用文件模型:common file model。特殊文件系统需要将它的物理结构转换成通用文件模型。

common file model包括以下几个重要对象:

super block:存储关于文件系统的信息。

inode:存储一个特定文件的信息。每个inode都有一个inode号,唯一描述一个文件。

file:存储文件与进程交互的信息。

dentry:目录项,目录的每个组成部分。例如,/home/xxx/yyy.c中,/,home,xxx,yyy.c都是目录项。目录项也是文件,因此也有inode。

VFS

● struct super_block:

所有的super block对象都被链接在一个双向链表,这个链表的第一个节点由super_blocks变量指向,s_list成员指向与自己相邻的成员。

s_fs_info成员指向与特定文件相关的信息(私有信息,和common file model无关)。例如该super block 对象指向一个ext2文件系统,则s_fs_info指向ext2_sb_info结构。

s_dirty反应super block对象是否被修改。

s_op:对super block的操作,它是struct super_operations类型。每种文件系统都可以定义自己的super_operators。vfs调用操作(例如read_inode)用类似这样的方式:sb->s_op->read_inode(inode)

● inode对象:struct inode

每一个inode对象都会在下面三个链表之一:

1)有效但未使用的inode链表,由变量inode_unused指向

2)正在使用的inode链表,由变量inode_in_use指向

3)脏inode链表,由对应的super block对象的s_dirty成员指向。

每个inode对象也会出现在super block对象的s_inodes成员指向的链表。

struct inode_operations:inode的操作,由inode对象的i_op成员指向。

● file对象:struct file

file对象描述了进程如何与它打开的文件交互。这个对象只存在于内存中,在磁盘不存在,因此没有标识是否dirty的成员。

每个super block对象的s_files成员指向一个file对象组成的链表,file对象的f_list成员指向它在这个链表的前后成员。因此,不同文件系统的file对象,在不同的链表中。

f_count:引用该file对象的进程的数量。

file_operations:file对象的操作,由file对象的f_op指向。

● dentry对象:struct dentry

对于一个路径,例如/tmp/test,的每一个组成部分,VFS都会未其创建一个dentry,因此,这个路径一共有三个dentry,每个dentry都有自己对应的inode。

dentry对象不存储在磁盘。

由kmem_cache_alloc和kmem_cache_free创建和销毁。

dentry对象的四种状态:

free:dentry对象没有有效的信息,并且没有被VFS使用。

unused:dentry对象当前没有被VFS使用,d_count成员的值为0,但是d_inode成员指向对 应的inode。对象包好的信息有效,但可能由于回收资源而被丢弃。

in use:dentry对象当前正被VFS使用中,d_count的值为正,d_inode指向对应的inode,对 象的内容也不能被抛弃。

negative:dentry对象对应的inode不存在。可能是因为inode被删除,或该dentry被创建的时候,对应的文件不存在。

dentry_operations:

由dentry对象的d_op成员指向。

unused dentry对象被组织在一个LRU双向链表中,按插入时间顺序排序。链表的第一个,也是最后一个元素被变量dentry_unused指向,这个元素的d_lru成员指向它在该lru链表中相邻的元素。

in use状态的dentry对象被组织在一个双向链表中,这个链表被它对应的inode对象的i_dentry成员指向。因为一个inode可能被多个dentry引用,因此,该链表实际上,是某个inode的dentry对象链表。

● struct fs_struct,files_struct

fs_struct:

描述进程与文件系统交互的信息。进程描述符task_struct的fs成员指向该结构。

VFS

file_struct:

描述了进程打开的所有文件,进程对象的files成员指向它。

VFS

fd成员的最大值由max_fds指定。fd_array包含32个file对象,如果进程打开的文件超过32个,则内核会分配一个更大的file指针数组,并将其赋给fd,同时更新max_fds的值。

对于fd这个数组,文件描述符就是它的索引。通常0为标准输入,1为标准输出,2为标准错误输出。允许不同的文件描述符,引用相同的文件,例如,通过shell重定向:2>&1。

疑问:fd是每个进程的局部变量,每个进程都是这样的规则?

文件描述符是一个无符号整型。

内核提供一个fget(fd)函数来使用一个file对象:current->files->fd[fd]。fget函数会使file对象的f_count成员加1。

相应地,内核提供一个fput函数,当该file对象使用完毕后,f_count减1。当f_count=0时,fput调用file对象的release方法,将i_writecount(假设该文件,用来写)减1,并从对应的super block的file链表上将该file对象删除,将该file对象返回给slab allocator,将对应的dentry的使用计数减1。

● 特殊文件系统:special filesystem

网络文件系统和基于磁盘的文件系统能让用户在内核以外处理信息,特殊文件系统让用户和程序处理内核的数据,并且实现操作系统的一些特殊功能。

VFS

VFS

特殊文件系统和具体的物理设备无关,但为了统一起见,内核会给每个挂载的特殊文件系统分配一个虚拟设备。这个虚拟设备用0作为主设备号(major number),任意的数值作为副设备号(minor number)。super_block有一个成员s_dev,是设备描述符,内核用set_anon_super函数来初始化特殊文件系统,这个函数获得一个副设备号minor number,然后用主设备号0和副设备号dev来初始化s_dev。

VFS

● 文件系统类型注册:

每个文件系统类型用file_system_type对象类表示:

VFS

所有的文件系统类型被插入到一个单链表,这个链表由变量file_systems来指向。file_system_type的next成员指向这个链表中的下一个文件类系统型对象。

file_system_type对象的fs_supers成员指向某个特定文件系统类型的所有super block,形成一个链表。super block的s_instances成员指向这个文件系统类型在链表的前一个和后一个元素。

VFS

注册:在编译时,调用register_filesystem 函数,将文件系统类型对象插入到file_systems指向的链表中。当一个实现了文件系统的模块加载时,也会调用register_filesystem。

解除注册:unregister_filesystem。

● 文件系统的挂载:

根文件系统root filesystem:内核在编译时期,直接挂载的文件系统。掌握了系统初始化脚本和最重要的系统程序。

其他文件系统可以挂载在已挂载的文件系统的目录上。每个文件系统都有它的根目录,文件系统挂载的目录叫做挂载点mount point。一个文件系统是它的挂载点对应的目录所在的文件系统的子文件系统。

根目录隐藏了挂载点目录的内容,以及挂载点之下的所有子树。

● namespace

namespace是一种资源隔离的方案pid,ipc,mnt等资源不再是全局性的,而是属于某个namespace。每个namespace下的资源对其他namespace是透明的。因此对于pid,可能出现相同的pid,但是相同的pid会在不同的namespace中。

VFS

对于文件系统,也有一个namespace。一个进程在clone时,如果设置了CLONE_NEWNS标志位,则获得了一个新的namespace。当一个进程挂载或卸载文件系统时,它只会修改自己的namespace。

命名空间结构体struct nsproxy,被进程对象的nsproxy成员指向。

每个文件系统可以挂载多次,但是他们共享一个super block。

一个挂载点也可以挂载多个文件系统。

● struct vfsmount

描述一个独立文件系统的挂载信息,每一个挂载点对应一个vfsmount结构。属于同一文件系统的文件和目录隶属于同一vfsmount。

VFSmount挂载点通过mnt_list双链表挂载在mnt_namespace->list中,该命名空间可以通过任意进程获得:task-> nsproxy

VFS

vfsmount结构被保存在下面的链表中:

  • 一个哈希表,索引为父文件系统的vfsmount地址挂载点的dentry地址。这个哈希表存储在名为mount_hashtable的数组里。该哈希表的每一项,是所有哈希值相同的vfsmount组成的链表。vfsmount的mnt_hash成员指向该链表的相邻元素。
  • 每一个namespace的list成员维护的一个链表,vfsmount的mnt_list成员指向这个链表中相邻的元素。

VFS

  • 对于每一个挂载的文件系统,维护了一个所有子文件系统(挂载在自己文件系统上的文件系统)的链表(假设为L)。vfsmount的mnt_mounts成员指向父文件系统的L。vfsmount的mnt_child成员指向父文件系统的L链表的相邻的元素。

(待续。。。)