zoukankan      html  css  js  c++  java
  • Linux 文件系统(二)---运行过程及结构间的关系

    (内核2.4.37)


    一、首先。看看磁盘。超级块,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结构表示:

    <span style="font-size:14px;">995 struct file_system_type {
    996         const char *name;
    997         int fs_flags;
    998         struct super_block *(*read_super) (struct super_block *, void *, int);
    999         struct module *owner;
    1000         struct file_system_type * next;
    1001         struct list_head fs_supers;
    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,这个是非常复杂的一个结构体,对于进程来说,能够有自己的操作的文件,那么进程的文件的信息,也是包括在这个结构中:

    283 struct task_struct {
    ... ...
    391 /* filesystem information */
    392         struct fs_struct *fs;
    393 /* open file information */
    394         struct files_struct *files;
    ... ...
    }

    代码中的两个字段就是涉及进程的文件的字段。

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

    代码中第一个字段fs:代码本进程自身的文件系统的信息。

    比如进程本身的根文件夹。挂载点,当前文件夹等信息。

    代码中第二个字段files:保存着本进程涉及的全部的文件的信息的指针。

    files_struct结构之前已经说过:files_struct

    里面有两个重要字段:

    172 struct files_struct {  
    ... ...
    178         struct file ** fd;      /* current fd array */  
    ... ...
    183         struct file * fd_array[NR_OPEN_DEFAULT];  
    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结构。能够看一下以下的大图:




  • 相关阅读:
    mac Redis相关配置,安装,启动,环境的配置。
    MySQL设置global变量和session变量的两种方法详解
    关于MySQL的锁以及数据脏读,重复读,幻读的笔记。
    MySQL新增数据,存在就更新,不存在就添加(转帖加实测)
    selenium 的显示等待和隐式等待的区别(记录加强版)
    MySQL字段与表的注释。转帖
    mysql格式化日期(转帖)
    通过Python用pymysql,通过sshtunnel模块ssh连接远程数据库。
    java io流
    openID 无效
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5062394.html
Copyright © 2011-2022 走看看