✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨
✨ 个人主页:余辉zmh–CSDN博客
✨ 文章所属专栏:Linux篇–CSDN博客
文章目录
- 一.认识硬件--磁盘
- 物理存储结构
- 1.存储介质类型
- 2.物理存储单元
- 3.CHS地址:三维物理寻址
- 逻辑存储结构
- 线性地址(LBA):一维逻辑寻址
- 二.文件系统
- 先分区再分组
- 分区(Partitioning)
- 分组(Block Group)
- 块组结构
- 1.inode表(`inode Table`)
- 2.数据块(`Data Blocks`)
- 3.inode位图(`inode Bitmap`)
- 4.块位图(`Block Bitmap`)
- 5.块组描述符表(`Group Descriptor Table`)
- 6.超级块(`Super Block`)
- 特殊文件“目录”
- 三.软硬链接
- 软链接
- 硬链接
- 四.文件增删查改过程
- 创建文件与硬链接
- 删除文件或硬链接
- 查看文件内容
- 修改文件内容
一.认识硬件–磁盘
物理存储结构
1.存储介质类型
-
固态硬盘(SSD):
- 基于NAND内存芯片,无机械部件,数据存储在**存储单元(Cell)**中。
-
机械硬盘(HDD):
- 由多个盘片堆叠组成,每个盘片表面覆盖磁性材料。
- 每个盘片都有两个磁头(Head),磁头固定在磁头臂(Actuator Arm)上,通过主轴下面的马达移动。
- 磁头移动是左右摆动,而盘片是高速旋转;两者在移动的过程中不接触。
2.物理存储单元
- 扇区(Sector):
- 磁盘的最小物理存储单元,传统大小是512字节,现代硬盘支持4K字节。
- 磁道(Track):
- 盘片上的同心圆环,每个磁道被划分为多个扇区。
- 柱面(Cylinder):
- 所有盘片上相同半径的磁道组成的立体结构,减少磁头移动开销。
前面提到盘片要高速旋转,而磁头要左右摆动,现在就可以明白:盘片高速旋转的目的是定位扇区的过程;而磁头左右摆动则是定位磁道和柱面的过程。
盘片和磁头运动越少,效率越高;运动越多,效率越低。所以在软件设计上,设计者一定会有意识地将相关数据存放在一起,这样就能减少运动次数,提高效率。
3.CHS地址:三维物理寻址
磁盘被访问的最基本单元是扇区–512字节/4KB字节,我们可以把磁盘看做成由无数个扇区构成的存储介质,而要把数据存储到磁盘上,第一个解决的问题就是定位一个扇区:哪一盘面(定位用哪个磁头)?哪一个磁道?哪一个扇区?
这就要借助CHS三维物理寻址方式。
CHS的组成:
- 柱面:选择磁头需要移动到哪个“同心圆环”(所有盘片的同一半径位置,也就是磁道)。
- 磁头:选择具体哪个盘片的表面。
- 扇区:选择磁道上的具体扇区位置。
CHS的局限性:
-
容量限制:
早期BIOS对CHS参数的存储位数有限(比如柱面10位,磁头8位,扇区6位),导致最大支持容量为:
最 大 容 量 = 柱 面 数 ∗ 磁 头 数 ∗ 扇 区 数 ∗ 512 字 节 最大容量 = 柱面数*磁头数*扇区数*512字节 最大容量=柱面数∗磁头数∗扇区数∗512字节
例如:1024柱面256磁头63扇区*512字节 约等于 8.4GB。 -
复杂性:
需要操作系统和硬件协调管理三维地址,对程序员不友好。
-
SSD不适用:
固态硬盘没有机械结构,CHS的物理概念不再有意义。
逻辑存储结构
线性地址(LBA):一维逻辑寻址
随着磁盘容量增长和SSD的普及,CHS的物理模型不再适用,LBA被引入以简化寻址。
LBA的原理:
- 将磁盘所有扇区按顺序从0开始编号,形成一个一维线性地址空间:基于扇区的数组;而数组天然具有下标,每个下标对应扇区的编号。
- 操作系统直接通过LBA编号访问扇区,无需关心物理位置。
- 比如:LBA 0 = 第0个扇区,LBA 1 = 第1个扇区,以此类推。
LBA的优势:
-
突破容量限制:
LBA使用32位或64位地址,支持极大容量(如64位LBA理论支持2^64*512B = 9.4ZB)。
-
简化接口:
操作系统和硬盘控制器只需处理线性地址,屏蔽物理细节。
-
兼容性:
适用于机械硬盘和SSD。
LBA与CHS的关系:
假设任意一个扇区都有下标,每个盘面有2W个扇区,每个盘面有50个磁道,每个磁道有400个扇区。
现在有一个编号为28888的扇区,确定是哪个磁头(确定磁头就是确定盘面)的哪个磁道的哪个扇区:
28888/20000 = 1;28888%20000 = 8888;
8888/400 = 22;8888%400 = 88;
LBA 28888 转化为CHS 第1个磁头的第22个磁道的第88个扇区。
上面是举例说明,并不是真正的转换方式,转换公式如下所示:
-
CHS到LBA的转换(假设每磁道有
S
个扇区,每柱面有H
磁头):
L B A = ( C ∗ H + H ) ∗ S + ( S − 1 ) LBA = (C*H+H)*S+(S-1) LBA=(C∗H+H)∗S+(S−1) -
LBA到CHS的逆转换:
C = L B A / ( H ∗ S ) C=LBA/(H*S) C=LBA/(H∗S)H = ( L B A / S ) m o d H H=(LBA/S) mod H H=(LBA/S)modH
S = L B A m o d S + 1 S=LBA modS+1 S=LBAmodS+1
-
注意:现代磁盘的物理参数(比如每道扇区数)可能动态变化,因此转换仅为逻辑映射。
比喻理解CHS和LBA:
- CHS:像图书馆的三维坐标(楼层-书架-书的位置),需要明确物理位置。
- LBA:像图书馆给每本书分配一个唯一的编号(如“第12345本书”),无需关心物理存放位置。
将磁盘的物理存储结构根据扇区抽象成一维空间的逻辑存储结构,这就是对磁盘理解的建模过程。
后面的文件系统将围绕逻辑结构展开讲解。
二.文件系统
先分区再分组
分区(Partitioning)
在磁盘的逻辑存储结构时已经讲解过将磁盘抽象成一维扇区数组进行存储,每个扇区的编号对应数组的下标。
而分区则是对一整个逻辑扇区数组进行划分,本质上则是划分磁盘的逻辑边界。
假设现在有一个800GB的磁盘,分成5个区:分别是200GB,100GB,150GB,150GB,200GB;
和进程的地址空间划分非常相似。
分区的目的:
- 隔离数据:将磁盘划分为多个独立区域,每个分区可安装不同操作系统,存储不同用途的数据(比如系统分区,用户数据分区)。
- 灵活性:不同分区可以格式化为不同文件系统,支持不同的性能和功能需求。
- 安全性:某个分区损坏时,仅影响当前分区,其他分区数据可能不受影响。
分区格式化(看完后面的块组结构再看):
每一个分区在被使用之前,都必须先将部分文件系统的属性信息提前设置进对应的分区中,方便后续使用这个分区,这就是分区格式化。
格式化时,文件系统初始化:
- 划分块组(数量根据分区大小自动计算)。
- 在每个块组中创建块组描述符表,inode表,位图,数据块等;部分块组中包含超级块。
分组(Block Group)
磁盘分区后,单独的一个区要继续划分为组Block group
,每个组同样也有编号,按顺序从0开始:
分组的必要性(看完后面的块组结构再看):
- 性能优化:将大分区划分为多个块组(Block Group),减少磁头移动(HDD)或提高并行性(SSD)。
- 元数据局部性:每个块组独立存储inode和数据块(后面讲),提高文件访问效率。
- 容错与恢复:超级块在多个块组中备份,单一损坏可通过备份恢复(后面讲)。
块组结构
每个块组包含以下关键部分:
1.inode表(inode Table
)
文件=文件内容+文件属性
因此在磁盘上存储文件=存储文件内容+存储文件属性
Linux的文件在磁盘中存储,是分开存放的,而文件属性就是存储在inode
表中。
每个文件都有自己的属性,因此需要对存储文件属性进行管理。
每个文件都有一个inode
数据结构体,里面存放的是单个文件的所有属性,大小为128字节,一般而言,一个文件一个inode。
struct inode{
//inode编号
inode number;
//文件类型
//权限
//引用计数
//拥有者
//所属组
//ACM时间
//这个后面讲
int i_block[NUM];
};
inode结构体中有一个唯一的inode编号,在Linux中,文件的属性不包含文件名称,标识文件用的是inode编号
而inode表则是用来存储该块组内所有文件的inode结构,每个inode对应一个文件,也就是说一个组内可以存储多个文件的属性。
2.数据块(Data Blocks
)
文件属性存储在inode表中,而文件内容则是存储在数据块中。
存文件内容的区域,以块的形式呈现,每个数据块的大小为4KB,如果扇区大小是512B,则一个数据块包含8个扇区;如果是现代扇区大小4KB,则一个数据块包含1个扇区。(了解即可)
在Data Blocks中每个数据块都有自己对应的编号(逻辑块号,类似于逻辑扇区编号),一个文件可能要使用多个数据块存放文件内容,因此在存放文件属性的inode结构体中有一个数据块指针数组int i_block[NUM]
来组织该文件的数据块。
数据块指针数组i_block
默认大小为15(即包含15个指针),其中前12个为直接指针,后三个为间接指针(一级,二级,三级)。
数据块指针数组的层次结构:
1.直接指针(Direct Blocks)
-
位置:
i_block[0]
到i_block[11]
(共12个)。 -
功能:
直接指向存储文件内容的数据块(逻辑块号)。
-
容量限制:
假设块大小为4KB,12个直接指针可存储
12*4KB=48KB
的文件。
2.一级间接指针(Single lndirect Block)
-
位置:
i_block[12]
。 -
功能:
指向一个间接数据块,该块本身不存储文件数据,而是存储多个直接指针。
-
容量计算:
- 每个间接数据块的大小为4KB,每个指针占用4字节(32位系统)或8字节(64系统)。
- 假设块大小4KB,每个指针4字节,则一个间接数据块可存储
4KB/4B=1024
个指针。 - 总容量:
1024*4KB=4MB
。
3.二级间接指针(Double Indirect Block)
-
位置:
i_block[13]
。 -
功能:
指向一个二级间接数据块,该块指向多个一级间接数据块。
-
容量计算:
- 每个一级间接数据块可存储1024个指针,每个二级间接数据块可存储1024个一级间接数据块指针。
- 总容量:
1024*1024*4KB=4GB
。
4.三级间接指针(Triple Indirect Block)
-
位置:
i_block[14]
。 -
功能:
指向一个三级间接数据块,该块指向多个二级间接数据块。
-
容量计算:
- 每个一级间接数据块可存储1024个指针,每个二级间接数据块可存储1024个一级间接数据块指针。每个三级间接数据块可存储1024个二级间接块指针。
- 总容量:
1024*1024*4KB=4GB
。
3.inode位图(inode Bitmap
)
每个块组可以使用的inode数量是固定的,需要确定都有哪些是未使用的,哪些是被使用的。
inode位图中比特位的位置和inode编号映射起来,比特位上的内容0/1标记该inode是否有效(使用还是未使用)。
4.块位图(Block Bitmap
)
比特位的位置和数据块号映射起来,比特位上的内容0/1标记该数据块是否有效(使用还是未使用)。
5.块组描述符表(Group Descriptor Table
)
用于描述整个块组的情况,记录每个块组的元信息:一共有多少个inode;有效和空闲的inode数;一共有多少个数据块;有效和空闲的数据块数;inode表位置等。
6.超级块(Super Block
)
用于描述整个文件系统的基本信息(里面包含的是整个分区的基本使用情况):块组大小,块组总数,inode数,空闲块列表等。
超级块不会在每个块组中都存在,这样就会有点浪费空间;但如果一个分区里只有一个块组存在超级块,一旦这个超级块丢失,整个分区的文件系统都会挂掉。
为了避免上面的情况,采用的则是备份超级块:分散在不同的块组中,防止主超级块损坏(例如块组0,1,3,5,7…)。一旦某个块组的超级块损坏,就可以使用其他块组中的备份超级块维护好整个分区的文件系统。
特殊文件“目录”
1.目录的数据块
目录本身是一个特殊类型的文件,其数据块内容存放的不是用户数据,而是文件名与inode编号的映射表。
- 表中的每个条目称为目录项,包含文件名和对应的inode编号,(还包含其他东西,但重点是文件名和inode编号的映射关系),映射表中包含当前目录下所有文件的文件名和inode编号的映射关系(包括子目录)。
- 通过
ls -i
指令可以查看目录下文件的inode编号(还可以搭配其他选项使用):
2.目录的inode
-
元数据信息:
目录的inode存储元数据(比如权限,时间戳,链接数等),其
i_block
字段只想存储目录项的数据块。 -
目录链接数(后面讲):
每个目录的硬链接数(
nlink
)至少为2(自身.
和父目录..
的链接)。
三.软硬链接
软链接
1.定义
-
独立文件:
软链接是一个独立的文件,有独立的inode编号,也有独立的数据块,他的数据块中存储的是目标文件的路径字符串。
-
本质:
通过路径间接指向目标文件,若目标文件被删除,则软链接失效。
-
应用场景:windows桌面的快捷方式,直接点击应用图标就能启动程序,快捷方式本质上就是软链接。
2.特性
- 跨文件系统:可以链接不同磁盘分区的文件
- 占用空间:软链接自身占用少量存储空间(用于存储路径信息)。
- 无链接数影响:创建软链接不会影响目标文件的inode计数。
- 支持目录:可以创建目录的软链接。
3.操作命令
创建软链接:
ln -s [目标文件] [软链接文件]
删除软链接:
unlink [软链接文件]
硬链接
1.定义
-
直接绑定inode:
硬链接不是独立的文件,没有独立的inode编号,而是和目标文件共享inode编号(通过inode编号中的数据块指针数组就可以找到数据块,所以本质上数据块也共享),硬链接是文件系统中同一个inode的多个目录入口(文件名)。
-
本质:
所有的硬链接共享相同的inode编号和数据块,删除任意一个硬链接不会影响其他链接。所谓的建立硬链接,本质上是在特定目录的数据块中新增文件名和目标文件inode编号的映射关系。
-
硬连接数:
每一个inode结构体中都有一个引用计数的计数器,用来表示有多少个指向当前目标文件,也就做硬连接数。
-
应用场景:
最常见的就是用来目录切换,每个目录都包含两个隐藏文件:
.
和..
文件;.
文件和当前目录共享inode编号和数据块(本质上是在当前目录的上一级目录的数据块中增加新的.
文件和当前目录inode编号的映射关系);而..
文件则是和当前目录的上一级目录共享inode编号和数据块(本质上是在当前目录的上一级目录的上一级目录的数据块中增加新的.
文件和当前目录inode编号的映射关系)通过对目录硬链接.
和..
文件,就可以实现路径之间的切换。
2.特性
-
同一文件系统:硬链接必须与源文件位于同一磁盘分区或文件系统。
-
无大小开销:硬连接数不占用额外存储空间(仅在特定的目录中增加一个目录项)。
-
链接数递增:每增加一个硬链接数,inode的计数加1。
-
不支持目录:
Linux系统中不允许对目录建立硬链接,因为会形成环路问题,一旦形成环路问题,在环路中查找目标文件,就会形成死循环。
至于上面提到的
.
和..
文件对目录建立硬链接这是系统创建的,系统在路径中查找文件时不会考虑这两个硬链接文件。
3.操作命令
创建硬链接:
ln [目标文件] [硬链接文件]
删除硬链接使用rm
即可
图中黄色方框中的就是硬连接数;绿色方框表示硬链接使用相同的inode编号
四.文件增删查改过程
创建文件与硬链接
1.创建原始文件
操作:
echo "hello world" > file.txt
文件系统操作:
- 分配inode:文件系统会分配一个空闲inode(比如inode 1000),记录元数据(文件属性)。
- 分配数据块:将文件内容写入到数据块中,使用的数据块按照编号填入到inode的数据块指针数组中。
- 更新位图:将inode和使用的数据块根据编号将对应的位图中比特位从0置为1
- 创建目录项:在该文件所在目录的数据块中添加条目
file.txt---inode 1000
,建立文件名和inode编号的映射关系。 - 初始化硬链接数:inode的硬链接计数设置为1。
2.创建硬链接
操作:
ln file.txt hard-link
文件系统操作:
- 复用目标文件的inode:不创建新的inode,而是直接复用目标文件inode 1000(共享inode和数据块)。
- 新增目录项:在该文件所在目录的数据块中添加
hard-link---inode 1000
,新增硬链接文件名和inode的映射关系。 - 更新硬链接数:共享inode中的硬连接数增加1。
删除文件或硬链接
1.删除硬链接(硬链接数大于1)
操作:
rm hard-link
文件系统操作:
- 删除目录项:从目录中删除映射关系
hard-link----inode 1000
。 - 更新硬连接数:硬链接数减1。
- 保留数据:因为删除后硬连接数还是大于0,还有其他文件在使用inode和数据块,所以inode和数据块仍保留。
2.删除最后一个硬链接(硬链接数等于1)
操作:
rm file.txt
文件系统操作:
- 删除目录项:从目录中删除映射关系
file.txt----inode 1000
。 - 更新硬链接数:inode中的硬链接数减1,变为0。
- 更新位图释放资源:因为硬链接数变为0,不再有其他的文件使用该inode和数据块,所以根据编号将对应位图中比特位上的1置为0。至于inode和数据块中原有的数据则不用删除,文件系统分配给下一个使用的文件时,该文件填充对应的属性和内容会自动覆盖原有的数据,进而达到删除的效果。
查看文件内容
如果目标文件硬链接数大于1,可以通过任意硬链接访问查看。
操作:
cat file.txt
#或者cat hard-link
文件系统操作:
- 路径解析:通过文件名找到对应的inode编号(比如
file.txt--->inode 1000
)。 - 读取数据内容:通过inode编号找到对应的inode结构体,再根据结构体里的数据快指针数组找到使用的数据块,获取内容。
关键特性:
所有硬链接平等,无论通过哪个硬链接访问查看,均指向同一inode和数据块。
修改文件内容
操作:
echo "Updated content" > file.txt
文件系统操作:
- 写入数据:先分配一个数据块,若新内容未超过原数据块容量,直接覆盖;如果需要更多空间,分配新的数据块并更新inode中的数据快指针数组。
- 同步所有硬链接:所有硬链接指向同一inode,修改后立即对所有硬链接可见。
以上就是关于文件系统的讲解,从硬件磁盘到文件系统再到软硬链接,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!