目录
前言:
了解机械磁盘
初始盘片与磁头
盘片是怎么存数据的呢?
详解盘片
如何访问磁盘中的一个扇区呢? -- CHS 定位法
磁盘的逻辑存储
LBA(Logical Block Addressing --- 逻辑块寻址)
如何将 LBA 地址转换为 CHS 地址?
如何管理扇区?
什么是 inode ?
inode 怎么管理文件内容?
什么是数据块?
位图
理解新建/删除文件
理解文件名
前言:
进程运行时会把需要用到的文件从磁盘加载到内存中,那么系统是如何在磁盘中快速找到进程想要的文件的呢?
了解机械磁盘
初始盘片与磁头
从下图中我们可以简单地了解一下机械磁盘:
盘片:文件的数据都存储在盘片中,一个磁盘中不止一块盘片,多个盘片是摞在一起的。当磁盘开始运作时,盘片中间的马达会带动盘片旋转。
磁头: 磁头用于读取盘片中的内容。当磁盘运行时,磁头会旋转到盘片的上方读取盘片的数据。一个盘片有上下两面,两面各有磁头。
当磁盘开始运作时,盘片顺时针(或者逆时针)旋转,磁头绕着轴左右摆动,在盘片中进行寻址,找到想要的位置进行读写。
因为磁头和盘片都是金属做的,两个金属相互摩擦,会把盘片刮花,那么盘片的数据都被刮没了,所以磁头不是紧紧挨着盘片的,而是有一定的距离。除此之外,磁盘内部是无尘的,也是为了防止把盘片刮花!
盘片是怎么存数据的呢?
首先需要明确:计算机在底层硬件层面主要使用二进制数系统进行数据处理和运算,这是因为二进制系统非常适合电子电路的工作方式。二进制只有两个数字:0 和 1,这可以很容易地通过电子信号的两种状态来表示,例如电压的高低、电流的通断等。
但是 0 和 1 只是一种二元状态,盘片中并不是真实地存储着 0 和 1 这两个数字!
盘片可以想象成由无数个磁铁构成,磁铁具有南北极,南北极也是一种二元状态,在盘片上修改数据,实际上也是在修改盘片上磁铁南北极的朝向。
由于磁铁的磁性保持的时间长,所以磁盘可以长时间保存数据,即使断电了数据也不会丢失,因为它们采用的是磁性、电荷捕获或其他物理性质来持久化地存储信息;而内存无论是DRAM还是SRAM,它们都是易失性存储器,它们都需要电力来维持内部电子元件的状态,意味着在断电情况下不能保留信息。所以说磁盘是永久存储介质!
详解盘片
磁道是指磁盘表面用来存储数据的一系列同心圆。每个磁道是磁盘上可以读取或写入数据的一个环形区域。磁盘的每一个面都被划分成许多这样的磁道。
柱面是由所有盘片上的同一半径位置组成的虚拟圆柱体,指在硬盘上多个盘片相同位置的一组同心圆磁道。想象一下,如果你将硬盘垂直切割,并且沿着这个切割面看去,你会看到一组圆形的磁道,这些磁道位于不同盘片的相同径向距离处,这一组磁道就构成了一个柱面。
当提到一个柱面时,实际上指的是该柱面上所有磁头所覆盖的所有磁道。
磁道由多个扇区组成(磁道被划分成多个扇区),每个扇区通常是固定大小的数据块,常见的大小为512字节或4096字节(随着技术的发展,更大容量的硬盘可能会采用更大的扇区)。当硬盘读写头移动到特定磁道上方时,它可以访问该磁道上的所有扇区。
磁道被划分成扇区后,扇区的面积大小可能不一样,但是扇区的内存大小都是一样的!
如何访问磁盘中的一个扇区呢? -- CHS 定位法
每个盘面、磁头都有唯一的编号,在一个盘面里,每一个磁道也有唯一的编号,每一个扇区也有唯一的编号。
如果想访问磁盘中的一个扇区,通过磁头定位,先确定扇区在哪一个磁道(cylinder)上,接着确定要使用哪一个磁头(head)(上面还是下面),最后确认在磁道上的哪个扇区(sector),这种定位方法称为 CHS 定位法。
我们就可以理解,选择哪个磁头,就相当于选择了哪个盘面,磁头的来回摆动是为了定位盘面的磁道,而盘片的旋转是为了寻找磁道上的扇区。
盘片的旋转和磁头的摆动都属于机械运动,机械运动导致磁盘的访问速度是比较慢的,所以需要操作系统把磁盘的数据预加载到内存中,提高效率!
磁盘的逻辑存储
逻辑存储主要涉及文件系统如何管理和访问磁盘上的数据。
LBA(Logical Block Addressing --- 逻辑块寻址)
如果把盘片的所有磁道拉直,磁盘就可以看成非常长的线性空间。
假设有4个盘面(2个盘片),每个盘面有200G,总共800G,每个盘面的基本单元(扇区)为512字节,所以一共有1 677 721 600 个扇区,每一个扇区都有对应的下标,对磁盘的管理,就变成对数组的增删查改。
LBA的主要优点包括:
- 简化了寻址:不需要考虑物理结构如柱面、磁头和扇区。
- 提高了性能:减少了硬件和软件处理复杂寻址逻辑的需求。
- 支持更大的磁盘容量:由于LBA是基于数字的线性地址,它不受传统CHS寻址中柱面数、磁头数和扇区数限制的影响。
如何将 LBA 地址转换为 CHS 地址?
LBA
:逻辑块地址SPT
:每磁道的扇区数(Sectors Per Track)HPC
:每个柱面的磁头数(Heads Per Cylinder)- HPC * SPT : 一个柱面总共有多少个扇区
计算柱面号(C):
C = LBA / ( HPC * SPT )
计算磁头号(H):
H = ( LBA % ( HPC * SPT ))/ SPT
计算扇区号(S):
S = ( LBA % ( HPC * SPT ))% SPT +1
( +1 是因为扇区号是从1开始计数的,而LBA是从0开始计数的。)
如何管理扇区?
假设磁盘中共有 800G,如何管理这 800G 呢?
我们可以对 800G 进行分区,假设分成5个区:100G、100G、150G、150G、300G,假设每个区内部是没有差异的,那么把这 5 个区管理好,不就相当于把 800G 管理好了吗。在我们的电脑中,把磁盘分为 C盘、D盘,就是所说的分区。
同样的道理,假设我们把 100G 进行分组,平均分成 10 组,每组 10G,把这 10G 管理好,100G 也就管理好了。这样把大问题划分成小问题的思想就是分治思想。
那么如何管理好这 10G 呢?
首先,文件 = 内容 + 属性,文件的内容大小是不固定的,但是文件的属性的大小是固定的,Linux 将文件的内容和属性分开存储,inode 可以将文件的内容和属性进行管理!
在每个分组中,都有 Block Bitmap、inode Bitmap、inode Table、Data Blocks。其中,Data Blocks 是用来存储文件的内容。
什么是 inode ?
inode 其实是一个结构体,结构体的内容与文件有关,通常包括:
- 文件类型:表示这是一个普通文件、还是目录、符号链接等。
- 权限:文件的所有者、组和其他用户的读、写、执行权限。
- 所有者ID 和 组ID:标识文件所有者和所属用户组的数字ID。
- 文件大小:以字节为单位的文件大小。
- 时间戳:包括最后访问时间(atime)、最后修改时间(mtime)和状态改变时间(ctime)。
- 指向数据块的指针:这些指针指向实际存储文件数据的数据块。对于小文件,可能直接在inode中存储一些数据;对于大文件,则指向一系列的数据块。
注意文件的 inode 中不包含文件名!!!此外,一个 inode 结构体大小为 128 字节,大小是固定的。
一个文件一个 inode,每个文件都有 inode 编号,inode编号 是在整个分区内唯一有效的数字!所以对文件的管理,就变成了对 inode 的管理。
inode 怎么管理文件内容?
什么是数据块?
每个分组中,都有一个 Data Blocks,也就是数据块。
在EXT2文件系统中,数据块并不是数组。数据块是存储文件内容的最小单位,它们是磁盘上的固定大小的连续空间。EXT2文件系统将磁盘划分为多个相同大小的数据块,每个数据块可以用来存放文件的数据或元数据(如inode信息)。尽管数据块不是数组,但是文件的内容可以通过类似数组的方式来访问。一个数据块只能存放 4KB 大小的数据。
而 inode 定义了数组 block[ 15 ] ,数组中存放着指向数据块的指针,一个数组只能记 15 个数据块的位置,那一个文件最大只有 60KB 吗?
- 数组下标从 0 到 11 是直接映射,指针指向的数据块直接存放文件的内容;
- 下标从 12 到 13 指针指向的数据块存放的是其他数据块的内容,文件的内容存储在这些其他数据块中(一次间接);
- 下标 14 存储的是其他数据块的位置,指针指向的数据块存放的是其他数据块的内容,这些其他数据块中存储的还是其他数据块的内容,此时的数据块的内容为文件的内容(二次间接)。
位图
在Data Blocks 中,有的数据块已经使用了,有的还没有使用, Block Bitmap 可以更快的分辨出哪些已经使用了,哪些还没有使用!
同样的,inode Table 中有的 inode 已经使用了,有的没有,inode Bitmap 的作用和 Block Bitmap 相同!
从下面这张图可以看出,每一个分组都有一张位图,一个分区就会有很多张位图,而 inode编号是在分组中唯一的,那么怎么确定 inode 在哪张位图中呢?
每个分组都会记录自己组的 inode 的起始编号和组内 inode 的个数,假设分组内的起始编号如下:
假设 inode 编号为 1500,通过比较每个分组的 inode 的起始编号,我们就可以确定 inode 在 Block group 1 中。
根据偏移量 500(500 = 1500 - 1000),就可以在 Block group 1 的位图中查询该文件是否存在。
理解新建/删除文件
新建文件,先查 inode bitmap,找到最小的为 0 的位置,把这个位置改为 1,然后去 inode table 找到对应的位置,把文件的属性填好,把文件的内容填写到数据区中,并把填写的数据区的位置填入到 inode 的block 中。
删除文件,找文件的 inode 编号,把 inode bitmap 改为 0,把 inode 结构体中的 block 数组对应的 block bitmap 改为 0,只是把位图清掉,并不会把inode 和数据区里面的内容清除掉!!
可见,删除文件比新建文件快很多。
理解文件名
作为用户,我们知道的是文件名,并不知道 inode 编号,在不知道文件 inode 编号的情况下,如何找到这个文件呢?
首先我们需要了解目录,目录也是一个文件,文件都有自己的属性+内容,那目录的内容是什么呢?
因为任何一个普通文件,一定在一个目录中,目录的内容是目录中的文件的文件名和 inode 编号之间的映射关系,找文件,只需要找到文件所处的目录,就可以字符串匹配到文件名,进而找到文件名和 inode 的映射关系,找到文件对应的 inode 编号。
目录这个文件的数据块存的就是文件名和 inode 编号之间的映射关系。
新建文件,假设在组 0 里面新建文件,在 inode 位图中找到一个最小的还没有用过的编号,然后把文件的属性都写到对应的 inode 中,有文件内容的话就把文件内容写入到数据块中,然后向上层返回 inode 编号,接着建立文件名和 inode 编号的映射关系,把这个关系写入到文件目录的数据块中。
- 目录没有写权限时,我们没办法在该目录下创建新文件,因为我们新建文件,会修改目录的内容,没有写权限就不能修改目录内容。
- 没有读权限就不能读取inode 和文件名的映射关系。
删除文件,拿着文件名,就可以知道与 inode 的映射关系,找到映射关系,知道 inode 编号后,清掉位图,然后在目录的内容中去掉文件名和 inode 的映射关系,没有目录的写权限也是没办法删除目录下的文件的。