关于ext4文件系统的一点疑问,以及文件系统中文件操作的原理

1、Ext文件系统块组分布与内容存储顺序

《鸟哥的Linux私房菜》与cnblog骏马金龙博客中给出的文件系统(挂载到linux目录树的ext文件系统)的block分组示意图为:

看起来像是,每个block组的inomde bitmap、block bitmap、inode talbe都在自己block组中,但我通过

sudo dumpe2fs -g /dev/sda8

查看到的block组描述符信息为:

可以看到,块组0到块组7的block bitmap分别连续位于125到132块,inode bitmap分别连续位于133到140块,inode table分别位于141、636、1131、1626、2121、2616、3111、3606块,即每个块组的block bitmap、inode bitmap、inode table均位于0号块组中(0-32767号block,第二列表示各个块组中的第一个块的编号),并且各个块组的block bitmap和inode bitmap所在块是相连的,并不是文件系统块组示意图中表示的那样在各自块组内部。

直接显示观察块组详细内容:

sudo dumpe2fs /dev/sda8

看到,/dev/sda8文件系统从块0开始依次存储:组0主超级块0——组0描述符表(GDT)1——组0保留的GDT块2-124——组0块位图125~组7块位图132——组0 inode位图133~组7 inode位图140——组0 inode表141-635~组7 inode表3606-4100——×××——组0可用块4107-32767——组1备份超级块32768——组1组描述符表(GDT)32769——组1保留的GDT块(保留扩充组描述符表)32770-32892——组1可用块32893-65535——×××组2缺失部分——组2可用块69632-98303——组n(【备份超级块+组描述符表(GDT)+保留GDT块】,如果有的话)+可用块。。。

说明文件系统各个块组除了主(备份)超级块+组描述符+保留组描述符表GDT块是随块组存储之外,各个组的块位图在组0中连续存储,各个组的inode位图在组0中连续存储,各个组的inode表在组0中连续存储,这和示意图中表达的不一样,只是深究一下而已,示意图能帮助理解文件系统块组的状态。

2、单文件系统中文件操作的原理

转载自骏马金龙《单文件系统中文件操作的原理》

2.1读取文件

当执行"cat /var/log/messages"命令在系统内部进行了什么样的步骤呢?该命令能被成功执行涉及了cat命令自身bash文件的寻找、权限判断以及messages数据文件的寻找和权限判断等等复杂的过程。这里只解释message数据文件的寻找

①找到根目录所在文件系统的块组描述符GD所在的blocks,读取GDT(已在内存中),找到inode table的block号

说明GDT记录了块组0的inode table的block号,因为根目录肯定是其所在文件系统(磁盘分区)的块组0中;

如骏马金龙文章前部分介绍,ext文件系统每一个块组信息使用32字节描述,这32个字节称为块组描述符,ext文件系统不是将每个块组的描述符分别放在各个块组中,而是将文件系统内所有块组描述符组成块组描述符表GDT(Group Descriptor Table),并将该GDT存放于某些块组中,存放GDT的块组和存放superblock和备份superblock的块相连,也就是说他们是同时出现在某一个块组中的。读取时也是读取块组0的块组描述符表GDT。

因为GDT总是和superblock在同一个块组(块组0或其他含备份的块组),而superblock总是在文件系统的第1024-2047个字节(第1KB-第2KB)的位置,所以很容易就知道第一个GDT所在的块组以及GDT在这个块组中占用了哪些block(若是1KB块,则GDT从第2KB开始,即第3个块;若是2KB块,则是第2个块;若是4KB块,则是第1个块)。

其实GDT早已经在内存中了,在系统开机时会挂载根文件系统,挂在的时候就已经将GDT放进内存中了。

②在inode table的block中定位到根目录/的inode,找出根目录/指向的data block

前文说过,ext文件系统预留了一些inode号,其中根目录/的inode号为2,所以可以根据inode号直接计算出在inode talbe中的偏移量,找到根目录/的inode记录,从而定位到根目录目录文件的data block

③在根目录/的目录文件data block中记录了var目录名和var目录的inode号,到inode table中找到该inode记录,inode记录中存储了指向var的data block指针,所以也就找到了var目录文件的data block

在根目录/中通过var目录的inode号找var目录的inode记录时,需要知道去哪个块组的inode table中寻找,这需要知道每个块组中的inode号区间,同样需要读取已经缓存在内存中的GDT。另外,即使每个块组的inode号连续,但只要某个块组中平均每个inode占用超过默认比例分配的4个block,则那个块组的inode将不能充分使用,会有inode浪费,所以每个块组已用inode号就不会连续了,一般是少量inode用尽了所有block)

④在var目录的data block中记录了log目录名和其Inode号,通过该inode号定位到该inode所在块组,在该块组的inode table中找到log目录的inode记录,根据该inode记录找到log目录的data block

⑤在log目录的data block中记录的messages文件名和对应的inode号,通过该inode号定位到该inode所在的块组即其inode table,找到inode记录,并最终找到messages文件的data block

⑥最后读取messages的data block

当然,访问目录或文件的data block前均要根据inode记录中的权限、UID、GID查询当前用户是否有权限;

2.2删除、重命名和移动文件

只讲不跨越文件系统的操作。

2.2.1删除普通文件

①找到文件的inode记录和data block;

②首先将inode table中该inode记录中的data block指针删除;

③将inode bitmap中该文件的inode号标记为未使用;

④在其所在目录的data block中将该文件名所在的记录行删除,删除了记录就丢失了指向inode的指针,外界再也无法看到这个文件了。(实际上不是真的删除,直接删除的话会在目录data block的数据结构中产生空洞,所以实际的操作是将待删除文件的inode号设置为特殊的值0,这样下次新建文件时就可以重用该行记录);

⑤将block bitmap中data block对应的block号标记为未使用(开始释放空间,这些data block可以被其他文件使用了);

2.2.2删除目录文件

①找到目录和目录下所有文件、子目录、子文件的inode和data block;

②在inode bitmap中将这些inode号标记为未使用;

③在该目录的父目录的data block中将该目录名所在的记录行删除;

需要注意的是,删除父目录data block中的记录是最后一步,如果该步骤提前,将报目录非空的错误,因为在该目录中还有文件占用。

2.3移动文件

同文件系统下移动文件实际上是修改目标目录的data block,将原目录中inode号-文件名项的inode号置零,向目标目录添加一行指向inode table中待移动inode记录的inode号——文件名项,如果目标路径下有同名文件,则会提示是否覆盖,实际上是覆盖目标目录data block中冲突文件的inode号——文件名项,由于同名文件的inode记录号被覆盖,所以无法再通过目标目录找到那个重名文件的data block,该文件的inode号、inode记录、data block号可能被删除|释放(如果重名文件有多个硬链接,则重名文件的inode号、inode记录、data block仍会存在);

所以在同文件系统内移动文件相当快,仅仅对原目录data block删除一条记录,对目标目录data block添加或覆盖一条记录。也因此,移动文件时,文件的inode号是不会改变的。

2.4存储和复制文件

①读取块组描述符表GDT(见上,有各个块组号、起始block号、(备份)超级块号、GDT块号、block bitmap位图块号、inode bitmap块号、inode table块号),找到各个(或部分)块组imap中未使用的inode号,并未待存储文件分配inode号;

②在inode table中完善该inode号所在行的inode记录,有文件类型信息、文件权限、硬链接数、UID、GID等;

③在目录的data block中添加一条该文件的inoe号-文件名的记录;

④查询块组bmap中未使用的block,将数据填充到data block中。

    i。注意,填充data block的时候会调用block分配器:一次分配4KB大小的block数量,当填充晚4KB的data block后会继续调用bock分配器分配4KB的block,然后循环直到填充完所有数据。也就是说,如果存储一个100M的文件需要调用block分配器100*1024/4=25600次;

    ii。另一方面,在block分配器分配block时,block分配器并不知道真正有多少block要分配,只是每次需要分配时就分配,在每存储一个data block前,就去bmap中标记一次该block已使用,它无法实现一次标记多个bmap位。这一点在ext4中进行了优化。

⑤填充完后,去inode table中更新该文件inode记录中指向data block的寻址指针。

复制文件的步骤与存储文件的步骤一样。

2.5根文件系统的特殊性

任何一个文件系统要在linux上能正常使用,必须挂在到某个已经挂载好的文件系统中的某个目录下,例如/dev/cdcom挂在在/mnt上,/mnt目录本身是在根目录/文件系统下。而且任意文件系统的一级挂载点必须是在根文件系统的某个目录下,因为只有根目录/是自引用的。需要说明挂载点的级别和自引用的概念。

我的目录层级:根目录/挂载在/dev/sda6磁盘分区,这是安装Linux系统时分好的。/dev/sda4分区挂载在/media/haypin/LENOVO/上,那么/media/haypin/LENOVO/就是一级挂载点(直接挂载在根目录文件系统上),此时/media/haypin/LENOVO/已经是文件系统(磁盘分区)/dev/sda4的入口了,而/dev/sda8所挂载的目录/media/haypin/LENOVO/Test/又是文件系统/dev/sda4中的某个目录,那么/media/haypin/LENOVO/Test/就是二级挂载点。

一级挂载点必须在根文件系统下(根目录挂载的文件系统),所以可以简述为:文件系统2挂载在文件系统1的某个目录下,而文件系统1又挂载在根文件系统中的某个目录下。

再解释自引用。首先要说的是,自引用只能是文件系统,而文件系统表现形式是一个目录,所以自引用是指该目录的data block中,"."和".."的记录的inode号都对应inode table中同一个inode记录,所以它们inode号是相同的,即互为硬链接。而跟文件系统是唯一可以自引用的文件系统。

注意到,根目录下的"."和".."都是"/"目录的硬链接,且其data block中不记录名为"/"的条目,因此根目录的硬链接数为2;

由此也能解释cd /.和cd /..的结果都还是在根目录下,这是自引用最直接的表现形式:

2.6挂载文件系统的细节

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值