一、首先,看看磁盘,超级块,inode节点在物理上整体的分布情况:

(图示来自:www.daoluan.net)

对于一个分区,对应一个文件系统,一个文件系统其实本质上还是磁盘的一部分,所以可以包括多个柱面。对于柱面上的数据,主要看看inode节点位图、block位图,i节点,数据块。inode节点位图是为了记录inode节点的使用情况,之前的违章中已经说过,inode节点在文件系统安装的时候,会初始化所有的inode节点,那么形成的位图表示使用or没使用的大表。对于block块也是一样的,记录数据块使用情况。

对于inode节点来说,每个文件都会对应一个inode节点,目录项也会对应一个inode节点。对于一个文件来说,只对应一个inode节点,但是一个文件可以有多个数据块,因为一个比较大的文件,一个数据块根本存放不了。所以inode中记录多个文件数据块的信息。

对于目录块来说,主要是为了索引而存在,所以里面的内容主要是inode节点号和文件名,其实就是一个映射表形式的东西。

二、

上一篇中对于VFS有一个简单的介绍与理解,我们知道,与用户打交道的是VFS,然后VFS与底层真正的文件系统交流。那我们知道在一个VFS下面,允许存在很多的“文件系统类型”,例如ext2,ext3,ext4,sysfs,proc等等。这些类型是可以共存的,同时,对于每一个类型来说,可以存在多个文件系统实体,例如:在一个目录下有多个子目录,子目录之间的文件系统类型可以不一样,也可以有部分是一样的类型,借用windows中的例子说就是,D盘和E盘可以都是NTFS类型文件系统,也可以是不一样的文件类型系统。

在Linux中,系统有一个全局变量叫做file_systems,这个变量用来管理所有的“文件系统类型”链表。也就是所有的文件系统类型都必须注册到(链接到)这个链表中,才可以被使用。如果是自己的文件系统,只要符合VFS的标准,也是可以注册进去的。最终形成一个单链表形式结构。

而对于一个文件系统类型,使用file_system_type结构表示:

[cpp] view plaincopyprint?
  1. <span style="font-size:14px;">995 struct file_system_type {
  2. 996         const char *name;
  3. 997         int fs_flags;
  4. 998         struct super_block *(*read_super) (struct super_block *, void *, int);
  5. 999         struct module *owner;
  6. 1000         struct file_system_type * next;
  7. 1001         struct list_head fs_supers;
  8. 1002 };</span>

字段意思:

name:文件系统类型名称,如ext2。

flags:安装文件类型标志,在fs.h中有定义。

read_super:各种文件系统读入其“超级块”的函数指针,不同的文件系统之间可能不一样,因此读入函数也不一样。

owner:如果这个文件系统是通过一个可安装模块实现的,那么这个指针指向这个模块。

next:这个就是链接到下一个“文件类型”的指针。

fs_supers:属于相同的文件系统类型的所有的super_blocks构成一个双向链表。在超级块中有一个s_instance就是连接这个双链表的连接点。(超级块在上一篇有介绍)

1、

那么根据上面的解释,一个大的框架图如下:

同时,在内核中,有一个全局的变量super_blocks用于将所有的suoer_block连接在一起,形成一个双向链表,这样就会发现s_list字段就有意义了!

如图:

2、我们在之前也提过,文件系统最终还是要和进程一起协作的,任何对于文件的操作都是基于进程的。由操作系统的知识我们知道,对于进程来说,管理进程的叫“进程控制块PCB”,这个在内核中的结构为:task_struct,这个是很复杂的一个结构体,对于进程来说,可以有自己的操作的文件,那么进程的文件的信息,也是包含在这个结构中:

[cpp] view plaincopyprint?
  1. 283 struct task_struct {
  2. ... ...
  3. 391 /* filesystem information */
  4. 392         struct fs_struct *fs;
  5. 393 /* open file information */
  6. 394         struct files_struct *files;
  7. ... ...
  8. }

代码中的两个字段就是涉及进程的文件的字段。每个进程在PCB中保存着一份文件描述符表,文件描述符就是这个表的索引(数组的下标),每个表项都有一个指向已打开文件的指针。

代码中第一个字段fs:代码本进程自身的文件系统的信息。例如进程本身的根目录,挂载点,当前目录等信息。

代码中第二个字段files:保存着本进程涉及的所有的文件的信息的指针。files_struct结构之前已经说过:files_struct

里面有两个重要字段:

[cpp] view plaincopyprint?
  1. 172 struct files_struct {
  2. ... ...
  3. 178         struct file ** fd;      /* current fd array */
  4. ... ...
  5. 183         struct file * fd_array[NR_OPEN_DEFAULT];
  6. 184 };

fd就是涉及到的所有的文件的数组指针!一般情况下fd就是fd_array,但是如果打开的文件超过NR_OPEN_DEFAULT,那么就会重新分配新的数组,然后fd指向新的数组。

对于一个文件数组来说例如:fd[],所谓“文件描述符”其实就是这个数组的下标!例如:默认0就是标准输入文件描述符,1是标准输出,2是标准错误。对于用户来说操作的是这个“文件描述符”,但是对于内核来说,“文件描述符”仅仅是为了找到对应的文件而已!然后所有的在内核中的操作,都是使用实际文件的file指针进行的!关于file结构体在上一篇也说了(之前files_struct链接)。延伸一下:我们在写C语言程序的时候会遇到两个函数,open和fopen。对于前者,返回的就是一个“文件描述符”,即那个文件数组的下标,对于fopen,返回的是一个FILE的指针,这里面其实除了“文件描述符”之外,还包括IO缓冲这些信息。文件指针FILE*更上层,FILE指针将文件描述符和缓冲区封装在一起。

OK,那么用户进程打开一个文件的具体的过程是什么呢?下面分析总结一下:首先我们知道用户使用open返回一个“文件描述符”(具体怎么获得,之后再说),然后在进程PCB中,即task_struct文件数组中找到对应“文件描述符”(数组下标)的文件(file)指针,在file结构体中,f_dentry记录了这个文件的完整目录项,一般在内存中会有dentry的缓存,通过这个我们可以找到文件的inode。对于一个dentry来说,也是有自己的inode,目录名称之类信息。总之通过dentry,可以找到最终文件的inode,找到inode之后,就可以定位到具体的文件数据在磁盘上的位置了!

对于上面的过程,整体的一张图如下:

3、多个进程和多个文件之间的关系:

对于一个进程来说,可以打开多个文件,也可以多个进程打开一个文件,对于文件来说,不变的永远是自己的inode节点,变化的仅仅是和进程直接关系的file结构。可以看一下下面的大图:

Linux 文件系统(二)---执行过程及结构间的关系相关推荐

  1. linux每隔多久调度y,Linux 进程调度+Linux系统一般执行过程 笔记

    进程的调度时机与进程的切换 操作系统原理中介绍了大量进程调度算法,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已. 对于理解操作系统的工作机制,反而是进程的调 ...

  2. Linux 命令的执行过程/Shell提示符/alias命令

    在 Linux 系统中"一切皆文件",Linux 命令也不例外.那么,当编辑完成 Linux 命令并回车后,系统底层是怎么执行的? 1) 内核层 内核层是 UNIX/Linux 系 ...

  3. linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...

    fork系统调?创建?进程,也就?个进程变成了两个进程,两个进程执?相同的代码,只是fork系统调?在?进程和?进程中的返回值不同. 打开linux-5.4.34/arch/x86/entry/sys ...

  4. Linux 系统调用的执行过程

    什么是系统调用 系统调用 (在 Linux 中常称为 syscalls ) 是应用程序访问硬件设备之间的桥梁. 系统调用层为用户空间提供一种硬件的抽象接口,使得用户不用关注设备的具体信息,同时系统调用 ...

  5. 分析teamTNT团队Linux挖矿木马执行过程与防范

    分析teamTNT团队Linux挖矿木马执行过程与防范 公司需要扩展海外业务,需要有一台海外云服务器.当我们把应用部署上去时的第二天所有应用down掉了,然后发现ssh连接服务器特别慢.好不容易连接上 ...

  6. Linux文件系统二(虚拟文件系统VFS实现原理)

    创作人QQ:851301776,邮箱:lfr890207@163.com         欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点! 个人座右铭:          1 ...

  7. linux内核make执行过程

    本篇基于上一篇<<linux内核make menuconfig执行过程>>基础上,追溯make执行过程. make 1. 与make menuconfig相同的部分 这部分内容 ...

  8. linux执行class文件_深入理解linux内核——可执行文件执行过程(2)

    接上篇.. 13.调用do_mmap()函数创建一个新线性区来对可执行文件正文段(即代码)进行映射.这个线性区的起始线性地址依赖于可执行文件的格式,因为程序的可执行代码通常是不可重定位的.因此,这个函 ...

  9. linux 文件可执行_深入理解linux内核——可执行文件执行过程(2)

    接上篇.. 13.调用do_mmap()函数创建一个新线性区来对可执行文件正文段(即代码)进行映射.这个线性区的起始线性地址依赖于可执行文件的格式,因为程序的可执行代码通常是不可重定位的.因此,这个函 ...

  10. linux 跟踪命令执行过程,Linux的strace命令跟踪线程死锁

    strace命令,是Linux提供的跟踪系统调用的命令,需要sudo或root权限,可以查看进程(线程)使用的系统调用. 基本用法:sudo strace -p 进程号 如果一个线程递归获取同一个锁, ...

最新文章

  1. RandomUnderSampler 中的fit_resample 是 imblearn.base.py中调用output = self._fit_resample(X, y)
  2. 十一、explain属性介绍
  3. HttpServlet概述及应用
  4. 模切ERP和免费OA系统是互相结合提高效率
  5. java去掉mongodb日志_MongoDB日志文件过大的解决方法 清理
  6. 正则表达式JavaScript版本回顾笔记背诵版本
  7. 如何修改magento产品详细页面的栏目
  8. 如何创建一个Mybatis程序,实现对数据库的简单查询?
  9. Cisco路由配置命令
  10. java8新特性和汪文君Google Guava项目实战视频
  11. Python基础 -- 注释、变量以及数据类型、标识符和关键字、类型转、运算符
  12. Windows下usb接口驱动技术(一)
  13. PS去水印的四种方式
  14. linux系统下的微信安装(ubuntu20.04)
  15. 如何用阿里云云盘快照恢复部分数据
  16. NFC开发 —————实现NFC手机做门禁卡的方法(二)
  17. win10激活错误,软件授权服务报告无法激活计算机怎么办?
  18. 别人花了几万元学的英语,我帮你们免费弄来了
  19. HTML5作业:美食网站设计(浮动的使用)
  20. pytorch里面nn.Module讲解

热门文章

  1. 智能客户端(Smart Client )中文文档及案例(转贴)
  2. ORACLE中如何查找定位表最后DML操作的时间小结
  3. 【Java】Java日志框架Logback的简单例子
  4. fscanf、fprintf的返回值
  5. NinePatchChunk.java分析
  6. Visual Studio 2012 RC 发布
  7. 判断linux下的网络服务是否正常启动
  8. Linux中利用NFS实现飞鸽传书
  9. 使用 Google Guava 美化你的 Java 代码
  10. Stacked injection--堆叠注入--堆查询注入