我们知道磁盘在分区后还需要进行格式化,之后操作系统才能使用这个分区。而需要格式化的原因正是因为每种操作系统所设置的文件属性/权限并不相同。在Linux中,传统的磁盘文件系统是EXT,下面以EXT为例浅析Linux的文件系统与索引节点。

  我们知道,文件的数据除了文件实际内容之外,通常还含有非常多的属性。文件系统通常会将权限与属性等数据放置到inode(index node)中,至于实际数据则放置到data block块中;另外,还有一个超级块会记录整个文件系统的整体信息。

  在文件系统中,每个inode与block都有编号,而每个inode都对应一个文件,inode内存放有文件数据放置的block号码。那么在寻找文件的时候,就可以通过查找文件对应的inode号码,从而找出文件数据放置的block号码,然后读出该文件的实际内容。其过程可以简化如下:

    Linux文件系统与索引节点inode浅析_Linux

  inode也会消耗硬盘空间,文件系统一开始就将inode与block规划好了,block是数据区,存放文件数据,inode是inode区,存放inode所包含的信息,除非重新格式化或通过命令更改文件系统,否则inode与block固定后就不再变动;每个inode节点的大小,一般是128byte或256byte,inode节点的总数,在格式化时就给定。但如果我们的文件系统比较大,那么inode与block的数量将会很大,如果放置在一起将不容易管理。因此EXT文件系统在格式化的时候是区分为多个块组(block group)的,每个块组有自己独立的inode/block/superblock系统(注意:块组是在单个文件系统内进行的划分,所以多个块组内的inode、block号码是互不相同的)。EXT系统的结构大致如下

    Linux文件系统与索引节点inode浅析_inode_02

  data block

data block是用来放置文件内容的地方,在Ext文件系统中所支持的block大小有1KB,2KB及4KB三种;在格式化时block大小就固定了,且每个block都有编号,以方便inode的记录。

  • 原则上,block的大小与数量在格式化完就不能再改变(除非重新格式化)

  • 每个block内最多只能放置一个文件的数据

  • 如果文件大于block的大小,则一个文件会占用多个block数量

  • 若文件小于block,则该block的空间就不能够再被使用(磁盘空间会浪费)

  inodetable

inodetable是用来放置块组内所有文件及其对应inode的地方。inode记录的文件数据至少有下面这些

  • 该文件的访问模式(read/write/excute)

  • 该文件的所有者与组(owner/group)

  • 该文件的大小

  • 指向此文件内容的硬链接数

  • 该文件创建或状态改变的时间(ctime)

  • 最近一次的读取时间(atime)

  • 最近修改的时间(mtime)

  • 定义文件特性的标志(flag),如SetUID等

  • 该文件真正内容的指向(point)

inode的数量与大小在格式化时就已经固定了,inode具有以下特点

  • 每个inode的大小均固定为128byte或256byte

  • 每个文件都仅会占用一个inode,因此文件系统能够创建的文件(除去硬链接文件)数量与inode的数量有关

  • 系统读取文件时需要先找到inode,并分析inode所记录的权限与用户是否符合,若符合才能够开始实际读取block的内容

    inode的大致结构如下

    Linux文件系统与索引节点inode浅析_Linux_03

  简单分析一下inode/block与文件大小的关系:

  由上图我们可以看到inode中有12个直接块指针、1个间接块指针、1个双重间接指针块与一个三重间接指针块。加入一个block为1KB,那么12个直接块指针可指向的数据大小为:12×1K=12K;当大于12KB时,就会使用间接指针块,其指向一个用来记录额外block号码的block,一个指针块占据4byte,所以一个block中可以存储256个指针块,可指向的数据大小为256×1K=256K;当文件再大时,会使用双重间接指针块,可指向的数据大小为:256×256×1K=64M;文件更大时,将使用三重间接指针块,可指向的数据大小为:256×256×256×1K=16G;

  Superblock

  Superblock是记录整个文件系统相关信息的地方,没有superblock,就没有这个文件系统了。其记录的信息主要有:

  • block与inode的总量

  • 未使用与已使用的inode/block数量

  • block与inode的大小(block为1K,2K,4K;inode为128byte)

  • 文件系统的挂在时间、最近一次写入数据的时间、最近一次检验磁盘的时间等文件系统的相关信息

  • 一个validbit数值,若此文件系统已被挂载,则validbit为0,否则为1

  注:一个文件系统应该只有一个superblock(在blockgroup1上),但后续的blockgroup若含有superblock则其应该主要是作为第一个blockgroup内superblock的备份,这样可以进行superblock的救援

  文件系统描述--File system Description

这个区段可以描述每个blockgroup的开始与结束的block号码,以及说明每个区段superblock/bitmap/inodetable/datablock分别介于哪一个block号码之间

  块对应表--block bitmap

  记录磁盘中使用与未使用的block号码

  inode对应表--inode bitmap

记录使用与未使用的inode号码

  上面我们大致讲述了通过inode对普通文件的访问与inode的结构。在Linux中,一切皆文件,那么目录是如何通过inode访问的,又如何通过目录访问目录中的文件的呢?

  对于目录,文件系统同样会分配一个inode与至少一块block给该目录。其中,inode记录该目录的相关权限与属性,并可记录分配到的那块block号码;而block则是记录在这个目录下的文件名与该文件占用的inode号码数据。

  下面通过访问/testdir/rootdir/f1.txt文件来看一下访问目录下文件的具体过程:

  Linux文件系统与索引节点inode浅析_inode_04

  • 系统首先读取访问文件的文件名(包含路径),根据挂载信息,确定这个文件名对应的文件所在分区,然后去所在分区的根目录开始读取

  • 通过挂载点的信息找到/dev/sda5的inode号码为128的根目录/testdir的inode,且inode具有的权限让我们可以读取该block的内容(有r和x)

  • 取得/testdir的inode中的block号码,并从block中找到/testdir/rootdir目录的inode号码(174)

  • 读取174号inode确定是否具有权限(r与x),取得inode中的block号码

  • 根据取得的block号码,从block的内容中找到/testdir/rootdir/f1.txt文件的inode号码(349)

  • 读取349号inode确定是否具有权限(r),取得inode中的block号码

  • 根据取得的block号码,从block中读取/testdir/rootdir/f1.txt的内容