hello,各位读者大大们你们好呀
系列专栏:【Linux初阶】
✒️✒️本篇内容:认识磁盘(物理结构、储存结构、逻辑结构、读取单位),理解文件系统(分治思想、理解文件系统结构、查找读取新建删除文件的底层逻辑)
作者简介:计算机海洋的新进船长一枚,请多多指教( •̀֊•́ ) ̖́-
之前我们学习了被打开的文件是被操作系统内部的 files_struct结构体管理起来的,那么问题来了,没有被打开的文件要不要被管理呢?答案是要的!
没有被打开的文件存储于 磁盘
中,磁盘上面有大量的文件,磁盘上面的文件会被 文件系统
静态管理起来,方便我们随时打开。
常识补充1
常识补充2
磁盘为什么叫磁盘,因为它得盘片上充满了各种磁化得单元,通过对磁化单元的充磁、退磁转化完成二进制数据的存储。
企业的磁盘损坏之后,企业会对磁盘进行消除数据(多次),大型企业会定制磁盘,让厂商提供磁盘深度清除接口,保证数据安全。
———— 我是一条知识分割线 ————
磁盘的盘片我们外观上是光滑的,但是微观上并不是!
接下来让我们一起来认识一下盘片的结构:
一个盘片有两面,盘面上拥有一圈一圈的同心圆,我们称之为
磁道
。以下图为例,一共有 7个同心圆,因此该盘片的这一面就有 7个磁道。
磁盘寻址的时候,基本单位不是 bit,也不是 byte。一般而言,我们磁盘寻址的基本单位为
扇区
,一个扇区有512byte
。
以盘面圆心向外延申,我们将一个磁道切分为若干个扇形区域,这个区域我们称它为
扇区
。我们可以通过上图中的绿色区域进行理解。
虽然圆心从内而外的扇区周长或者说大小不一样,但是它们的存储空间是一样的,都是 512byte。
———— 我是一条知识分割线 ————
在单面上,我们怎么定位一个扇区呢?
我么通过定位磁道,再找到对应的扇区。具体行为:磁头通过来回摆动确认是在哪一个磁道(磁头是横向摆动的),再通过盘片旋转的相对运动来定位扇区(转速非常快)。
这也就是为什么磁盘在运行时需要磁头来回摆动、盘片高速旋转的原因。
上面我们学习了磁盘的单面结构,实际上,我们磁盘是多盘多面的复式结构。
我们将各个盘面,同半径的圆上下视为一个整体,这就是
柱面
。具体可通过上图理解。
磁头数 = 盘面数,磁头是共进退的,所有磁头的移动方向是一致的。在同一时间段内,磁头可以在同一柱面上的所有磁道进行查找。
———— 我是一条知识分割线 ————
如何在立体结构的磁盘中,定位一个扇区呢?
对于立体的磁盘结构来说,定位一个扇区,需要:
先定位磁道(柱面),再定位磁头(定位盘面),最后再定位扇区
。
磁道(track),柱面(cylinder),磁头(head),扇区(sector)
磁盘中定位任何一个扇区的,采用的硬件基本方法为:CHS定位法!(cylinder - head - sector)
以此类推,我们就得出了定位任意多个扇区的方法。
———— 我是一条知识分割线 ————
不知到大家小时候有没有听过磁带,我们的磁带在新买回来的时候是卷好的(圆形的),但是我们将它们抽出来后,我们发现其实它是一个线性结构。
我们的磁盘实际上和磁带的物理结构是类似的,因此,我们也可以将磁盘盘面逻辑想象成一个线性结构,来帮助我们理解磁盘的逻辑结构。
磁盘物理上是圆形的,我们可以将磁盘抽象成线性结构。
为了方便后续学习,我们假设我们的磁盘有两个盘,四个面,共500G存储空间,且有 3个柱面。
盘面中有柱面(一个个磁道),根据条件,得出有三个柱面。每个柱面中又包含一个个扇区。当我们将扇区进行统一的编号,我们就可以以扇区作为最小单位,将整个磁盘从逻辑上看作成为一个 sector arr[n];
就此,我们就可以将对磁盘做管理,转变成对数组做管理。
———— 我是一条知识分割线 ————
所以,我们要怎么找到一个扇区呢?
很简单,只要找到这个扇区的 下标 ,就算定位了一个扇区。 在操作系统内部,我们称这个下标为 LBA地址。
之前我们不是说定位扇区需要使用 CHS定位法吗?这个又怎么体现呢?
下面我再举一个例子帮助大家理解:假设有 4个盘面,每面有 10个磁道,每个磁道有 100个扇区:
我们首先可以判断出来:总容量、下标范围、每一面有多少个扇区。
我们以查找 123号扇区的磁盘位置为例,讲述CHS定位法:
虽然磁盘对应的访问的基本单位为 512字节,但依旧很小!因此,OS内的文件系统会定制的进行多个扇区的读取 -> 以 1KB,2KB,4KB(使用最广泛,KB-千字节)为基本单位。哪怕你只修改了 1bit的数据,也必须 将 4KB load到内存,进行读取或修改,如果必要,再写回内存。
为什么 4KB为基本单位,使用最广泛呢?
局部性原理:当我们的计算机去访问某些数据时,它附近的数据也有非常大的数据被访问到。
【总结】
所以从本质上来说,这种行为属于:1.数据预加载; 2.以空间换时间。
我们的内存实际上被划分成为了一个个 4KB大小的空间,这些空间我们称之为 页框
。
磁盘中的文件尤其是可执行文件 - 它们都是按照 4KB跨分好的块,这些块我们称之为 页帧
。
【总结】
数据 IO的过程,实际上就是将磁盘数据转变成页框的过程,这是文件系统和内存管理之间的融合,它们都是以 4KB大小为单位的。
一个磁盘的存储容量是很大的,因此我们可以通过将整体切分成小块(分区、分组)进行管理,通过对多个小块的管理,最终实现对整体的管理,这种思想我们称之为 分治思想
。
不同文件的分组大小不一样,5G只是一个例子,是我随便写的
以 5G为例,对该部分的存储结构进行剖析。
———— 我是一条知识分割线 ————
分区之后会格式化写入,格式化的本质就是 写入文件系统
。
我们以 Linux ext2文件系统为例进行讲解,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。
Block Group
:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。为了方便讲解,下文中我会将 Block Group简称为 分组。
我们对 Block Group的内部结构再做进一步的拆分:
超级块(Super Block)
:存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。超级块对于一个分组来说不是必须的,但是它的多存在,可以让文件系统实现备份。假如有一天我们常用的 Super Block出现了问题,没关系,我们只需要将其他组的 Super Block拷贝过来即可,这样就避免了出现故障时数据的大规模丢失。
常见的场景有:文件打开故障,计算机询问你是否进行恢复,底层问题可能就是文件的某些分组的字段出现了问题被文件系统查到了,因此文件系统将其他分组的 Super Block进行了拷贝,最终完成了对文件的恢复。
———— 我是一条知识分割线 ————
文件 = 内容 + 属性,Linux的文件内容和文件属性是分批储存的,其中存储文件属性的单元我们称之为 inode
。
inode的大小是固定的,每个文件都有一个 inode,它存储了一个文件几乎所有的文件属性,但是文件名不包括
。inode存放文件属性 如 文件大小,所有者,最近修改时间等。
文件内容被保存在 Data blocks(数据区)中,它的大小随着应用类型的变化而变化。
总结:inode大小不可变,Data blocks大小可变。
我们知道,每个文件(打开+未打开)都有自己的 inode,为了彼此区分,每个 inode都有自己的 ID。
ls -li #查看文件ID指令
inode table
:保存了分组内部所有可用的(已经使用的+没有使用)inode,包括 inode内部的属性信息。Data block(数据块)
:保存的是分组内部所有文件的数据块,一个文件的内容会被放在其中1个或n个块中。我们可以视分组内所有数据块为一个数据区。总结:inode table保存文件的 inode,inode保存文件属性,Data block(数据块)保存文件内容。
inode table内保存的 inode数量是有限的,因此在我们创建一个新文件之前,我们需要在 inode table中找一个没有被使用的 inode,然后将我们新文件的属性填充到这个 inode中.
同理,我们新创建的文件,需要将数据填充到还没有被使用的数据块中。
至此,一个文件的内容和属性都被写入进磁盘中。
总结:新创建的文件需要申请还没有被使用的 inode和数据块。
———— 我是一条知识分割线 ————
根据上面的讲述,我们推断出,在创建文件之前我们需要一个功能,那就是查找。我们需要知道哪些 inode被使用,哪些没有被使用,数据块也如此。文件系统通过 inode位图和块位图(Block Bitmap)帮我们解决了这个问题。
inode位图(inode Bitmap)
:inode对应的位图结构,用每个bit表示一个inode是否空闲可用。举一个简单的例子理解位图,0000 1001,表示某个inode已经被占用,当位图变为 0000 0001,说明该inode被释放了,当前没有被占用,其中我们只用了一个比特位就对该 inode进行了标识。
总结:位图中的比特位位置和 文件的inode位置是一一对应的。
块位图(Block Bitmap)
:数据块对应的位图结构,Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。总结:位图中的比特位位置和 Data block(数据块)的位置是一一对应的。
新文件创建时,在计算机知道文件大小等属性信息后,会给文件申请足够大小的块用于放置我们的文件信息。
GDT,Group Descriptor Table
:块组描述表,描述块组宏观属性信息,有兴趣的朋友可以在了解一下,这里不深入。———— 我是一条知识分割线 ————
查找一个文件的时候,我们统一使用的是 inode编号(ID)
。
inode可以跨组,不可跨分区,在一个分区中,inode的编号是统一编篡的,比如说前面分组的 inode的起始编号是1000,后面的某个分组的 inode起始编号是 10000。
我们直接上图理解:
inode中存有 block有关的数组,数组对应指向不同的数据块,通过对不同数组数据的读取,就得到了不同的数据块的位置(通常获取的是起始和结束数据块),再通过数据块的组合,就知道了该文件所有的数据块位置。
这种一个数组单位只指向一个数据块的方式,实际上储存的数据块信息有限,因此从12号下标位置开始,指向的就不是普通的数据块,而是保存有其他数据块的地址(block id)。
如果还担心不够,13号、14号下标中存的是 block id的二级、三级索引,也就是它们指向的数据块也是保存其他数据块地址的数据块。就此,实现了很大的地址存储空间结构。
总结:创建文件,在位图中将对应的比特位由 0置1,根据比特位对应的文件位置,找到对应的 inode table,将文件属性填充到文件自己的 inode中,再将对应的文件数据填充到Data block(数据块)中, 建立 inode table与Data block(数据块)之间的映射关系,建立成功后返回对应的 inode编号,至此文件创建成功。
查找读取文件时,直接根据 inode编号找到inode table,再根据inode table与数据块之间的映射关系,这样文件的属性和数据就全有了。
———— 我是一条知识分割线 ————
找到文件在 inode位图(inode Bitmap)上的比特位,将 1置0,这个文件就被删除了。这个行为意味着,被删除文件中的 inode属性无效了,一旦inode无效,它内部与数据块之间的映射也就无效了。当然,数据块在文件删除过后也是需要被清理掉的,但是什么时候清理由文件系统说了算。
总结:删除一个文件就是将inode位图(inode Bitmap)上的比特位由 1置 0.
这就是,我们在计算机删除一个文件,却可以在回收站找到并恢复的原因。
文件恢复的本质:将被删除文件的 inode位图(inode Bitmap)上的比特位由 0置 1.
当我们不小心删除了一个重要文件,在我们不懂得如何修复的情况下,最好什么都不要做。因为你一旦对计算机做了某些操作,新建了某些文件,就有可能导致被删除文件的 inode被新文件启用,数据块被新文件覆盖,最终导致无法恢复。
Linux下,文件的删除信息会保存在日志中。所以Linux被删除的文件也可以被恢复,但通常都要配合相关工具才能完成。
你不是叫我用 inode吗,我什么在我们Linux操作系统下都是用文件名删除的呢?
任何一个文件都是在某一个目录里面的,而目录也是一个文件!因此,目录也会有自己的文件属性和数据,属性存储于 inode,而数据块中放的就是该目录下所有文件的文件名
和 各自inode的映射关系
。
在同一个目录下不能存在同名文件,因此,操作系统就可以根据文件独有的文件名 缩映到对应文件的 inode了!有了 inode,我们之前提及的文件的增删查改就全部成立了。
这是因为,新增文件时,需要向当前目录的内容部分写入文件名 和 对应inode的映射关系的!因此必须要有写入权限。
这是因为,我们必须根据目录 inode,访问目录对应的数据块,才能找到对应的文件属性。
【Linux初阶】基础IO - 磁盘 & 文件系统的知识大概就讲到这里啦,博主后续会继续更新更多C++ 和 Linux的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!