博客总结
核心内容
磁盘物理结构
机械硬盘(HDD)与固态硬盘(SSD)的区别,磁盘的组成(盘片、磁头、磁道、扇区)及工作原理(磁头悬浮、高速旋转)。
企业级磁盘与桌面级磁盘的差异,云服务器与机房的基础架构。
磁盘的逻辑抽象
CHS定址法:通过磁头(Header)、磁道(Cylinder)、扇区(Sector)定位数据。
LBA逻辑块地址:将磁盘抽象为线性数组,以逻辑块为单位(如4KB)管理数据。
分区的逻辑划分与管理(起始LBA、结束LBA),分治思想的应用。
文件系统(ext2为例)
分区格式化:写入文件系统元数据(超级块、块组描述符、inode表、块位图等)。
文件存储机制:
文件属性存储在inode中(inode编号唯一标识文件)。
文件内容通过数据块映射(直接/间接寻址)管理。
目录的本质:特殊文件,存储文件名与inode的映射关系。
文件操作底层原理
增删查改:通过位图(inode Bitmap、Block Bitmap)管理资源分配与释放。
删除文件的实际操作(位图置0)与数据恢复的可能性分析。
Linux实战操作
使用
dd
命令创建虚拟磁盘镜像,格式化(mkfs.ext4
),挂载分区(mount
/umount
)。分区的挂载原理与路径解析(目录树、dentry结构)。
目录
博客总结
核心内容
1.看物理磁盘
2.了解磁盘的存储结构
3.对磁盘的存储进行逻辑抽象
index 下标---> CHS地址?
4.引入文件系统 ---- 如何管理磁盘文件的
1.一个目录下不能建立同名文件(文件名在一个文件里面必须为1个)
2.查找文件的顺序
3.目录的r本质是是否允许我们读取目录的内容,如文件名:inode的映射关系
4.如何理解一个文件的增删查改?
增
查:
改:
删:
如何找到一个文件?
模拟实现一个分区
命令dd
基础选项
一个文件其实在访问之前, 都是先有目录的。
没有被打开的文件,存放在磁盘当中,要找到这个文件,先要通过文件路径与文件名在磁盘中找到。
1.看物理磁盘
![]()
企业级磁盘,有个盖子(云服务器)
![]()
服务器 ![]()
磁盘图示 ![]()
机房(机柜里放服务器)
服务器不需要键盘等等,只需要网络,磁盘插在服务器里面。
磁盘中有盘片(多个层叠),可读可写可擦除(光盘(小时候放碟子看动画片)是只读的)
一片的两面都可以写,每片有两个磁头,六个盘片12个磁头,通过马达的带动,高速旋转,磁头左右摆动,磁盘的本质是一个机械设备,一秒钟几万转。磁头和盘面是不能挨着的是悬浮的,挨着会刮花盘片,磁盘里是无尘密封的防止刮花盘片。因此机械磁盘容易损伤,如果发生碰撞很容易就坏了,故障率很高。
一般个人不会使用磁盘(客户端不使用), 磁盘一般在企业用的比较多,我们现在一般用SSD固态硬盘。笔记本就不会装磁盘。虽然磁盘在效率上没有固态硬盘高,但是机械磁盘的容量大的多,稳定,性价比高。
磁盘:
桌面级磁盘(民用的)
企业级磁盘(企业用的,要求高)建立一个机房保底都是几十亿甚至上百亿。因此组件机房只能大公司组件。因此云服务器是大公司给中小企业或者个人提供的。
2.了解磁盘的存储结构
磁盘是一个机械设备外设,不管是cpu、内存、显卡、网卡他们之间用总线连接起来,设备之间数据拷贝都是通过光电信号。机械设备跑的再快也赶不上电子速度,速度是很慢的。因此我们尽量一次就向外设写入更多的数据。这就是为什么内核也需要提供缓冲区的原因,积攒一部分定期再传输到外设磁盘里面。
磁盘的盘片不是光滑的,是由无数的同心圆组成,将来的数据就存在同心圆里,每个盘片上有无数个磁铁,每一个磁铁都有南北极,如果是N的话表示为1,为S的话表示0,数据写在磁盘上的本质是通过磁头改变南北极就可以改变0、1。磁盘报废了,是不能随便处理的,牵扯到各种数据安全的问题,最安全的处理方式是清掉上面的所有数据,对磁盘进行消磁、将磁盘中的所有数据全写0或1。
磁盘读写的时候的基本单位是一个扇区。一般是512字节(也可能是4kb企业级的磁盘)
1片 = n磁道
1磁道 = m扇区
当我其实只需要改变512字节中的一个比特位时,也需要将这个扇区都加载到内核当中修改,改完之后再回磁盘,必须以一个扇区512字节的单位进行读写修改操作
多个同一半径的磁道(柱面)就会形成柱面:
![]()
磁盘的存储结构 1.如何找到一个指定位置的扇区?找到Header、Cylinder、Sector ---- CHS定址法
- a.先确认在哪一面(确认是哪一个磁头) 磁头:Header
- b.磁头左右移动,缩小与圆心的距离,再确定是哪一个,磁道(柱面)Cylinder
- c.盘片高速旋转时找到指定的 扇区:Sector
磁头左右摆动 ---> 定位磁道
盘片高速旋转 ---> 定位扇区
文件 = 内容 + 属性 ==== 都是数据 ---> 都是二进制数据
文件其实就是在磁盘中占有几个扇区的问题!!!
3.对磁盘的存储进行逻辑抽象
我们走一遍OS对磁盘这样的设备进行管理和抽象,为什么OS直接用CHS,耦合度太高

磁带的本质是将一个圆形结构拉长成一个线性结构 ----> 我们这里就是想将一个磁盘的盘面抽象成一个线性结构。无论是靠近圆心的磁道还是远离圆心的磁道所存储的数据都是等量的512*8个比特位(现在已有技术做到不等量)
相当于得到了一个数组: sector disk_array[N] N为数组的下标,操作系统通过下标找到一个扇区。
那么通过下标是怎么得到磁盘位置的呢
index 下标---> CHS地址?
假如一个磁盘,每个盘面都有1000个扇区,十个磁道,则一个磁道里有100个扇区
index/1000 = H 表示在哪一个面上的
比如等于0就是第一个面上的,
等于2就是第三个面上的 ...
index%1000 = temp [0,999], 表示在H面的第temp个扇区 通过temp/100 = C 表示在哪一个磁道(柱面) temp%100 = S 表示在哪一个扇区 假如现在的下标是500:
通过 500/1000 = 0 , 则表示在0面上
通过 500%1000 = 500, 则表示在1面的第500个扇区(属于这一面上的第500个扇区),这第五百个扇区在哪一个磁道上呢?
通过 500/100 = 5, 则表示在第5个磁道(柱面)
通过 500%100 = 0, 则表示在第五个磁道上的第1个扇区上
因此index为500的CHS地址为在第0(1)面上的第5个磁道的第1个扇区上。
文件 = 很多个Sector(扇区)的数组的下标
一般而言,操作系统未来和磁盘交互的时候:
基本单位:4KB(大部分场景够用)(8个连续扇区) ----> 数据块
文件 = 很多个块构成
通过块号是多少,这个 号数*8 就是他这块第一个数据的下标
对于OS而言,未来我们读取数据,就可以以块为单位。所以对于OS而言,他只需要知道一个起始地址,和磁盘的总大小,有多少块,每个块的块号,就能知道如何转换到对应的多个CHS地址。
我们把块号叫做:LBA(Logical Block Address 逻辑块地址 )
最后就将对磁盘的管理转化成了对数组的管理: LBA blocks[N]
分区:只需要知道每一个区的开始LBA、结束LBA
因为我们整个磁盘的大小是800GB,管理起来还是很困难的,因此会将800GB拆分成几个区域,
只要能管好一个区域,就能通过一个区域的管理经验(ctrl + c,ctrl + v)管理好其他几个区域的空间,因为都是0、1序列。
4.引入文件系统 ---- 如何管理磁盘文件的
文件 = 很多个LBA地址
对于一个分区的内容,还会进行分组:
以上的整个思想称为分治。
分组后,每个组内又会分很多属性
文件 = 内容 + 属性(属性本质也是数据)
现在以一个分区的分组来讲:在每一个分区内部分组,然后写入文件系统的管理数据 ---> 格式化(在磁盘中写入文件系统)
Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。
- Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子
- 数据区(Data blocks):存放文件内容,实际上它所占的面积是最大的,每一个块都有它的块号。假如一个文件是5kb,那么就需要占据两个块,因为文件内容是以块为单位被管理。
- 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用,有一万个块,则在理想情况下就有一万个比特位。一个4KB的块能保存4*1024个字节。如果有10万个数据块,理论上位图只需要4*4KB,就能表示出每一块的使用状态。
比特位的位置就表示的是块号,比特位的内容表示该块是否被占用
- i节点/node表(inode Table):存放文件所有的属性 如 文件大小,所有者,最近修改时间等。Linux中的文件的属性是一个大小固定的集合体。文件的属性存在inode表中。如果有一万个文件,10000个inode,需要10000/32 =312个块就能保存这些文件(一个块表示32个inode),inode内部不包含文件名。内核层面:每一个文件都有inode number!我们通过inode标识一个文件
一个正常文件一个inode属性集合
- inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
比特位的位置表示是第几个inode(inode number):比特位的内容,表示是否被占用
通过这样的方法可以查看inode号:
ll -li
/
一般是通过文件的inode号直接找到文件的属性集,文件的属性集中是会包含一个数组datablocks[N],这个数组会保存该文件占据的数据块(数据块的块号),就可以存到包含了哪些数据块,就可以找到文件的内容。
- GDT(Group Descriptor Table):块组描述符,描述块组属性信息基本情况,像是多少inode被使用了....一个管理字段。
- 超级块(Super Block):整个分区,整个文件系统分区的情况,存放文件系统本身的结构信息。记录的信息主要有:block 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。超级块不是每个分区都有的,也不是整个分区里只有一个,他会根据不同的文件系统在两到三个分组里存在。让文件系统变得更稳定。
在我们寻找文件的时候,都必须先得到文件得我inode号,inode编号是以分区为单位,不是以分组为单位来编号的,通过inode号就能确定在哪一个组,到了分组里,就能根据inode号 - start_inode就能找到inode Bitmap确定我的inode是合法的,再索引inode table就能找到文件的inode属性,此时就能通过数据块的映射关系找到文件所有的内容。(inode不能跨分区访问,在分配的时候,会记录分组,在GDT和超级块当中会记录inode的范围[start_inode,end_inode])。
int datablocks[N]一般多大,一般是N = 15,datablocks[0,11](一共十二个数据块),前12个数据块是直接寻址,直接指向data blocks中的对应数据块(数据块直接保存文件的内容),像是12号的指向一个数据块,数据块中会保存指针数组,间接的指向其他数据块,14号指向一个数据块,数据块中保存指针数组,间接的再指向其他指针数组,再指向数据块。如此这般就相当于将datablocks[N]扩容。这里其实可以实现跨组访问(但不建议,意味着所有的块可能不连续了,让磁盘效率变低)
凭什么直接拿到inode编号,我们一直使用的是文件名
目录:(目录也是文件并且有inode)
目录 = 文件属性 + 文件内容(文件名和inode编号的映射关系):
1.一个目录下不能建立同名文件(文件名在一个文件里面必须为1个)
2.查找文件的顺序
- 先根据文件名(在目录的数据块中保存,所以inode不需要存文件名,而是根据文件名找inode编号)找到文件的inode编号----->找到文件内容
3.目录的r本质是是否允许我们读取目录的内容,如文件名:inode的映射关系
目录的w:新建文件,最后一定要向那个当前所处的目录内容中写入:文件名和inode的映射关系,因此没有写权限,就没有办法在指定的目录下创建文件。
4.如何理解一个文件的增删查改?
增
新建一个文件的本质实际上是需要的是在特定的分区当中申请一个inode编号,super block他也会记录下来最近一次该分配哪个inode编号了,根据inode再确定在哪个分组里,再从位图inode bitmap里找(从低向高找),哪一个比特位为0,对应的偏移量加上分配给我的inode编号从而得到新的inode编号,再在inode table ,inode表里直接分配一个新的inode空间,写上属性。要有对应的文件内容,直接在block bitmap里申请位图,通过需要几个块,在block bitmap里找几个为0的,找到之后在数据块中把内容写上,写完之后将块和inode属性建立映射关系,得到inode编号,将inode编号返回,再建立文件名到inode的映射关系写到目录里,此时就新增了一个文件。
查:
通过文件名找到inode编号。。。
改:
文件分为改属性还是改内容。
删:
找到inode bitmap里的位图,将这个比特位由1置0,文件的inode在表里面就相当于被删掉了,inode table里还有对应的映射关系,遍历整个datablocks数组,把用到的数据块,在数据块位图里依次清0。文件的属性和内容就被删除了。
这就是为什么在拷贝一个文件的时候需要拷贝很久,删除一个文件就很快(只用让文件的内容和属性无效),因此当在linux系统中如果误删了一个文件是可能恢复的,需要找到这个文件的inode,inode bitmap置1,inode table里再找到对应的数组,再遍历所有的数据块,再把block bitmap置1。但是实际情况下,当误删文件就什么都不要做了,一旦再新建文件,此时会在这个分组里直接把对应的刚清空的bitmap直接复用,属性覆盖,这个文件就真的找不到了。
被删除的inode,会在linux日志里记录下来。实际上想要恢复最好借助工具。
如何找到一个文件?
找到指定的文件 -> 该文件所在的目录(也是文件,最后要找到根目录) -> 打开 -> 根据文件名 :inode -> 目标文件的inode
逆向的路径解析: OS自己做的
这就是为什么我们在linux中,定位一个文件,在任何时候都需要有路径的原因
linux会缓存路径结构
因为每一个分区都有可能有相同的inode,因此想要知道文件在哪,需要先确定文件的分区
我们所使用的云服务器一般只有一个盘vda(虚拟出来的一个分区):
在linux需要访问一个分区,是需要将这个分区挂载:将一个磁盘分区和文件系统的目录进行关联,
进入这个分区,本质上是进入一个目录。
就比如说我现在所做的所有操作都在目录/dev/vda2上操作。
模拟实现一个分区
命令dd
dd
命令是 Linux 中用于复制和转换文件的强大工具,常用于磁盘操作、数据备份等场景。以下是其常用选项及说明:
基础选项
if=FILE
指定输入文件(源文件),默认为标准输入(stdin
)。
of=FILE
指定输出文件(目标文件),默认为标准输出(stdout
)。
bs=BYTES
设置块大小(一次读写的数据量),默认单位为字节。支持后缀(如K
、M
、G
)。例如:bs=4M
。
count=N
仅复制前N
个输入块。例如:count=1
表示复制 1 个块(总大小 =bs
×count
)。
skip=N
跳过输入文件的前N
个块后开始读取。
seek=N
跳过输出文件的前N
个块后开始写入。
dd if=/dev/zero of=disk.img bs=1M count=2
从/dev/zero(这个文件是字符文件内容全0)中读,拷贝给disk.img,块大小是1M,2个块大小:
最后形成一个2M的文件
mkfs.ext4 disk.img
disk.img相当于一个简单的分区
格式化一个文件系统:当前支持ext2/3/4
mkfs.ext4 disk.img
当然我当前的分区太小了不足以格式化:
将分区修改的稍微大一点:10M, 就格式化完成
挂载分区:
创建一个目录:
mkdir mymnt
将分区挂载到mymnt目录下:
sudo mount disk.img mymnt
再查看:
df -h
这个loop0就是被挂载的分区disk.img
此时进入mymnt目录,创建一个test.txt:
此时已经可以创建文件了。
分区 -> 写入文件系统(格式化)---> 必须挂载到指定的目录下并进入该目录在指定的分区中进行文件操作。
不使用这个分区了:
sudo umount mymnt/
再删除这个创建的分区文件:
一个文件其实在访问之前, 都是先有目录的。
我在哪一个目录下,就在哪个分区下,目录本身能定位文件,还能帮我确定我当前在哪个分区。
目录通常是我或者我的进程早就提供了。通常是由内核文件系统提前写入并组织好,然后我们提供的
比如说:
在这里touch就是一个进程,启动时他会记录自己的路径,创建文件时将自己的路径与文件进行拼接,形成一个全路径,根据路径确认在哪个分区,然后inode bitmap、data block,置1申请各种属性数据块,inode映射再写到当前的目录里面,所创建的文件就在当前路径下创建好了。
linux内核在被使用的时候,一定存在大量的解析完毕的路径,并对路径信息做管理。对于一个被打开的文件(目录),都会存在一个struct dentry的结构,里面会包含路径解析的信息,一个文件一个dentry。
了解:
dentry里面还有个字段指向文件的指针,最终形成一颗目录树,帮我们找到文件。
整个文件会帮我们缓存下来。
在文件结构当中会存在一个path的结构
点进path之后就会有:
点进dentry
结语:
随着这篇关于题目解析的博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。
在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。
你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容,让我们在知识的道路上共同前行。