Linux相关概念和易错知识点(19)(HDD、Block group)
目录
1.HDD
(1)HDD存储描述
(2)HDD结构图
(3)磁盘管理的分治思想
(4)硬盘中文件系统的整体划分图
2.Block group
(1)文件管理
①文件属性的存储
②inode分配和管理
③Data blocks存储和inode存储的解耦合、组的设计和文件设计的解耦合
④常见文件管理
(2)分区的格式化
(3)inode如何映射数据块
(4)inode和文件名的映射
1.HDD
(1)HDD存储描述
HDD磁盘是利用磁铁的磁性来存储数据的。永磁铁的两个磁性分别对应数据的0、1。一块HDD磁盘实际上是由三块竖直叠放的磁盘(正反共6个面)构成的,每个面都可以存放数据。每个面都有磁头紧贴但悬空在盘面上。所有磁头连接在一个传动臂(机械臂杆)上,由传动臂的运动来定位磁盘不同位置。所有磁头从竖直方向看都始终重合,它们受传动臂约束同步运动,都指向每个盘面的同一个相对区域。
(2)HDD结构图
下面是对HDD物理结构和逻辑结构的剖析,按照顺序看完,我们就能大致明白HDD的写数据模式了。
(3)磁盘管理的分治思想
通过上图的解析,管理磁盘从管理物理结构变成了对数组的管理,但磁盘太大,OS不可能一次性全部管完,因此就像我们国家分成多个省一样,磁盘需要分区管理。每个分区互不干扰,一个分区坏了不会影响另一个分区。同时仅仅分区还是太大了,磁盘的每个分区还分成了几个组(Block group),我们只需要管理好每个组就可以了。一个组里面又由多个部分组成,每个都对文件的存储有特定的管理,我们后续会讲到。我们需要注意的是,OS管理数据的最小单位是数据块(一般都是几KB,而不是扇区),每次写入读出都是以数据块为单位进行的。
总之,我们在这一步需要进一步理解磁盘管理的分治思想,这是后面详细理解每个组里面的不同部分的功能的关键。
(4)硬盘中文件系统的整体划分图
每一层向下划分都有对应的管理者,如分区表、BootBlock、超级块,我们了解即可。我们重点关注每一组下面的其它分组,理解整个文件存储和读取流程对我们认识文件很有帮助。
2.Block group
(1)文件管理
文件 = 文件内容 + 文件属性
①文件属性的存储
文件属性通过inode的结构体专门存到Block group的inode Table里面(每个文件都有自己独一无二的inode,inode都配有一个编号用于唯一性标识)。inode里面存储了当前组所有文件的属性信息(权限、属性、大小等,但注意文件名不存在inode里面)。每次存储一个inode,inode Bitmap和GDT里面都会进行相应的更新,这些细节我们注意即可。
但有一点非常重要,inode是以分区为单位分配的,不能跨文件系统。每个分区一套inode编号方法,因此不同分区的inode编号有可能相同。但在同一分区下,inode是全局且唯一的,针对不同组inode永远不会重复。
②inode分配和管理
由于inode在一个分区里是全局且按顺序分配的,GDT存储inode在该组的起始编号,这个起始编号对应inode Bitmap和inode Table的第0位,同时GDT还掌握该组允许的inode最大数量。每个组的GDT都这样处理,由此一来查找inode就会变得非常简单,仅需对GDT进行访问即可知道该组有没有要查找的inode
因此创建inode会依次到inode Bitmap里面找0位置,再对应到inode Table里面开辟空间并写入数据,最后更新GDT和inode Bitmap。之后就需要存储内容了。我们需要知道,存储数据时会在GDT找Block Bitmap的空闲块,最后在对应的Data blocks存数据。但如果这个时候Data blocks存满了呢?inode是白白创建了吗?我们需要删掉这个inode,直到找到一个能存数据的组再创建inode并存储吗?
③Data blocks存储和inode存储的解耦合、组的设计和文件设计的解耦合
数据块号和inode都是全局建立的,可以跨组。在Data blocks中每个数据块都有自己的下标,由GDT里面存储的起始块号 + 当前下标就能得到Data blocks里面的全局数据块号。这就导致数据块在全局都不会搞混,同一分区下可以跨组。
当我们要存储数据时,会根据GDT里面的inode分配情况先找到空位。这里我们需要注意每个组inode的个数,Data blocks里面数据块的个数都是固定的。当找到空位置之后,inode就被创建下来了,这个时候再去根据GDT找数据块的分配情况,将有空位的数据块占用了,并将占用的数据块号存到inode里面。这个块号是全局的,只要找到了inode,根据里面存储的块号一定能找到数据块,就算数据存在和inode完全不同的组。
我们能够发现,这样存数据,inode可以依次将所有组中inode Table填满,Data blocks也能依次存储,它们之间不需要强行要求一起存在一个组。数据存自己的,inode也存自己的,磁盘存储数据的利用率也会上升,只要inode里面用块号定位数据块就永远不怕定位失败。这就叫Data blocks存储和inode存储的解耦合。同时组的设计和文件的存储解耦合,文件存储再也不受组的限制。
理解了这一点,分配和定位inode、数据块都不再是问题,只需要比较起始inode或起始块号 + inode或块号的存储个数就能找到对应的数据,具体而言我们可以通过inode里面的数据块号找数据,也能通过块号反定位inode,这些都是可行的。到这里,我们也能理解为什么inode和块号会设计成全局。
④常见文件管理
如何查找文件?知道分区和inode编号后,先通过GDT确定组,再通过inode Bitmap和inode Table确定inode内容,进一步确定块号,和查找inode的方法一样找到文件。
如何删除文件?先查找inode,直接将inode Bitmap置0即可,再根据inode内容找到数据块号,根据块号去找Block Bitmap并置0,与此同时GDT更新数据块和inode的空闲情况。这也告诉我们如果误删了文件,最好的办法是什么都别做,因为所谓删除只是修改状态,想办法修改回Bitmap和GDT是最重要的,如果这部分磁盘被新数据覆盖了就无力回天了。
如何修改文件?先将inode或内容加载到内存中,修改了再写回去。
如何新增文件?先根据GDT找一个组(参考文件大小、名称等),具体根据inode Bitmap来分配inode,再在全局范围内分配Block Bitmap。GDT时刻更新。
以上就是在硬盘侧对文件的管理,那么OS侧应该通过什么渠道来管理呢?遍历寻找inode或块编号是怎么进行的呢?
我们只需将Super Block和GDT的内容保存在内存中,进行内存级操作和访问,就能进一步对inode编号、块编号等做出判断并及时操作。这依然是先描述再组织的思想。
(2)分区的格式化
当我们进行分区格式化时,就算当时我们不写数据,也要初始化组里面的各个部分,针对GDT、Bitmap、Table、blocks写入一些基本信息,这叫格式化。格式化的本质是向一个分区写入空的文件系统,注意这是以分区为单位的,对一个分区进行格式化不会影响其他分区。
(3)inode如何映射数据块
inode作为文件属性,它是如何映射到数据块呢?我们只知道大概是通过存储全局块号进行的,但具体怎样仍未讲清楚。
inode里面有一个数组int block[15]存储全局的块编号。前12个直接映射全局块号,能直接通过GDT映射到块中,这些块直接存文件数据。后续三个其实也是全局块号,但对应里面存的数据并不是文件数据,而是一级、二级、三级间接块索引表指针。
一级间接块索引指针大小就是一个数据快的大小,它的内容是除最开始12个块以外其它存文件数据的块号;二级索引指针也不保存文件数据,数据块里存的是其它一级索引的块号;三级索引指针存二级索引指针的块号。三级指针保证文件大小上限能够达到TB级别,同时保证inode里面的数组int block[15]大小恒定,都是15 * 4个字节。这就使得所有文件的inode大小都是恒定的,文件的最不可控因素就是文件的大小,当这个存储索引的问题解决后,所有文件的inode都可以是固定字节的。
因此inode这个结构体大小固定、稳定,可以有效提高文件的访问效率。
(4)inode和文件名的映射
文件名不属于inode,文件名是目录文件的内容。文件名和inode在目录文件中组成了一一映射的关系,当我们使用文件名进行定位时,本质是转换为inode进行定位。但目录文件是什么?我们需要进一步介绍。
目录文件本质也是一个文件(inode属性 + 内容)。目录的内容(即Data blocks存的内容)里面存的是文件名和inode的映射关系。当我们用文件名查找时,就在当前目录文件里映射查找inode,这也能解释同一级目录下不能有同名文件,这违反了map的基本特性。
理解到了这一点,我们重新梳理目录权限,没有r就没办法读取文件名和inode,拿不到inode,自然无法显示具体信息;同样的,无w就写不了映射关系,也就无法新建文件,改变文件映射等;没有x本质上就意味着打不开目录文件。很明显,像ls -i -l操作就是通过文件名的映射,获取inode里面的部分属性向我们展示的。
从这种映射关系中,我们也知道了对Linux系统来说,文件名、用户名这些字符串会降低系统效率,对系统来说,inode编号、UID等数字的处理才是高效率的。