目录
前言:
一、磁盘结构
1.磁盘的存储结构
2.LBA逻辑地址
2.CHS寻址方式
二、块
三、OS如何对磁盘管理?
1.分区
2.ext2文件系统
3.inode文件属性数据集合
4.inode Table 和 Data blocks
5.inode Bitmap 和 block Bitmap
6.删除文件
7.GDT(Group Descriptor Table)
8.SuperBlock超级块
四、格式化分区
五、关于inode
六、inode和block映射关系
七、目录文件
1.重新理解目录权限
2.路径解析
八、文件和进程的关系
1.struct dentry结构体(目录项)
九、如何知道所处分区?
1.创建分区
2.删除分区
十、命令总结
总结:
前言:
我们在上一篇已经学过了文件的很多内容,这一篇重要讲讲文件在硬件上的存储方式,已经如何寻找他们,让我们开始吧!
一、磁盘结构
生活中,大家应该都见过机器磁盘,它的容量很大。
很多个磁盘在一起可以组成一个服务器,很多个服务器在一起可以构成一个机柜,很多个机柜在一个机房中。
1.磁盘的存储结构
磁盘有很多片,每个片都有两个面,叫做盘面。 我们把磁头想象成笔,因为有很多面所以就有很多磁头,但是磁头是共进退的。
磁道:一个盘面上面有很多磁道,它相当于同心圆。
扇区:一个磁道由多个扇区组成,每个扇区512字节(现在可能会更大)。
柱面:每个盘面的同心半径的磁道构成一个柱面。
2.LBA逻辑地址
我们可以将磁盘的一面想象成一个卷起来的磁带,我们可以将这个磁带拉成一个一维数组。这样定位每个扇区,就有了一个线性地址(也就是数组下标),就不需要用CHSCHS(柱面-磁头-扇区)地址定位法,这种地址叫做LBA(Logical Block Addressing)。
2.CHS寻址方式
因为磁头是共进退的,所以在寻找时,本质先会寻找一个柱面:
柱面就是每个面上相同半径构成的面,所以磁盘分了很多个面,在我们看来,逻辑上磁盘整体是由许多个“柱面”构成的:
所以,寻址⼀个扇区:先找到哪⼀个柱⾯(Cylinder) ,在确定柱⾯内哪⼀个磁道(其实就是磁头位置, Head),在确定扇区(Sector),所以就有了CHS。 所以我们逻辑上是LBA寻址,但本质是CHS寻址,LBA地址转成CHS地址,CHS如何转换成为LBA地址?
CHS 转 LBA
1. 单个柱面的扇区总数 = 磁头数 × 每磁道扇区数
2. LBA 计算公式:
◦ LBA = 柱面号 C × 单个柱面的扇区总数 + 磁头号 H × 每磁道扇区数 + 扇区号 S - 1
◦ 即:LBA = C × (磁头数 × 每磁道扇区数) + H × 每磁道扇区数 + S - 1
注意:
• 扇区号 S 通常从 1 开始,而 LBA 地址从 0 开始。
• 柱面号 C 和磁头号 H 从 0 开始编号。
• 磁盘内部会自动维护总柱面数、磁道数和扇区总数等信息,上层系统在开机时会获取这些参数。
LBA 转 CHS
1. 柱面号 C = LBA // (磁头数 × 每磁道扇区数)(即 LBA 除以单个柱面的扇区总数,取整)
2. 磁头号 H = (LBA % (磁头数 × 每磁道扇区数)) // 每磁道扇区数
(即 LBA 对单个柱面的扇区总数取余,再除以每磁道扇区数,取整)
3. 扇区号 S = (LBA % 每磁道扇区数) + 1
(即 LBA 对每磁道扇区数取余,再加 1)
符号说明:
• // 表示除法取整。
• % 表示取余运算。
OS只需要使⽤LBA就可以了!CHS如何转换成为LBA地址。谁做啊??磁盘 ⾃⼰来做!
二、块
OS和磁盘进行IO的时候,以扇区(512Byte)为基本单位,对于OS而言,单次IO的的数据量有点少。OS在文件系统和磁盘交互时,以1KB、2KB、4KB、8KB数据量进行IO的,⼀次性连续读取多个扇区,即⼀次性读取⼀个”块”(block)。一般以4KB为单位,也就是8个扇区。
所以我们对LBA定位是这样的:
LAB=块号*8 + n. (n是块内第⼏个扇区)
所以我们可以将磁盘看做以块为单位的一维数组。
三、OS如何对磁盘管理?
OS对一个500G的磁盘进行管理,是如何管理的?
1.分区
我们会对磁盘拆分为很多区域,其实就是分区。
我们可以使用lsblk命令,以树状结构列出所有块设备(硬盘、分区、逻辑卷等)及其挂载点。
如果你是云盘,则磁盘可能叫做vda,且只有一个分区。但是作者这里是物理盘,所以如下:
分区是互相独立的,可以给分区划分为不同的文件系统,这样一个分区挂掉了也不会影响其他分区。
2.ext2文件系统
我们以 Linux 系统中广泛使用的ext2文件系统举例。分完区以后还是太大了,我们又把分区分成组进行管理:
Boot Block 通常只存在于 第一个分区 中,用于引导操作系统。其他分区一般不需要 Boot Block,除非你配置了多引导系统。
而一个组中,又包含以下内容:
文件 = 内容 + 属性
3.inode文件属性数据集合
属性也是数据,以结构体的方式构建出来(inode)。一个文件一个inode,inode是文件属性数据的集合。
当我们新定义一个文件时,OS会新建一个inode,把里面的内容填充以后,写入到磁盘中指定的 inode table 中。
OS与磁盘IO交互时基本单位是4KB,而一个inode是128字节,所以一个块中有32个inode。
每一个inode都有自己的编号。
文件名不在inode中!
4.inode Table 和 Data blocks
文件的内容在Data blocks中:
所以Linux下,文件属性和文件内容分开存储。
此时我们知道了一个组内的 inode Table 和 Data blocks,之后我们需要知道组中其他数据块的含义。
5.inode Bitmap 和 block Bitmap
inode Bitmap也就是位图。inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
加入 inode Table 中有5000个inode,那么inode Bitmap中就有5000个1。
当我们新建文件的时候,会先查inode Bitmap之后如果是0,则将对应的位置1,之后在inode table中创建文件属性。
我们先暂停一下,我们之前说OS和磁盘交互大小是4KB。磁盘最小访问单元是扇区。但是现在我们要将inode bitmap其中一个位置一,假设inode bitmap中有10000个比特位,向上取整为2KB。inode bitmap存储上也是以块为单位,当我们要修改其中1位时,会将对应的4KB加载到内存,修改完以后再以4KB为单位输出到磁盘。
而 Block Bitmap 和 inode Bitmap 含义几乎一样,它是表明 data blocks 中块的使用情况。
所以我们知道inode编号就可以找到文件了。
6.删除文件
删除文件只需要在 inode bitmap 和 block bitmap 对应的位置置0即可,恢复可以将其置1。在Linux中删除本质就是设置 inode ,block 无效。
7.GDT(Group Descriptor Table)
此时已经解决了创建文件和删除文件的问题,我们其实还要知道这个组的使用率,通过GDT(Group Descriptor Table)来完成。
GDT(GroupDescriptorTable):块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描述符存储⼀个块组的描述信息,如在这个块组中从哪⾥开始是inodeTable,从哪⾥开始是Data Blocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉。
8.SuperBlock超级块
超级块(SuperBlock):存放⽂件系统本⾝的结构信息,描述整个分区的⽂件系统信息。记录的信息主要有:bolck和inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写 ⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息。SuperBlock的信息被破坏,可以说整个⽂件系统结构就被破坏了。
超级块在每个块组的开头都有⼀份拷⻉(第⼀个块组必须有,后⾯的块组可以没有)。为了保证⽂ 件系统在磁盘部分扇区出现物理问题的情况下还能正常⼯作,就必须保证⽂件系统的superblock信息在这种情况下也能正常访问。所以⼀个⽂件系统的superblock会在多个blockgroup中进⾏备份,这些superblock区域的数据保持⼀致。
SuperBlock本质表示的就是文件系统!
文件系统以分区为单位,不同分区可以使用不同文件系统。
四、格式化分区
所以整个磁盘中会先把各种区域划分好,就算我们没有向里面填充数据也会写一些东西,也就相当于快递站的架子都会整理好等待快递摆放上去,这就叫做格式化。
格式化 的本质是创建文件系统。
inode以分区为单位,每个分区都有一套inode。也就是说,第一个分区中有inode100,第二个分区中也可以存在inode 100。
五、关于inode
一个文件系统中,inode和block的个数都是固定的。inode在分配的时候,只需要确定起始inode即可。对于一个分区,块号也是统一编号的。
上图假设是第二组,位图为3分配inode,inode就会加上改组起始记录的start_inode值分配。 也就是10003。所以这样就得到了全局的inode,即使是局部也可以通过计算得到。
又是如何分配块号呢?和分配inode一样。当当前组的块存不下该文件时,inode结构体会映射块,会进行跨组管理。所以假设此时有inode : 10004,block : 100006要怎么找?会先找对应的组,通过start_inode,之后拿inode - start_inode就可以得到当前inode bitmap,之后就可以对其操作。
因为这是磁盘上的操作,难道真的会逐个去遍历磁盘吗?并不是,而是OS会进行文件管理,把superBlock和GDT先描述,再组织,将其封装为结构体,之后管理起来。所以对于刚才我们所说的inode查找等操作都是内存级操作。
六、inode和block映射关系
inode 和 block 到底是怎么映射的?我们需要来分析inode结构体的结构:
其中前12个是直接映射的,也就是直接保存数据。 后面的块索引表指针又是存其他块号。
我们平时访问文件时一般是属性居多,一般只查一个具体的文件。所以一个文件大小是有上限的,但是这里二级索引已经到GB级别,三级索引已经到TB级别,几乎可以存放下任何文件。
七、目录文件
我们到底是怎么拿到inode的?我们平时都是使用文件名访问文件的。我们之前说过,文件名并不在inode中存储!
目录是一个文件吗?其实目录也是文件!如何理解目录文件?目录文件也有自己的inode和datablock!
目录 = inode + datablock = 属性 + 内容
所以目录也有对应的数据块!目录文件的数据块中存放的是文件名和inode的映射关系。所以文件名处于所处目录中的数据块中。
我们为什么不直接根据文件名查找文件,而是通过inode找文件?如果按照文件名查找文件,需要对比字符串;而inode就直接比较数据即可,提高了效率。
1.重新理解目录权限
重新理解目录权限:rwx。
当没有读权限,就不能查找当前目录中的文件,读取不到目录中的block映射关系。
当没有写权限,就无法在目录中新建文件,因为无法写入block。
当没有执行权限,就无法进入目录。
2.路径解析
所以我们要找到文件名需要先打开当前目录,而当前目录也是文件,所以我们会进行逆向的路径解析。
我们会从根目录开始找,根目录的inode是固定写死的,直接写在superblock中。
所以任何一个文件都有路径,而每个进程有CWD。
当我们已经访问一个/home/gan/112_cur/new_warehouse/lesson18/test.txt文件后,之后又在同级目录下访问另一个文件,还是会从左向右进行路径解析,就是不断访问磁盘文件系统。这就会降低效率,所以Linux系统会对路径结构进行缓存。
磁盘上不会保存路径,Linux系统需要对路径结构进行缓存。这个数据结构也就是多叉树,当我们首次访问完一个目录后,会构成多叉树的缓存目录。
第一次访问磁盘,第二次访问缓存结构。
八、文件和进程的关系
1.struct dentry结构体(目录项)
Linux中,在内核中维护树状路径结构的内核结构体叫做:struct dentry。
所以当我们使用 find /home -name test.txt 时会去磁盘上找,第一次很慢,它会找目录对应的block,之后就会快。
这些文件又和文件描述符和进程是什么关系?
我们先来观察一下struct dentry源码:
它和进程之间的关系如下:
每个⽂件其实都要有对应的dentry结构,包括普通⽂件。这样所有被打开的⽂件,就可以在内存中形成整个树形结构。
九、如何知道所处分区?
我们此时已经可以在一个分区中找到任何一个inode和block了,但是我们怎么知道我们所处的分区呢?
如果Linux系统中有多个分区的话,一定要有一个分区包含根目录,同时又会从根目录中又有若干个普通目录(10个分区就有10个普通目录),默认只有分区,该分区无法直接使用,分区必须经过挂载到目录上,分区才可以被通过路径的方式进行访问!
这里你可能有疑问?还是要从根目录下创建分区,那么根目录处于那个分区呢?在Linux系统中,挂载到根目录(/)下的分区通常是根文件系统分区,用于存储操作系统核心文件、系统程序和用户数据等。
注意:Linux和Windows在文件系统和分区管理上有显著的不同。
(Linux是将所有分区都属于 / 下的;而Windows并不是,文件系统的起点是 驱动器号(如
C:\
、D:\
等)。
1.创建分区
我们做一个实验,给系统分一个区,在此之前我们先来看几个命令:
lsblk -f 命令:系统会列出所有块设备,并显示每个设备的文件系统相关信息,具体输出信息通常包括以下内容:
NAME:设备名称,例如 sda、sda1、nvme0n1 等。
FSTYPE:文件系统类型,如 ext4、xfs、ntfs、vfat 等。
LABEL:文件系统的标签,用户可以为文件系统设置一个自定义的名称。
UUID:文件系统的通用唯一识别码,用于唯一标识一个文件系统。
MOUNTPOINT:文件系统的挂载点,即文件系统在文件系统树中的挂载位置。df -h 命令:查看磁盘情况
我们直接来看磁盘情况:
我们可以做一个文件系统。创建一个大型文件,看操作:
我们此时已经创建了一块空间,之后要向其写入文件系统:
而mkfs.ext4 disk.iso也就叫做格式化。
此时我们就有了一个虚拟的磁盘了,但是目前用不了,我们需要对其挂载到一个具体的目录下才能使用。
/dev/loop0:
在Linux系统中代表第⼀个循环设备(loopdevice)。循环设备,也被称为
回环设备或者loopback设备,是⼀种伪设备(pseudo-device),它允许将⽂件作为块设备
(blockdevice)来使⽤。这种机制使得可以将⽂件(⽐如ISO镜像⽂件)挂载(mount)为
⽂件系统,就像它们是物理硬盘分区或者外部存储设备⼀样。
2.删除分区
我们当然也可以卸掉分区。在卸载的时候,不能处于要卸载分区的路径,因为其正在工作。所以我们在另一个分区卸载,使用unmount卸载分区。
因为分区需要挂载才能使用,所以任何分区都有基本路径。所以我们任何文件都有路径,路径前缀就知道是哪个分区了。
十、命令总结
lsblk -f 命令:系统会列出所有块设备,并显示每个设备的文件系统相关信息。
df -h 命令:查看磁盘情况。
unmount 命令:卸载分区。
总结:
可能不少小伙伴都是一知半解,因为这部分知识确实很难,但是我们目前不需要了解的那么详细,但是至少要脑海中要有对这方面的框架,这对以后的知识会更好的理解。接下来我们还有重磅内容,对,这部分知识很多,我们不要急躁。
各位看在我这么用心的做文章,动动发财的小手点个赞吧!