目录
1 磁盘结构
2 逻辑抽象管理磁盘
2.1 逻辑抽象
2.2 管理磁盘
2.3 补充知识
3 软硬连接
本篇的学习需要建立在大家在脑海中有一副磁盘的结构才能进行下去,所以我会以图解的方式为大家简单讲解一下,注:博主对这一部分并不是特别的了解,只能让大家对于磁盘有一个联想的空间。
上图为我们磁盘的机械结构,根据冯诺依曼体系的分类,这个东西被称为外设,而这个家伙又是外设当中比较慢的哪一种结构,因为它有马达等之类的机械结构,所以我们一般在对磁盘进行操作的时候都会比较慢,但重点不在这里。
对于我们了解来说,这个结构重要的东西就是中间的那个圆盘和它旁边像是针头一样的东西,他们俩就是我们所知的磁盘和磁针。
对于它的读取我们有一个很形象的东西可以替代,那就是以前的留声机,和光碟。我以留声机为例,我们只要打开留声机的开关,放上黑胶,留声机就会转动这个黑胶片,如果此时我们将留声机的针头放到黑胶片上,这时,留声机就能够发出声音了。同理,我们的磁盘也是一样的操作,通过磁盘旋转以及磁针读取内容就能实现在磁盘的读取和写入了。
再具体看我们的上图,上面的磁盘课磁针并不只是一个,而是有多个叠加起来的,并且它们由各自的马达同轴转动,也就能够存更多的数据了。
单个盘面可以被抽象为上图结构,整个磁盘是由一个一个的小扇区组成。虽然不同磁道的扇区大小并不相同,但是它们的大小都是一模一样的(不绝对,有些盘大小不一样),为512byte。
然后i每一个扇区都是由很多的小bit位组成,也就能存我们的数据了。
那么有这么多的扇区,这么多的磁道,这么多的扇面,我们应该如何去查找我们需要的数据呢?难道是依次扫描文件?很明显不是的。
其实磁盘文件的查询就像是我们到图书馆找一本书一样,他是被规划好的,首先我们得知到我们要找的书的大类是什么?也就是通过磁针去匹配那一块磁盘;然后得知我们的书在哪一个大书架里面,也就是匹配我们对应的磁道;最后找到大书架里的小书架,查找我们对应的书籍,也就是找到扇区去查找我们对应的数据。这样就能实现我们的查找操作,也被我们称为磁头(header)、柱面(cylinder)、扇区(sector)查找方式————CHS。
通过上面对于磁盘结构的简单讲解,相信大伙对于磁盘也是有了一点点概念了,那么就能开始我们本篇的重点了。
根据我上面讲解如果OS能够通过CHS去访问磁盘的任意一个位置,那么是否表示OS就是这样做的呢?答案肯定不是,首先以冯诺依曼体系他就跑不过去,磁盘是外设欸,我们的OS只能重内存当中读取内容,那肯定不是;从效率而言也不可能,磁盘的可是一个机械结构,他能跟上我们操作系统的运行速度?别开玩笑了,肯定跟不上啊;从硬件角度理解这也是不科学的,如果OS直接使用了这一个地址,那么一旦硬件发生了改变,那么原本的操作系统也会被改变了,整个文件操作就会被变得乱七八糟;而且一个扇区就只有512字节,但是我们OS每一次进行IO操作就是以4KB为一个基本单位,这两者之间不能直接对应起来。综上OS内部一定不是通过CHS寻址。OS一定还有一套其它的方式,来进行块方式的访问。
我们知道,磁盘的读取是通过磁盘旋转,然后再由磁针去匹配,这一过程其实很像我们以前的老式录音机的磁带,将整个磁带拉开,这是不是一条线性的直线磁带?我们的磁盘也这样理解,那么磁盘是不是也是一条直线?连续的地址还是连续的,根本不影响他的读取。(这让我想起了以前学高数积分的日子,哈哈)。
所以既然是一条线性,那我们可以将其看成什么东西?对应我们的代码层面。数组是不是,这不就是一个大数组吗?既然是数组,那么我们不久能够轻松的将其管理起来咯。这一步就是管理操作最重要的先描述、在组织。
我们有多个磁盘,也就有了多个大数组,每一个大数组上面有很多很多的磁道,每一个磁道上面都有很多的小扇区。也就是下图结构:
但是呢,我之前不是说了OS在进行IO操作的时候每一次会有4KB大小的数据嘛,但是这每一个扇区不久只有512byte吗,这岂不是每次读取都是读起来很亏?
所以这个时候我们就又做了另外一件事情,那就是每八个扇区就构成一个数据块,那么我们下标访问例如arr[0],就能够读取8个扇区的内容,也就能将IO操作的4KB数据读取满。
也就变成了上图的情况。
这个时候我们就初步的将磁盘的物理逻辑到线程逻辑的抽象过程,因为数组天然有一个下标,所以想要定位一个扇区,只需要知道它的某一个下标就可以了。并且我们称这样的一个地址为逻辑块地址(logic block address)LBA。
假设我们要找一个扇区,已知数组的下标是6500,每一个扇面有5000数组块,每一个磁道有1000个数据块,请问要找的扇区在哪里?
这个问题很简单,既然下标是6500,那就表示了我们要找的是第2个磁面,我们就排除了5000个数据块,现在只剩下1500个,每一个磁道有1000个数据块,那么表示我们的数据块在第二个磁道,现在只剩下500个数据块,那么就找到了该扇区在哪里了:第二面第二磁道的第500个数据块。该数据块有8个扇区,我们要的扇区一定在里面。
上述问题完美的呈现了LBA和CHS的相互转换,也实现了对数组下标的管理到磁盘内存的管理的完美过度,并直接的解除了操作系统和磁盘的耦合关系。
对于OS来说,磁盘的大小实在是太大了,他不像是内存只有十几个G,他从理论上来说可以是无限大的,只要厂家想或者是项目需要。那么此时就需要一个合理的管理制度,光靠一个下标是无法满足这样的需求的,所以就有了下图:
既然我们一个500G的磁盘内存管理不过来,那么我分区可以把,我分成5个100G的小磁盘内存,我嫌弃100G也大了,那么我再对这个区域进行划分,分组可以吧。这样这就成功的减少了管理这整个磁盘的消耗。
为什么能这么做呢?那是因为磁盘其实是一个很单一的东西,它的结构都是一样的,只要我们管理好了一个组,那么等于我们能够管理好所有组,我们管理好了所有组,就能管理好一个区,只要管理好了一个区,等于我们能够管理好所有区,也就表示我们管理好了任意大小的磁盘。
那么接下来就是了解这每一个组内的各个功能块都是干什么用的了。
Boot Block:
Boot Block其实就是启动块,我们电脑在开机的时候调用的就是这一块的内容,如果没有了这一块的数据,那么我们电脑就不能正常开机了。
Super Blcok:
超级块,里面存了我们组内的block和inode的总量,未使用的block和inode的数量,一个block和inode的大小,最后一次挂载的时间,最近依次写入数据的时间,最近一次检验磁盘的时间等其它文件系统的相关信息。并且,每一个组都有一个super block,且这些块是相连的,也就是更改一个全部都会被更改。这样做的目的也就是为了保护好数据不被丢失。防止因为一个块的错误导致所有的文件信息不可读取。也就是做好备份。
Group Descriptor Table:
组内描述符,描述块组属性。一般而言,一个文件内部所有属性的集合有128个字节,一个文件也对应一个Inode,每一个组每一个分区都会有大量的indoe结点,需要有一个区域准们保存该Group内的所有文件的Inode结点。
Data Blocks:
数据块,也就是我们之前划分这么久的4KB一个的小磁盘块,用于存储数据。
Block Bitmap:
数据块位图,用于表示我们的某个数据块是否被使用,用0/1表示,并且位图的位置就是数据块所在的下标。
Inode Bitmap:
结点位图,所谓结点位图就是表示这个文件结点是否被使用,与数据块位图相相似。
Inode Table:
用于存放我们的Inode结点,每一个结点都是大小为128byte大小的结构体,里面存放了文件的各种属性。
知道了上述块的作用之后,那么我们应该如何理解一个文件的存储呢?
假设我们要创建一个新文件:
1. 首先内核要找到一个空闲的Inode结点,将文件的信息写入。
2. 如果这个文件需要三个数据块,那么内核就会找3个空闲数据块,依次写入数据。
3. 根据数据块的使用,内核在Inode上的磁盘分布区记录了上述块列表。
4. 添加文件名到目录,用Inode Num和文件名相互作为关键字查找。
对于OS来说,它找文件只是凭借inode num,那么文件名又是什么?他岂不是没意义?话不能这么说,文件名至少还有一个作用————给我们看的,我们总不能拿着一堆数字去看这个这个文件吧,可太难受。
还记得吗,linux下一切皆文件,那么目录算不算文件?算当然算,它也有它自己的inode num,这时肯定的,问题是他这个文件用来存什么?其实这个问题我们只需要好好想想目录里面有什么就能想到了,目录下面无非就是文件或则另外一个目录嘛,那么存的数据就一定是这些文件的某些相关内容,而这个内容就是文件名和inode num对应的映射关系,这两个互相为Key值,都能找到相应的文件。
那么也就表示我们在访问一个文件的时候,我们是在特定目录下访问的,只要在当前目录下,就能够找到某个文件的inode编号,所以OS在加载数据进入内存的操作就是通过通过inode num逐渐向下查找,直到找到需要的文件,然后加载到OS,最后显示到显示器当中。
然后呢,Inode和数据块一定是由某些联系的,它的练习就是如下伪代码:
struct inode
{
int inode number;int ref _count;
mode_t mode;
int uid;
int gid;
int size;
data;
......
int datablock[NUM]
}
上代码中我加黑的部分就是inode和数据块之间的联系,这个数组存的数据就是数据块的下标,根据我们的需要,可以存无线大的数据。为什么?这个下标不是有限的吗?哪里会让你一个文件开这么大的空间,那我就得说一个很牛的二级索引和三级索引了,二级索引指向一个数据块,这个数据块不存其他数据,只存其它数据块的下标,那么就能够扩大存储数据的大小,三级索引呢?三级索引全部存二级索引,二级全部存一级索引,那这个数据可能存太大了,基本上是无限了。
当然,从上面的各个解释上来看,inode和数据块好像是独立的。那么有没有可能inode用完了,或则是数据块用完了的情况?当然有,但是如何避免呢?没有办法,有了这种情况就等死吧。博主没有开玩笑,只要有了这种情况要么换一个磁盘,那么给他再买一个磁盘扩容。
在linux下通过ls -i命令可以得到文件的inode num和inode结构体内部的ref,也就是该文件被几个文件指向。
当我们有了一个test.txt文件,通过软连接 ln -s test.txt 新文件名就能构成一个软连接,软连接是重新开辟一个新的文件,我们从inode num可以看出来。
通过ln test.txt 新文件名就能构成硬连接,硬连接没有重新搞一个文件出来,因为他与源文件的inode num一样,并且ref增加变为了2,唯一做的事情就是在目录的数据块的映射表当中添加了一个新的映射关系。
以上就是博主对本节的全部理解了,希望能够帮助到大家。