🌎Linux文件系统
文章目录:
Linux文件系统
简单认识磁盘
文件系统
磁盘线性结构抽象
文件系统存储方法
inode Table
inode Bitmap
Data Block
Block Bitmap
Group Descriptor Table
Super Block
文件名的作用
重谈文件的增删查改
总结
前言:
文件系统作为Linux重要组成部分,本文我们就针对Ext2文件系统进行详细解读,了解该系统如何将文件管理的井井有条。
🚀简单认识磁盘
我相信只要使用过电脑的人都对磁盘这个词不陌生,我们通常在买电脑的时候也会根据磁盘的大小做选择,磁盘作为计算机的存储设备也是很重要的一个部件。
以上就是一个常见的磁盘,结构上有:盘面(hard disk)、磁头(Head)、悬臂、以及 马达 等部件。当磁盘工作时,悬臂不断带动磁头在盘片上摆动,磁头和盘面之间并 不是直接接触,中间有一段距离。工作时是通过磁性进行IO交互的。
通常,磁头和盘面都是一对一的关系,不止一对。并且磁盘越多容量越大。在盘面上,以磁盘重心为圆心,被划分为一圈圈的 磁道,而在一个盘面上像切大饼一样将不同的磁道切割为了一个个扇形区域,叫做 扇区(Sector)。
通常来说,磁盘的盘面都不止一个,通常是很多个,而每个盘面都被划分了相同的磁道,并且磁盘之间是上下关系,形成了一个圆柱体。而在所有盘面中相对位置所划分的相同磁道,也被我们称为 柱面(cylinder)。
肉眼可见,最内侧的磁道扇区面积最小,因此数据密度最大。并且每个 扇区都是固定大小,通常为 512byte 或者 4kb。一个磁道通常会划分63个扇区,所以 扇区是硬盘上的最小单位。
为了区分每个扇区的位置,扇区是早早被编了号的,同样因为有多个磁头,磁头也被编号,1号磁头,2号磁头等。柱面也被分为不同柱面。
而有了这三样,柱面(Cylinder)、磁头(Head)、扇区(Sector),进行IO读写的时候,首先定位磁头,再定位柱面、最后定位扇区。这样我们就可以找到磁盘上的任意一个位置了,这样的定位方法称为 CHS 定位法。
🚀文件系统
✈️磁盘线性结构抽象
但是磁盘这种物理存储模式不易管理,我们可以将磁盘的存储空间看作 “磁带”,而我们把磁带全部展开,得到一条长的 “磁带”。
我们可以将这条磁带看作磁盘的物理存储空间,并且按照扇区为最小单位划分为了一个长的数组,数组的每个元素就是一个扇区。假设我们磁盘有800G,那么数组的长度就为:array_length = 800*1024*1024*1024 / 512 = 1677721600 。
那么我们就可以根据数组下标来找出对应的扇区了。这样,我们就把 操作系统从对磁盘的管理 转化为了对数组的增删查改。那么我们只需要将数组下标与CHS定位相互映射,就可以对扇区进行简单操控了。
但是我们的目的是为了对所有文件做管理,现在显然是不够的。文件分为属性和内容,那么哪些扇区存属性那些扇区存内容呢?我们都不得而解。所以我们需要继续抽象。
其实计算机读取磁盘的最小单位为 4kb,因为如果每次读取仅仅读取一个扇区效率太低了,所以干脆每次读取 4kb数据,就算只更改一个文件的一个比特位,也会访问这4kb的空间。也就是说,操作系统 读取的最小单位为连续的8个扇区(4*1024/512)。
8个扇区为一组,可以把前面的数组看成一个有8个扇区为最小单位的新数组。我们将这个数组成为 逻辑块地址(Logical Block Address) 简称 LBA。
从此以后,操作系统对磁盘的管理变为了对 LBA数组的管理,于是操作系统每次进行IO读写的最小单位就是 4kb 大小。
而这个 “磁带” 共有800GB,太长了,有时候会被人为的分成不同的区域,每个区域根据人的分配大小不定,这个分配不同区域的过程就是 分区。比如我们系统中的C盘、D盘、E盘等。
这里我假设给 800GB的磁盘分了三个区,大小分别是 100GB、300GB、400GB。那么如果我们能把一个分区管理好了,剩下的就一定能依照那个分区来管理好。而一个分区的内容还是太大,继续将分区进行细分,分为不同的组。
我们可以使用如下命令来 查看Linux机器中磁盘的分区 情况:
ls /dev/vda* -l#查看分区情况
比如我当前正在处理100GB的分区,将其分组为10个组,每个组10个G。那么我们只需要管理好一个组,整个分区就能同理进行管理,那么整个磁盘也就能同理进行管理。这种 分治 的方式让我们把 操作系统对整个磁盘的管理 转化为了对分区的一个组进行管理。
那么我们接下来研究好如何对一个组10个G进行有效的文件管理,进而就可以扩散到对整个磁盘800个G做管理。
✈️文件系统存储方法
我们都知道,在Linux下 文件 = 内容 + 属性。但在Linux下 文件的内容和属性是分开存储的,因为文件的属性是固定的,而文件的内容并不固定,可能很大也可能很小。
我们可以通过 ls 命令查看文件的一些属性信息:
文件的属性和内容是分离的,而 文件的属性信息又被称为 元信息,存放元信息的结构叫做 inode。每个文件都有自己的inode,为了区分不同的inode,他们被分配了编号,使用如下命令可以查看inode编号:
ls -ail#查看inode编号
可能有人会问,文件的属性就一定是固定的吗?文件名就不固定啊?我的答案是,文件名不属于文件的属性!当然除此之外文件确实也有很多的属性。我来举一个例子:
阿熊是一个大学生,计算机专业,他身高185,爱打篮球,打的还不错,班级成绩一般,没挂过科,爱听音乐尤其是周杰伦的,今年大二,体重75公斤,编程竞赛拿过第一,至今单身…这是阿熊对自己的总结。
但是学校领导需要看到学生的数据,于是对阿熊提供的数据进行总结,总结起来就是:阿熊身高185、体重75公斤、计算机专业、大二。
从例子中我们可以知道,属性可以有无穷无尽,但是真正主要的信息总是有限并且重复的,阿熊被学校领导抽离出来的信息难道别的同学就没有吗?仅仅是信息的内容不同罢了。
文件也是一样,文件的有用属性被抽离出来,让操作系统对其进行管理,如何进行管理?先描述、再组织!
struct inode
{
类型
大小
权限
时间
...
}
所以,文件的属性大小一定是固定的,每个文件的属性类别相同,内容不同。且通常 一个inode属性的大小通常为 128字节。
我们把视角拉回分组,一个分组10个G,那么一个组究竟是如何将文件管理起来的呢?其实分组又被分为了几个区域:
一个组被划分为了6个不同的部分,我们一一来了解这些部分的构成和作用。
🚩inode Table
- 节点表(inode Table):存放文件属性 如 文件大小,所有者,最近修改时间等。
Linux下一切皆文件,那么在这10个G的分组中可能存在大量的文件,假设当前分组存在 10000 个文件,而10000个文件就有10000个inode,所以这些inode就会在这10个G的某个共同区域连续存放,这个区域我们叫做 inode表,也就是节点表。
所以在inode Table中存放着很多inode,每个inode占用128byte空间,每个空间可以写入一个inode的文件属性。所以我们只需要 知道一个文件在 inode Table中的位置,就能拿到该文件的属性。并且 inode 编号在整个 分区 内唯一。
🚩inode Bitmap
- inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
inode Table确确实实存放着文件的属性,但是,是每生成一个文件才会生成一个inode编号吗?非也,其实inode编号是已经被编排好的,它是有范围限制的,当有文件生成时,会给新文件分配一个未使用的inode编号。
那么如何区分inode编号到底有没有使用?这就inode位图的工作了,inode位图上比特位的位置表示inode的位置,而 比特位的0、1表示inode的使用情况,0为未使用、1为已经占用。这样就可以简单快速的判断一个inode是否被占用。
而我们要 删除一个文件,其实并不需要删除文件的内容和属性,只需要将inode位图对应文件的inode置为0即可,这样下次再分配到这个编号的时候内容和属性就会被新的文件覆盖了。
🚩Data Block
- 数据区(Data Block):存放文件的内容。
文件的属性存放在inode Table中,而文件的内容存放在块组中,所以data block是文件内容的集合,每一个块组4kb大小,并且每个块组拥有对应的编号,同样,块组并不是文件创建时才开辟的空间,而是在文件创建之前就已经将块组分配好了,只是在创建文件时将提前分配好的空间拿去用。
文件的属性和内容分开存储,那么我们如何得知 inode 和 data block 的对应关系呢?实际上在inode结构体内有着data block的数组:
struct inode
{
int block[15];
//...
}
所以,只要我能够找到文件的inode,那么我就一定能找到block数组,找到了数组就一定能找到数组对应的每一个data block。肯定会有人问:我们block只有15个元素,也就是60kb,那很多时候也不够用啊?
没错,60kb确实不够用,所以在block数组也做了调整,其中 [0,11] 的12个元素正常指向12个普通data block。[12,13] 这两个元素 并不直接是保存文件数据的data block,这 两个元素指向的data block内保存的其他块组的编号,两个就是保存8kb的编号。
8kb的空间看来能保存不少data block编号,但是还是可能出现不够使用的情况,所以block数组的最后一个元素 block[14],也并 不直接保存文件 的数据,而是 其他文件的data block编号,而这些编号所对应的块组 也不直接保存数据,而是 保存更多的data block编号。如此套娃,文件就有足够大小了。
🚩Block Bitmap
- 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。
与inode bitmap大差不差,因为data block 也是有编号的,所以文件在创建的时候需要确认哪些data block没有被占用,所以需要用位图来进行判断,0为未占用、1为占用了。同样,如果要删除一个文件的内容,只需要将对应的位图置为0即可,等到下一个新建文件分配data block时自然会将其覆盖。
🚩Group Descriptor Table
- 块组描述符(Group Descriptor Table):描述块组属性信息,简称 GDP。
GDT在Ext文件系统中是一个非常重要的数据结构,用于 组织 和 管理 文件系统中的 数据块组。每个块组都有一个块组描述符,其中包含了关于该块组的重要信息,如已用数据块数量、已用inode数量、空闲数据块和空闲inode数量等。这些信息帮助文件系统管理每个块组的存储情况。
假设一个分组内有1000个文件,那么就有1000个块组描述符,那么管理这1000个块组描述符就只需要管理 GDT 即可。
🚩Super Block
- 超级块(Super Block):存放文件系统本身的结构信息。
记录的信息主要有:bolck 和 inode 的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。
并且超级块通常在分组内多个组有一个超级块,在系统中是有一定比例的,假设我一个100G的分区有1000个分组,每20个分组就有一个super block,那么总共就有50个超级块。为什么需要这些超级块呢?本质上还是为了数据备份,如果某个块组或者inode丢失,那么就 可以通过super block来进行恢复。
✈️文件名的作用
我们磁盘的分区设置有一栏叫做 “格式化” 的东西,这是什么?
实际上,格式化就是指 将分区写入文件系统,每一个分区都可以写入相同或者不同的文件系统。
文件名既然不属于inode属性,那么它有什么用?
目录是不是一个文件?我们学Linux都知道一切皆文件,所以目录也是文件。那么任何一个普通文件一定在目录当中,这也没毛病。目录跟普通文件有所不同,目录 = inode编号 + 目录的内容,而 每个文件名都是与目录间 的 映射关系(inode间映射)。
🚀重谈文件的增删查改
我们学习过Linux的权限,那么我们都知道,文件的增删查改与权限之间的关系密不可分,没有w权限我们我们不能修改文件,也不能删除文件。没有r权限我们不能读取文件内容,没有x权限,我们无法运行可执行程序。
我们来一个一个详谈,为何会如此?
- 没有w权限:
由于文件存储在目录之下,系统想访问对应的文件就需要先通过文件名在目录内容中找到inode与文件的映射关系,从而找到文件。
所以,一个目录没有w权限,也就是说在该目录中,我们无法将文件的inode与目录的映射关系写入到目录的内容里,所以自然我们不可以创建文件,同理,我们无法修改目录的内容,删除文件也同样做不到。
- 没有r权限:
如果目录中没有开启读权限,那么我们就不能用类似ls的命令查看目录文件的文件内容,也就不知道有什么文件和目录之间有映射关系。
- 没有x权限:
如果目录没有可执行权限,那么就无法进入目录之中。
📒✏️总结
- 磁盘有 硬盘、磁头、悬臂、马达 等部件组成。磁盘也存在抽象的 柱面、扇面、扇区和磁道,可以通过 CHS定位法 查找到任意一个扇区。
- 为了方便管理,将硬盘存储空间抽象为一个连续的数组,每个数组的最小单位为一个扇区(常为512byte),由于一次访问一个扇区过小,OS将八个扇区为一组,形成一个新的数组,叫做 逻辑块地址。
- 一般,磁盘空间可以被人为的分区,比如C盘、D盘,而每个分区有多个分组。
- 每个分组被划分了6个不同的区域,分别是: inode bitmap、inode table、super block、block bitmap、data block、GDT。
- 文件名不属于文件的属性,目录是通过 文件名与文件inode之间做映射,把映射关系存储到目录文件的文件内容当中,所以也直接 影响着文件的增删查改。
如果这篇文章对您有用的话,还望点赞收藏加关注~~