美文网首页
linux 虚拟文件系统(VFS)---实现一个无持久存储文件系

linux 虚拟文件系统(VFS)---实现一个无持久存储文件系

作者: 鹏_921010 | 来源:发表于2022-11-09 14:15 被阅读0次

Linux 2.6.34

1.mount命令如何调用到sys_mount?(用的linux0.1.1看的 【嘿嘿】)

系统调用是通过0x80软中断触发的,中断的入口函数system_call, 在system_call里面,调用sys_call_table,系统调用表(数组),在unistd.h里,有设置了系统调用ID号,就是数组的下标,sys_call_table通过基地址寻址:sys_call_table+%eax*4-->(表是数组指针,大小是4),然后调用到内核调用:sys_mount()函数。

include/unistd.h 系统调用表

2.sys_mount如何调用到file_system_type.mount?

见底下流程:type.get_sb(xxx);

3.super block为什么在mount的时候才有?

sb-->文件系统,实例化一次,就会有一个super block。 多个设备可能对应一种文件系统。

4.应用层如何到VFS, VFS又如何到具体的文件系统实例?

应用层是先通过系统调用,触发软件中断,到内核态,根据文件系统类型,执行对应的文件系统的操作函数。

这儿从sys_mount往下分析

1. sys_mount: sys_mount主要将系统调用的参数dev_name.dir_name type flags data 从用户空间拷贝到内核空间(copy_mount_string(), getname(),copy_mount_options()这些函数将结构形式或字符串形式的参数值从用户空间拷贝到内核空间。),然后调用do_mount函数

2. do_mount :MS_MGC_MSK和MS_MGC_VAL是以前版本中定义的安装标志和掩码,现在的安装标志中已经不再使用这些魔数了,因此,遇到这魔数则丢弃。对参数dir_name 和 dev_name进行基本检查,!dir_name 和 !*dir_name,前者是指向字符串的指针不为空,后者是指字符串不为空。memchr()函数在指定长度的字符串中寻找指定的字符,如果字符串中没有结尾符\0,也是错误。kern_path里主要调用path_init和path_walk, 寻找安装点的dentry数据结构,找到的dentry结构存放在局部变量nd的dentry域中,主要获取挂载点path。flags有4个分支。如果flags中的MS_REMOUNT的标志位为1,就表示所要求的只是改变一个原已安装设备的安装方式,例如:从只读安装方式改为可写安装方式,这是通过调用do_remount(),MS_BIND为1,就表示把一个"回接"设备捆绑到令一个对象上。回接设备是一种特殊的设备(虚拟设备),是一种机制,这种机制提供了把回接设备回接到某个可访问的常规文件或块这杯的手段。通常在/dev目录中有/dev/loop0 和/dev/loop1。调用do_loopback()实现回接设备的安装。MS_MOVE为1,就表示把一个已安装的设备可以移动到另外一个安装点,这是通过do_move_mount,MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE有为1,调用do_change_type。

3. do_new_mount: do_new_mount函数会先定义struct vfsmount结构体,这个结构体在内核中用来表示已挂载文件系统的一些信息, 接着会lock_kernel获取内核锁,调用do_kern_mount函数,do_kern_mount函数的返回值就是struct vfsmount,参数name是挂载的设备文件,因此这个函数会根据要挂载的文件系统将这个结构体填充.

4. do_kern_mount: do_kern_mount函数:只有系统管理员才具有安装一个设备的权力,因此首先要检查当前进程是否具有这种权限。然后会调用get_fs_type来查看内核是否注册了参数type所指的文件系统,对于内核源码下fs目录下的所有文件系统都会通过调用register_filesystem来注册这个文件系统,其实就是添加到内核文件系统链表中,get_fs_type会将参数type字符串跟内核链表中所有已经注册的文件系统结构体file_system_type的name成员向比较,如果找到,则说明内核已经注册了相应文件系统,并且返回相应文件系统注册的file_system_type结构体。后面的挂载过程需要使用到这个结构体中的成员。找到相应的file_system_type后do_kern_mount会调用vfs_kern_mount,这个函数返回值是struct vfsmount

5. vfs_kern_mount: vfs_kern_mount首先调用alloc_vfsmnt为struct vfsmount分配内存空间并初始化许多双向循环链表,参数是要挂载的设备文件名称,在alloc_vfsmnt中会将name来填充vfsmnt结构体的mnt_devname成员。设置vfsmount的mnt_flags。然后调用对应的file_system_type的mount函数(2.6是get_sb)读出超级块,然后再填充mnt数据结构(mnt->mnt_mountpoint = mnt->mnt_root;mnt->mnt_parent = mnt;)。主要分配一个vfsmnt结构体,并初始化。

6. do_add_mount: 再do_mount函数中,kern_path中调用了path_init 和path_walk函数中已经找到了安装点的dentry结构、inode结构数据,然后再通过do_new_mount参数带过去。再do_add_mount寒素中,首先对mnt_flags字段的处理,因为从设备上读入超级块的过程是个较为漫长的过程,当前进程在等待从设备上读入超级块的过程中几乎可肯定要睡眠,这样就有可能另外一个进程先将另一个设备安装到了同一个安装点上。然后d_mountpoint()函数就是检查是否发生了这样的情况。如果确实发生了这情况,其对策就是调用follow_down()进入到已安装设备的根节点,并且通过while循环进一步检查新的安装点,知道找到一个空安装点为止。如果在同一个安装点上要安装两个同样的文件系统,报错。调用graft_tree()把mnt与安装树挂接起来,完成最终的安装。至此,设备的安装就完了。

实例:主要的数据结构,超级块 、inode、dentry等

no_storage_fs.ko文件 插入模块成功 将gpfs 名字的文件系统手动挂载到/mnt目录下,没有具体设备,参数写none类型 这样就可以读写了,机器重启后就没有了 手动取消挂载,再rmmod no_storage_fs.ko卸载模块

不足:ls的功能没有实现,内核新版的readdir-->iterate_shared,暂时还没实现。

参考文档:深入分析Linux内核源码/linux内核实现与设计 书籍

具体数据结构关系可看这兄台的博客:https://blog.csdn.net/jasonactions/article/details/115869530  

也是讲解vfs的:                                   https://developer.aliyun.com/article/248839

相关文章

网友评论

      本文标题:linux 虚拟文件系统(VFS)---实现一个无持久存储文件系

      本文链接:https://www.haomeiwen.com/subject/jnpbhrtx.html