"虚拟文件系统VFS-文件系统的安装"

  "第二章"

Posted by Xu on December 19, 2017

虚拟文件系统VFS-文件系统的安装


特殊文件系统

特殊文件系统可以为系统程序员和管理员提供一种容易的方式来操作内核的数据结构并实现操作系统的特殊特征。有一些特殊文件系统根本没有安装点,它们不是用于与用户进行交互,但内核可以用它们容易重新使用VFS层代码,因为vfs将一切视为文件,比如pipefs特殊文件系统,VFS就可以将管道FIFO文件用相同的方式对待。

内核给每个安装的特殊文件系统分配一个虚拟的块设备,让其主设备号为0次设备号为任意值。一般来说主设备号来标示一个类型设备的驱动程序,次设备号表示使用该类型驱动的不同设备,这里用于区分文件系统

文件系统类型注册

每一个文件系统类型都用file_system_type来表示,所有文件系统类型对象都会插入到一个单向链表中,由变量file_systems来表示,file_systems_lock自旋锁防治链表被同时访问。


file_system_type:

  • name:文件系统的名称。
  • fs_flags:文件系统类型标志。
  • next:维护链表上的多个文件系统。
  • fs_supers:表示给定文件系统所对应的超级块链表的头结点。fs_supers指向系统中相同文件系统的超级块对象的链表。
  • get_sb:这是一个函数指针,依赖于具体的文件系统来实现,表示分配一个超级块对象并初始化或者读取一个已经存在的超级块对象。
  • kill_sb:删除一个超级块对象。
  • owner:指向实现文件的模块的指针,因为文件系统可以在源码中直接实现,也可以由模块来安装

注册:文件系统的注册调用register_filesystem()函数来注册指定文件系统,该函数主要把相应file_system_type对象插入到文件系统链表file_systems中。

get_fs_type():扫描file_systems链表,匹配文件系统名,返回file_system_type

文件系统处理

Linux使用根文件系统,由内核在引导阶段直接安装,并拥有初始化脚本和最基本的系统程序,其它的文件系统:

  • 初始化脚本安装
  • 由用户安装在已安装文件系统的目录上。

命名空间

每个进程都可以拥有自己的已安装文件系统树--进程的命名空间

大多数进程共享同一命名空间,即位于系统的根文件系统且被init进程使用的已安装文件系统树。不过clone()系统调用以CLONE_NEWNS标志创建一个新进程,进程将获取一个新的命名空间,且被随后的子进程继承


命名空间结构体namespace:

  • count:引用计数器
  • root:命名空间根目录的已安装文件系统描述符:vfsmount结构体
  • list:所有已安装文件系统描述符链表头
  • sem: 保护这个结构读写的信号量

文件系统安装

在linux中一个文件系统可以被安装多次,相当于该文件系统的的根目录可以被多个安装点访问,但实际存在的文件系统是唯一个的,所以无论文件系统被安装多少次,都仅有一个超级块对象。

由于文件系统可以安装在已安装的文件系统的子目录上,所以文件系统之间的关联关系可能会很复杂,有一个结构体就是为了维护这一层关联关系:vfsmount,已安装文件系统文件描述符,描述一个文件系统下子目录已安装的文件系统信息


vfsmount:

  • mnt_hash:用于散列表链表指针
  • *mnt_parent:指向父文件系统,该文件系统安装在其上
  • *mnt_mountpoint:指向这个文件系统安装点目录的dentry对象
  • *mnt_root: 指向这个文件系统的超级块对象
  • *mnt_sb:指向这个文件系统的超级块对象
  • mnt_mounts:包含所有文件系统描述符链表的头
  • mnt_child:用于连接已安装文件系统链表mnt_mounts的下一个链表元素的指针
  • mnt_count:引用计数器
  • mnt_flag:标志
  • mnt_expiry_mark:到期标志
  • mnt_devname:设备文件名
  • mnt_list:已安装文件系统描述符的namespace链表的指针
  • mnt_fslink:具体文件系统到期链表指针
  • namespace *mnt_namespace:指向安装了该文件系统的进程命名空间

vfsmount存放在如下几个双向循环链表中:

  • 散列表数组中链表:mount_hashtable,散列值由父文件系统描述符地址和安装点目录项地址索引得到,链表连接字段为mnt_hash
  • 命名空间下已安装文件系统链表:namespace结构体中list指向该链表头,连接字段为mnt_list
  • 文件系统子目录下已安装文件系统链表:也就是在一个文件系统描述符中,他的已安装子文件系统构成一个链表,存放在mnt_mounts,连接链表的字段为mnt_child

vfs_mnt_list

vfsmount_lock保护已安装文件系统对象链表免受同时访问。

安装普通文件系统

我们分析将一个文件系统被安装到一个已安装文件系统之上的,mount()系统调用用于安装一个普通文件系统:

查找路径名,根据标志位调用相应挂载程序,返回已安装文件描述符插入到三条相关链表。 mount

kern_mount

安装根文件系统

根文件系统的安装分为两个部分:

  • 内核安装特殊rootfs文件系统,该文件系统仅提供一个初始安装点的空目录
  • 内核在空目录上安装实际根目录

VFS系统调用实现

open():将文件对象初始化(包括f_op),插入到进程描述符中的已打开文件的文件对象数组中去。

open

read(),write()操作类似,首先获取文件对象的地址,检查标志位及是否有强制锁,调用文件对象中的读写操作file->f_op->read/write,不同的文件系统实现方式不同,然后释放文件对象,返回实际传送字节数。

close()获取current->files->fd[fd]中文件对象地址,置为NULL释放文件描述符,通过清除current->files(当前打开文件)中的open_fds(位图)及close_on_exec(位图)相应bit来进行。最后调用filp_close,调用文件操作的flush()同步磁盘,释放文件是的任何锁,调用fput()释放文件对象。