转自:https://blog.csdn.net/zr_lang/article/details/39963253

一直想写有些关于文件系统的博文,但是由于近一年来实在太忙,所以没有时间写。前几日赶上放国庆节假期,回来后又正好处在RHEL-6.6刚发布,RHEL-7.1还没有开始繁重工作的阶段,所以抽出一些时间准备写一些东西。不知道是否能坚持长久,可能在忙起来后会拖后进度吧。反正也不着急,慢慢写。

既然要分析就要选择一个确定的linux版本进行说明,目前最新的linux稳定版是3.16.3,就选这个内核了。之后的文章都以这个版本为基础。

研究linux
fs的入手点应该是哪呢?可能仁者见仁,智者见智。我一直以来也都是零零散散的翻阅着有关super block, inode, dentry,
file等等内容的各种代码和资料,但是知识始终是散乱的,无法拼凑成完整的体系。现在我要试图整理顺一个整套的文件系统知识,我决定从file_system_type入手。

本文是要尽力将我已经掌握的分块的知识串连起来,所以至少了解linux vfs的几个结构是必须的,super_block, inode, dentry, file等。

在include/linux/fs.h里定义着几个基本数据结构——block_device,
file_system_type,
inode和file。其中block_device一般和块设备操作,如硬盘、分区等有关,文件系统的操作多半都会反映到硬盘等块设备上的操作,如读取super

block、读写数据等,所以block_device掌管着文件系统的底层设备。由于我们从file_system_type开始研究,所以这里先不管block_device。

来看file_system_type的结构:

  1. struct file_system_type {
  2. const char *name;
  3. int fs_flags;
  4. #define FS_REQUIRES_DEV         1
  5. #define FS_BINARY_MOUNTDATA     2
  6. #define FS_HAS_SUBTYPE          4
  7. #define FS_USERNS_MOUNT         8       /* Can be mounted by userns root */
  8. #define FS_USERNS_DEV_MOUNT     16 /* A userns mount does not imply MNT_NODEV */
  9. #define FS_RENAME_DOES_D_MOVE   32768   /* FS will handle d_move() during rename() internally. */
  10. struct dentry *(*mount) (struct file_system_type *, int, const char *, void *);
  11. void (*kill_sb) (struct super_block *);
  12. struct module *owner;
  13. struct file_system_type * next;
  14. struct hlist_head fs_supers;
  15. // ....
  16. //为了说明方便,此处省略若干锁相关变量。
  17. //....
  18. }

name: 文件系统的名字,如xfs, ext2等

fs_flags: 说明文件系统的类型,下面的宏定义代表了它的几种类型:

FS_REQUIRES_DEV: 文件系统必须在物理设备上。

FS_BINARY_MOUNTDATA: mount此文件系统时(参见mount_fs函数 -
fs/super.c)需要使用二进制数据结构的mount data(如每个位域都有固定的位置和意义),常见的nfs使用这种mount
data(参见struct nfs_mount_data结构 - include/uapi/linux/nfs_mount.h)。

FS_HAS_SUBTYPE: 文件系统含有子类型,最常见的就是FUSE,FUSE本是不是真正的文件系统,所以要通过子文件系统类型来区别通过FUSE接口实现的不同文件系统。

FS_USERNS_MOUNT: 文件系统每次挂载都后都是不同的user namespace,如用于devpts。

FS_USERNS_DEV_MOUNT: user namespace挂载支持MNT_DEV, 即非nodev模式。

FS_RENAME_DOES_D_MOVE: 文件系统将把重命名操作reame()直接按照移动操作d_move()来处理,主要用于网络万件系统。

mount: 代替早期的get_sb(),用户挂载此文件系统时使用的回调函数。

kill_sb: 删除内存中的super block,在卸载文件系统时使用。

owner: 指向实现这个文件系统的模块,通常为THIS_MODULE宏。

next: 指向文件系统类型链表的下一个文件系统类型。

fs_supers: 具有同样此文件系统类型的超级块结构,都串连在这个表头下。

有了file_system_type,现在就是如何使用file_systems_type了。file_system_type的基本操作都在fs/filesystems.c文件里,文件不长,可以简短的浏览一下都有那些操作函数。最主要的变量莫过于此文件内的全局变量:

// 此变量是文件系统类型单链表的头指针

static struct file_system_type *file_systems;

而其中最主要的函数莫过于:

  1. int register_filesystem(struct file_system_type * fs)
  2. {
  3. int res = 0;
  4. struct file_system_type ** p;
  5. BUG_ON(strchr(fs->name, '.'));
  6. if (fs->next)
  7. return -EBUSY;
  8. write_lock(&file_systems_lock);
  9. // 遍历全局file_systems链表,尝试查找本次要注册文件系统名。
  10. p = find_filesystem(fs->name, strlen(fs->name));
  11. if (*p) // 如果不为NULL,则说明找到了重名的文件系统。注册失败。
  12. res = -EBUSY;
  13. else // 如果返回NULL,说明已经到链表结尾,可以注册此文件系统。
  14. *p = fs; // 将此文件系统链接到链表结尾。
  15. write_unlock(&file_systems_lock);
  16. return res;
  17. }
当然与注册相对应的就是注销,
unregister_filesystem就是register的反操作。除了注册文件系统操作以外还有一个相对重要的函数get_fs_type,接受文件系统名称(如xfs)作为参数,在*file_systems链表里查找到对应的file_system_type成员。
mount/get_sb和kill_sb方法
我觉得file_system_type,或者说register文件系统时就是要完成两个主要的事情:
1. 告诉kernel自己叫什么(一个唯一的name)
2. 告诉kernel怎么使用自己的超级块信息,以便完成挂载自己的操作(过去的get_sb现在的mount)。
所以mount和kill_sb回调函数就是file_system_type中最需要重点实现的了,因为这里涉及到每个文件系统的具体实现,所以我们就不详细的一一说明,只说一下大概的实现死路。fs/下实现着不同的文件系统,每一个目录名基本上就代表一个具体文件系统的实现,以xfs为例,fs/xfs/下就是xfs文件系统的实现。而file_system_type结构一般被定义在super.c里(一般,不是所有)。那么看一下fs/xfs/xfs_super.c里如何定义xfs的file_system_type:

  1. static struct file_system_type xfs_fs_type = {
  2. .owner                  = THIS_MODULE,
  3. .name                   = "xfs",
  4. .mount                  = xfs_fs_mount,
  5. .kill_sb                = kill_block_super,
  6. .fs_flags               = FS_REQUIRES_DEV,
  7. }

owner说明xfs模块本身拥有这个file_system_type。

name是xfs。

fs_flags是FS_REQUIRES_DEV,表明xfs一定要被使用在物理设备上。

接下来mount=xfs_fs_mount,说明 xfs_fs_mount这个函数实现了xfs的具体mount操作。搜索xfs_fs_mount,在本文件里看到了它的实现:

  1. STATIC struct dentry *
  2. xfs_fs_mount(
  3. struct file_system_type *fs_type,
  4. int                     flags,
  5. const char              *dev_name,
  6. void                    *data)
  7. {
  8. return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
  9. }

看起来就是一个mount_bdev()函数,但是看参数可以看到一些重要的东西

fs_type不用多说,携带file_system_type的信息,这里传递它主要是因为它携带了super block的链表和很多锁变量。

flags文件系统的通用挂载选项。

dev_name是mount操作时的设备名,如/dev/sda1。后面会用到这个设备名找到对应的设备信息,从而从中获得super block。

data是挂载时指定的挂载选项信息。

xfs_fs_fill_super是一个由xfs特定实现的fill_super方法,用来根据xfs文件系统的特性解析mount data并继续填充super block的字段,并且初始化挂载点的根索引节点对象和目录项对象。

对于mount的具体过程将在后续内容中详细介绍。

总结:

为什么我认为file_system_type是学习linux
fs的开始,因为注册文件系统是让一个具体文件系统能够生效的第一步,而注册文件系统实际就是注册了一个file_system_type实例。如xfs文件系统,加载xfs模块是使用xfs的必要条件,加载xfs模块时就会将xfs的file_system_type注册到kernel中,当然xfs要先具体化一个自己的file_system_type,然后注册。

当一个文件系统注册进内核后,它并没有被使用,只有mount这个文件系统后,这个文件系统才真正工作,我们一般这样初始化并使用一个文件系统:

mkfs.xfs /dev/sda1

mount -t xfs /dev/sda1 /mnt

mkfs是用户态工具,根据每个文件系统的不同实现有不同的mkfs方法。对于硬盘来说,mkfs就是向硬盘中按照某个文件系统的格式写入文件系统的信息到硬盘中,如文件系统类型,block
size,bitmap,
inode索引等,这些内容主要组成了一个文件系统的超级块,本来这些信息是很难理解的,单是对于文件系统本身来说他们就是一个个有效的数据。
在mount文件系统时,这个文件系统注册的mount回调函数(过去的get_sb函数)就有用了,它由具体文件系统实现,可以从设备上(如磁盘)读取文件系统的超级块信息,用以完整整个mount操作。(关于mount操作我们后面叙述)

所以说file_system_type主要就是完成两件事,一个是告诉系统自己叫什么,一个是告诉系统怎样解析自己特有的数据结构完成mount操作。

http://blog.csdn.net/zr_lang/article/details/40325241 (mount 七)

http://blog.csdn.net/zr_lang/article/details/40343899 (mount 六)

http://blog.csdn.net/zr_lang/article/details/40115013 (mount 五)

http://blog.csdn.net/zr_lang/article/details/40080979 (mount 四)

http://blog.csdn.net/zr_lang/article/details/40049305 (mount 三)

http://blog.csdn.net/zr_lang/article/details/40002285 (mount 二)

http://blog.csdn.net/zr_lang/article/details/39963253 (mount 一)

mount过程分析之一(基于3.16.3内核)【转】的更多相关文章

  1. Linux系统启动那些事—基于Linux 3.10内核【转】

    转自:https://blog.csdn.net/shichaog/article/details/40218763 Linux系统启动那些事—基于Linux 3.10内核 csdn 我的空间的下载地 ...

  2. [转]Linux芯片级移植与底层驱动(基于3.7.4内核)

      1.   SoC Linux底层驱动的组成和现状 为了让Linux在一个全新的ARM SoC上运行,需要提供大量的底层支撑,如定时器节拍.中断控制器.SMP启动.CPU hotplug以及底层的G ...

  3. 基于x86架构的内核Demo的详细开发文档

    http://hurlex.0xffffff.org/ 这里是hurlex这个基于x86架构的内核Demo的详细开发文档, 包含PDF文档和生成PDF的XeLaTex源码和文档每章节的阶段代码. 你可 ...

  4. 做自己的docker镜像(基于ubuntu:16.04)

    基于ubuntu:16.04 apt-get update -y apt-get install sudo -y 换源 sudo apt-get install vim sudo vim /etc/a ...

  5. 基于Linux-3.9.4内核的GDB跟踪系统调用实验

    382 + 原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ 一.实验环境 win10 -> VMware -> Ubuntu1 ...

  6. 基于tiny4412的Linux内核移植 -- eMMC驱动移植(六)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  7. 基于tiny4412的Linux内核移植 -- DM9621NP网卡驱动移植(四)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  8. 基于tiny4412的Linux内核移植(支持device tree)(二)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  9. Linux mount/unmount命令(6/16)

    linux是一个优秀的开放源码的操作系统,可以运行在大到巨型小到掌上型各类计算机系统上,随着 linux系统的日渐成熟和稳定以及它开放源代码特有的优越性,linux在全世界得到了越来越广泛的应用.现在 ...

随机推荐

  1. 第二阶段冲刺——two

    个人任务: 王金萱:优化作业查询结果,按学号排列. 马佳慧:测试登录功能并优化. 司宇航:修复博客作业查询功能. 季方:测试博客作业查询功能. 站立会议: 任务看板和燃尽图:

  2. 第二个Sprint冲刺第 九天(燃尽图)

  3. "Gun N' Rose" Team学习心得

    如果我比别人看得更远,只因为我站在巨人的肩膀上.                                                        ——牛顿 高级软件工程课程终于开课了!第 ...

  4. 第一章:帝国的余晖 AT&T公司

    启示:自己的想法,有好的技术比什么都重要,一定要注意的是技术,不要贪小便宜,明白自己最先关心的的哪个事情. 书中内容:没有人能活两百岁,也没有公司能辉煌两百年,这就是规律,很难超越.

  5. java学习三 小数默认为double

    前++,后++在独立运算时候 直接计算出值 当后加加和减减和其他代码在一行的时候先使用加加和减减之前的值, 如果不在同一行,后面的一行就会得到加加或减减后的值 &&是逻辑运算符,逻辑运 ...

  6. BZOJ 4242 水壶(BFS建图+最小生成树+树上倍增)

    题意 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入建筑 ...

  7. oracle无法通过IP地址进行连接

    在oracle安装完成之后有时候后无法使用IP地址进行连接或者压根无法进行连接,此时我们可以通过配置oracle的监听来解决这个问题: 在开始菜单中找到oracle文件夹的net manager,如下 ...

  8. diyiti.cpp

    diyiti.cpp/c/pas diyiti.in diyiti.out 2s/256MB 给定两个01串,S,T(下标从0开始). 支持如下3种操作: 1. 修改S第i位的字符,即0->1, ...

  9. 六、spring boot 1.5.4 配置多数据源

    spring boot 已经支持多数据源配置了,无需网上好多那些编写什么类的,特别麻烦,看看如下解决方案,官方的,放心! 1.首先定义数据源配置 #=====================multi ...

  10. 界面编程之QT绘图和绘图设备20180728

    /*******************************************************************************************/ 一.绘图 整 ...