文章目录
- [1. 磁盘](#1. 磁盘)
- [2. 块、分区、分组](#2. 块、分区、分组)
- [3. inode](#3. inode)
- [4. 路径解析](#4. 路径解析)
- [5. 路径缓存](#5. 路径缓存)
- [6. 挂载分区](#6. 挂载分区)
- [7. 软硬链接](#7. 软硬链接)
1. 磁盘
分类
磁盘是一种常见的计算机存储设备,用于保存和读取数据。根据其工作原理和使用方式,磁盘可以分为几种类型,最常见的有硬盘(HDD)和固态硬盘(SSD)。
-
硬盘(HDD,Hard Disk Drive):
- 硬盘是基于磁性原理工作的,内部有一个或多个旋转的圆盘(盘片),盘片表面涂有磁性材料,通过磁头读写数据。
- 数据存储的方式是通过改变磁盘表面磁性材料的磁化方向来表示二进制数据。
- 优点:存储容量大,价格相对便宜。
- 缺点:由于机械部分的存在,读写速度较慢,且容易受到震动等物理因素影响,故可靠性相对较低。
-
固态硬盘(SSD,Solid State Drive):
- 固态硬盘与硬盘不同,它没有机械部分,采用闪存芯片存储数据,数据通过电流的变化存储在存储单元中。
- 由于没有机械部件,SSD的读写速度极快,且更耐用,抗震性强。
- 优点:速度快、耐用、体积小,噪音低。
- 缺点:价格相对较高,存储容量相比HDD通常较小。
-
其他类型的磁盘:
- 光盘(CD/DVD):使用激光读取和写入数据,适用于较低容量的存储需求。
- 软盘(Floppy Disk):一种较老的磁盘存储形式,容量小且速度慢,现在已经很少使用。
磁盘的物理结构

(1)盘片(Platters)
- 盘片是硬盘内部用来存储数据的圆形金属片,通常由铝合金或玻璃材质制成,表面涂有磁性材料。
- 数据以磁性的形式存储在盘片表面上。盘片的数量会影响硬盘的容量和性能,多个盘片可以堆叠在一起,每个盘片有两个表面可以用来存储数据。
(2)磁头(Read/Write Head)
- 磁头用于在盘片上读写数据。硬盘的磁头并不直接接触盘片,而是悬浮在盘片表面上方,依靠空气动力学原理保持一定的距离。
- 每个盘片表面都有一个读写磁头,盘片的读写过程是通过这些磁头来完成的。
(3)主轴(Spindle)
- 主轴是盘片的旋转轴,它使盘片旋转以便数据读写。主轴通常由电动马达驱动,转速常见的有 5400 RPM、7200 RPM 等。
- 硬盘的性能(如访问速度)和转速有很大关系,转速越高,读取数据的速度也越快。
(4)臂架(Actuator Arm)
- 臂架是一个用来支持磁头并将其定位在盘片上的机械臂。它通过精密的控制系统来移动磁头,从而读取或写入指定位置的数据。
- 臂架通过控制器驱动,在盘片上精确定位磁头,通常采用电磁力驱动来精确调整磁头的运动。
磁盘的存储结构
磁盘存储的基本单位是扇区,扇区的大小一般是512字节。




- 磁头(head)数: 每个盘片一般有上下两面,分别对应1个磁头,共2个磁头
- 磁道(track)数: 磁道是从盘片外圈往内圈编号0磁道,1磁道,靠近主轴的同心园用于停靠磁头,不存储数餐
- 柱面(cylinder)数: 磁道构成柱面,数量上等同于磁道个数
- 扇区(sector)数: 每个磁道都被切分成很多扇形区域,每道的扇区数量相同
- 圆盘(platter)数: 就是盘片的数量
- 磁盘容量 = 磁头数 x 磁道(柱面)数 x 毎道扇区数 x 毎扇区字节数
- 细节: 传动臂上的磁头是共进退的
CHS地址定位 && LBA地址
想要定位一个扇区,我们只需要知道柱⾯(cylinder),磁头(head),扇区(sector)这三个参数即可。
对早期的磁盘⾮常有效,知道⽤哪个磁头,读取哪个柱⾯上的第⼏扇区就可以读到数据了。 但是CHS模式⽀持的硬盘容量有限,因为系统⽤8bit来存储磁头地址,⽤10bit来存储柱⾯地址,⽤6bit来存储扇区地址,⽽⼀个扇区共有512Byte,这样使⽤CHS寻址⼀块硬盘最⼤容量 为256102463*512B=8064MB(1MB=1048576B)(若按1MB=1000000B来算就是 8.4GB)

- 一个磁道展开后有多个扇区,每个扇区有一个下标,类似于一维数组。
- 一个柱面包含多个垂直位置的磁道,这样柱面-磁道形成类似于二维数组的结构。
- 整个磁盘含有多个柱面,磁盘-柱面-磁道形成类似于三维数组的结构。
所以如果想要定位某一个具体的扇区,只需要找到哪⼀个柱⾯(Cylinder),在确定柱⾯内哪⼀个磁道(其实就是磁头位置, Head),在确定扇区(Sector),所以就有了CHS。
C/C++的数组本质上都是一维数组:

每一个扇区的下标其实就是LBA(LogicalBlockAddress)地址,也就是线性地址,操作系统只需要使用LBA地址,CHS地址需要转换为LBA地址,这个工作是交给硬件电路完成。
CHS转换成LBA:
- 磁头数(单个柱面磁道数)* 每磁道扇区数=单个柱⾯的扇区总数
- LBA=柱⾯号C * 单个柱⾯的扇区总数 + 磁头号H * 每磁道扇区数 + 扇区号S - 1
- 扇区号通常是从1开始的,⽽在LBA中,地址是从0开始的
- 柱⾯和磁道都是从0开始编号的
- 总柱⾯,磁道个数,扇区总数等信息,在磁盘内部会⾃动维护,上层开机的时候,会获取到这些参数。
LBA转转换成CHS:
- 柱⾯号C=LBA // (磁头数*每磁道扇区数)(单个柱⾯的扇区总数)
- 磁头号H=(LBA % (磁头数 * 每磁道扇区数)) // 每磁道扇区数
- 扇区号S=(LBA % 每磁道扇区数)+1
所以总的来说,,磁盘就是⼀个元素为扇区的⼀维数组,数组的下标就是每⼀个扇区的LBA地址。操作系统使⽤磁盘,就可以⽤⼀个数字访问磁盘扇区了。
2. 块、分区、分组
磁盘是"块"设备,操作系统读取数取时不是一个个扇区地读取,这样效率太低,一次性连续读取多个扇区,多个连续的扇区组成一个"块"。
一个块的大小一般是4KB(连续的8个扇区,512B * 8 = 4096B = 4KB)。

LBA与块号的转换:
- 每一个扇区都有一个下标,也就是LBA地址。
- 块号 = LBA / 8。
- LBA = 块号 * 8 + x(x是块内的第几个扇区)

操作系统为了更好管理磁盘,进一步对磁盘进行了分区(类似于Windows的C盘、D盘),只需要确定管理一个分区的方式,然后将这个管理方法应用到别的分区即可。
对于磁盘的一个分区,空间还是太大了, 所以操作系统再对一个分区进行分组,管理好一个分组就可以将管理方法套用在其他分组,这样就管理好一个分区。

一个分组也就是 Block Group,是文件系统中的一个基本结构,用来组织和管理磁盘上的存储块(blocks),其中包含:
-
超级块备份(Superblock)
- 每个 block group 会存储文件系统超级块的一个备份副本。超级块包含了文件系统的全局信息,如文件系统大小、块大小、inode 数量、空闲块数量等。
- 多个 block group 都保存超级块的副本,以便在超级块损坏时进行恢复。
-
块组描述符(Block Group Descriptor)
-
用于描述一个 block group 的信息,包含以下字段:
- Block bitmap的块号:指向该 block group 的块位图的块号。
- Inode bitmap的块号:指向该 block group 的 inode 位图的块号。
- Inode 表的起始块号:指向该 block group 中 inode 表的起始块号。
- 空闲数据块数:该 block group 中剩余的空闲数据块数量。
- 空闲 inode 数:该 block group 中剩余的空闲 inode 数量。
-
-
块位图(Block Bitmap)
- 块位图用于记录哪些数据块是空闲的,哪些是已分配的。每个 bit 对应一个数据块,bit 值为 0 表示该数据块空闲,为 1 表示该数据块已分配。
- 通过位图,文件系统可以快速查找空闲的数据块,从而实现高效的存储管理。
-
inode 位图(Inode Bitmap)
- inode 位图类似于块位图,用来记录哪些 inode 是空闲的,哪些是已分配的。每个 bit 对应一个 inode,bit 值为 0 表示该 inode 空闲,bit 值为 1 表示该 inode 已分配。
- 文件系统通过 inode 位图来管理和分配 inode。
-
inode 表(Inode Table)
- 每个 block group 中包含一个 inode 表,用于存储文件和目录的 inode。inode 中包含了文件的元数据,如文件权限、所有者、时间戳、文件大小、指向数据块的指针等。
- 每个 inode 在文件系统中都是唯一的,inode 表的大小和 inode 的数量是根据文件系统的初始设置(如创建时指定的 inode 数量)来决定的。
-
数据块(Data Blocks)
- 这是用于存储实际文件内容的区域。每个 block group 会包含若干个数据块。数据块的数量取决于文件系统的大小和 block size(块大小)。
- 这些块存储文件内容,或者在目录文件中存储指向其他文件的指针。
3. inode
Linux下文件的存储其属性和内容是分离存储的,文件的属性也是用结构体去描述,这个结构体就是inode(索引节点),inode节点是固定大小的,一般是128字节;一个文件就对应着一个inode,一个inode内有唯一的标识符,inode号,其编号是以分区为单位的,一个分区内inode号不能重复,两个分区之间可以,所以inode不能跨分区访问。
注意:
- 文件名属性没有纳入
inode内,因为文件名有长有短,文件名存放在文件当前目录文件的文件内容,以文件名-inode指针的形式存在。 - 任何文件的内容大小可以不同,但是属性大小一定相同。
基本内容
一个inode节点包含以下文件信息:
- 文件类型,例如普通文件、目录文件、符号链接、设备文件等。
- 文件权限,包括读、写、执行权限(对于文件和目录都有区别)以及文件的所有者、所属用户组等。
- 文件所有者,存储了文件的所有者(用户ID,UID)和所属用户组(组ID,GID)。
- 文件大小,记录了文件的大小(字节数),即文件的内容长度。
- 时间戳,包括创建时间(birth time)、修改时间(mtime)、访问时间(atime)、元数据修改时间(ctime)。
- 文件数据块指针,包含指向实际文件内容的指针(直接指针和间接指针),当文件数据非常大时,inode 可能使用间接指针(单重间接、双重间接、三重间接指针)来指向更多的块,从而允许文件存储更多数据。
- 硬链接计数,表示有多少个硬链接指向该 inode。这帮助文件系统管理文件删除,当硬链接计数为 0 时,文件的数据块可以被释放。
查找文件的作用
每个文件(无论是普通文件还是目录)在文件系统中都有一个对应的 inode,而文件的实际数据内容则存储在数据块中。当操作文件时,操作系统通过 inode 获取文件的元数据,如文件的权限、所有者、时间戳等信息,然后根据 inode 中的指针访问文件的实际数据。
文件系统通过一个 inode 表 来管理所有 inode。每个文件系统在创建时会分配一定数量的 inode,当文件系统中没有足够的 inode 时,就无法创建新文件(即使磁盘空间尚未用完)。
与文件名的关系
在文件系统中,inode 只存储文件的元数据和数据块位置,而文件名则存储在 目录项(directory entry) 中。目录项将文件名和对应的 inode 号关联起来,这样操作系统通过文件名可以找到对应的 inode,再通过 inode 找到文件的实际内容。
例如,假设我们有一个文件 /home/user/file.txt,文件系统会有一个目录项将 file.txt 与该文件的 inode(比如 inode 号 1234)关联。文件的元数据和数据块信息都在 inode 1234 中,而文件名 file.txt 则存在于目录 /home/user 的目录项中。
多个文件名可以指向同一个inode(硬链接),删除一个文件名不会清空inode,只有当这个inode不被任何文件名相关(硬链接数为0),inode才会被释放。
数量限制
在文件系统创建时,指定了一个 inode 的数量。这个数量决定了文件系统中能够存储的最大文件数(即使磁盘空间还有空闲,也可能因为 inode 用尽而无法创建新文件)。为了避免 inode 不足,文件系统设计者通常会根据磁盘的大小和文件系统的预期使用场景来决定 inode 的分配。
- inode 不够时:当 inode 用完时,用户即使磁盘还有足够空间,仍然不能创建新文件。这是因为文件系统只能通过 inode 来索引文件的元数据。
- inode 的分配方式:现代文件系统通常会根据需要动态分配 inode,尽量减少 inode 数量过剩或不足的情况。
相关命令
- 查看文件的
inode号:ls -i filename - 查看文件系统的 inode 使用情况:
df -i - 查看文件的详细信息:
stat filename
4. 路径解析
在 Linux 文件系统中,每个文件和目录都有一个唯一的路径,路径从根目录(/)开始,经过各个子目录,最终指向目标文件。当我们访问一个文件时,实际上是通过路径逐级向下解析,直到找到目标文件。
-
路径解析的基本原理 :每个文件和目录都被唯一标识一个 inode,它存储了关于文件的元数据(如权限、所有者、时间戳等)。但文件名和目录结构本身并没有存储在 inode 中,目录项中仅包含文件名和指向 inode 的引用。因此,当我们访问某个文件时,系统需要通过路径名逐级"递归"解析,依次访问每个目录,最终到达目标文件。
-
访问当前工作目录 :当前工作目录实际上是一个目录文件,它同样有自己的 inode。当你在命令行中使用
ls等命令查看当前工作目录的内容时,操作系统首先需要访问当前工作目录的 inode,查找该目录下的文件项,并输出它们的列表。实际上,这个过程并不是直接访问文件名,而是通过 inode 来解析目录的内容。 -
递归路径解析 :访问文件的路径从根目录开始,路径中的每个目录都需要通过 inode 来解析。假设路径为
/home/whb/code/test/test/test.c,系统会从根目录开始:- 首先,访问根目录
/,通过 inode 查找到/home目录。
- 接着,访问
/home目录,查找whb子目录。 - 依此类推,直到找到最后的文件
test.c。
每一层目录都需要依次解析,打开该目录,查找目录项并获取指向下一级目录的 inode。这个过程是递归的,直到最终到达目标文件。
- 首先,访问根目录
总结:无论是文件还是目录,都有自己的路径。在 Linux 中,路径解析的过程就是从根目录开始,依次通过每个目录在·,最终找到目标文件。这个过程依赖于 inode,它帮助操作系统找到文件的实际存储位置和相关元数据。路径解析是文件系统管理的一部分,通过递归地访问每个目录,最终确定目标文件的位置。
那问题来了,路径是谁提供的?
- 路径是由用户或程序提供的。在 Linux 中,路径是文件或目录的位置表示方式,可以是绝对路径 (从根目录
/开始)或者相对路径(相对于当前工作目录)。
你访问文件,提供了路径,最开始的路径从哪里来?
- 最开始的路径(或 CWD)是由进程启动时确定的。通常情况下,进程会继承父进程的 CWD,或者在启动时指定一个默认的工作目录。
为什么 Linux 需要根目录?
- 根目录(
/)是文件系统的起点。无论文件存储在哪个物理设备上,它们都必须位于根目录下的某个位置。根目录下的各种默认子目录(如/bin、/etc、/home等)提供了文件系统的基础结构和标准布局,这样系统可以高效地存储和访问文件。- 根目录提供统一的访问点:所有的文件和目录从根目录开始,确保了文件系统的统一性和一致性。
- 默认子目录的必要性 :这些目录为系统和用户提供了预定义的存储位置。例如,
/bin存放系统命令,/etc存放配置文件,/home存放用户文件等。这些默认目录的存在是系统功能正常运行的基础。
为什么要有家目录?
- 家目录(
/home/username)是每个用户在系统中的私人空间,它提供了一个独立、隔离的区域来存储个人文件和配置,确保用户之间的数据和设置不会互相干扰,用户也可以在自己的家目录中创建新目录或文件,或者根据权限在其他地方创建目录。
总结:系统与用户共同构建 Linux 路径结。
- 系统提供基础结构 :通过根目录
/和一些预定义的子目录(如/bin、/etc等),为文件系统提供了一个有序的文件存储结构。 - 用户提供个性化扩展 :用户根据需要在自己的家目录下或者其他目录下创建新文件和目录,逐渐扩展文件系统的路径结构。
路径的最终确定,取决于 当前工作目录(CWD) 、用户输入的文件路径、以及系统如何组织和管理文件系统中的目录结构。因此,每个路径都是通过进程、系统与用户的共同作用逐步确定的。
5. 路径缓存
Linux磁盘中,存在真正的目录吗?
- 不存在,在 Linux 文件系统中,并没有"真正"的目录。目录本质上是一个特殊类型的文件,本身并不存储文件内容,而是存储了指向其他文件(包括普通文件和子目录)的指针(inode)。
访问任何文件,都要从根目录开始进行路径解析?
- 访问文件的过程中,文件系统会从根目录
/开始,依次解析每一个路径中的目录,最终找到目标文件。然而这样效率过慢,存在缓存机制(如 目录项缓存 和 inode 缓存)来优化路径解析。
Linux中,在内核中维护树状路径结构的内核结构体叫做:struct dentry
- 在 Linux 文件系统中,dentry(目录项) 是用来表示文件或目录路径中的一部分的内存结构。每个被打开的文件或目录都会有对应的 dentry 结构,dentry 主要用于缓存路径中的目录项和文件名。
- 整个树形节点也属于
LRU结构中,当 dentry 缓存满时,操作系统会根据 LRU 算法淘汰最不常用的路径节点,从而释放内存并腾出空间给新的路径。 - 当进程尝试访问某个文件时,系统会首先检查内存中的 dentry 缓存,如果缓存中存在对应的 dentry,系统会直接从内存中获取该路径的 inode 和文件属性,如果缓存中没有该路径,系统会从磁盘中加载路径信息,然后将新的 dentry 结构添加到缓存中。
- Linux 还会将 dentry 结构存储在一个 哈希表 中,通过键值对的方式存储目录项,使得通过文件名(或者目录路径中的一部分)可以快速查找到对应的 dentry 结构,从而直接获取到 inode 和相关元数据。

6. 挂载分区
前面提到磁盘是进行了分区的,不同分区的inode是独立,我们在进行路径解析的时候,如何确实是在哪个分区的?
在Linux文件系统中,是通过挂载分区实现的,要使操作系统能够访问分区上的文件,必须将该分区"挂载"到一个现有的目录下。这个挂载的目录叫做"挂载点",通常是一个空的目录。
在 Linux 中,挂载分区的基本步骤是:
- 查看分区 :通过命令
lsblk或fdisk -l查看系统中的分区。 - 创建挂载点 :使用命令
mkdir /mnt/my_partition创建一个空的目录来作为挂载点。 - 挂载分区 :使用
mount命令将某个分区挂载到刚才创建的挂载点。例如:mount /dev/sda1 /mnt/my_partition
7. 软硬链接
软连接
- 文件指针 :软链接是一个特殊的文件,它包含指向目标文件路径的路径名。软链接实际上是对原始文件路径的引用,而不是直接指向文件的 inode。
- 文件名:软链接文件本身有自己的 inode 和文件名,但它的内容是目标文件的路径。
- 跨文件系统:软链接可以跨文件系统创建,因为它只包含目标文件的路径,路径可以指向不同文件系统中的文件。
- 删除原文件:如果目标文件被删除,软链接会变成"悬空链接"(dangling link),即链接指向一个不存在的文件,尝试访问会报错。而硬链接不会受目标文件删除的影响。
- 可以跨目录:软链接可以跨目录创建,因为它仅保存目标文件的路径,而路径可以指向任何目录。
使用命令:ln -s 可以创建软连接
bash
ln -s original_file symbolic_link
硬连接
- 件指针:硬链接直接指向文件的 inode,也就是说,硬链接是对文件 inode 的一种引用。因此,硬链接和原始文件实际上是同一个文件,彼此没有区别。
- 文件名:硬链接是为文件的 inode 分配新的文件名。这意味着它与原始文件有相同的 inode 号。
- 同一个文件系统:硬链接只能在同一文件系统内创建,因为 inode 号是文件系统内的唯一标识。
- 删除原文件:当硬链接创建时,文件的内容并不会立即复制到硬链接。文件的实际内容只有在所有指向该 inode 的硬链接被删除后才会被回收。因此,删除硬链接或原文件的任意一个,不会影响文件的内容,只要还有其他硬链接存在,文件内容依然可以访问。
- 不可跨目录:硬链接不能跨目录创建,它们只能在相同目录或者相同文件系统下的不同位置创建。
使用命令 :ln(不带 -s 选项)
bash
ln original_file hard_link
注意:硬链接只能用于普通文件,不能用于目录,其原因:
- 循环引用和死循环问题,如果允许目录创建硬链接,会导致潜在的循环引用,即两个或更多目录会相互引用,形成一个环。
- 删除问题,如果硬链接指向一个目录,删除其中任何一个硬链接都会影响整个目录树。
但是,.和..分别是当前目录和上级目录的硬链接,这是特殊处理。
使用场景
-
硬链接 :适合用于确保文件内容不会因删除原文件而丢失,且多个文件名指向同一文件的场景。硬链接不容易区分文件原始名与硬链接,因此在某些需要保留文件所有权或多个引用的情况下非常有用。
-
软链接 :适用于需要指向目录或跨文件系统链接的场景。例如,创建快捷方式或链接到某个位置的配置文件等。软链接通常用于便于管理和用户友好的文件系统设计。