Linux——Ext系列文件系统

理解硬件

磁盘、服务器、机柜、机房

  • 机械磁盘是计算机中唯一的一个机械设备
  • 随机读写速度慢
  • 容量大,价格便宜

磁盘核心物理部件

  1. 盘片(Platter)
  • 磁盘的数据真正存储载体,材质为铝合金 / 玻璃基底,表面喷涂磁性涂层。
  • 数据以磁性磁极方向记录二进制 0、1,盘面正反两面都可存储数据。
  1. 磁头(Head)
  • 负责读取、写入盘面磁性数据的感应元件,每一张盘面都对应独立磁头。
  • 写入:改变盘面磁极方向;读取:感应磁极信号,转化为电信号数据。
  1. 磁臂(Arm)
  • 固定所有磁头的支架,可做径向伸缩摆动
  • 作用:带动磁头在盘片同心圆轨迹之间移动,切换不同磁道位置。
  1. 主轴电机(Spindle Motor)
  • 驱动所有盘片同步高速旋转的动力核心。
  • 转速单位:RPM 转 / 分钟,转速越高,数据读取等待时间越短。
  • 常见规格:家用 7200 转,企业服务器 10000 转、15000 转。
  1. 密封盘腔 + 外部电路板
  • 密封腔体:内部真空无尘,杜绝灰尘划伤高速运转的盘片,灰尘会直接造成磁盘坏道。
  • 电路板:磁盘的控制中枢,接收主板读写指令、缓存临时数据、转换电信号与磁信号。

磁盘的存储结构




注意:传动臂上的磁头是共进退的

1. 磁道 Track

  • 形成原理:盘片高速旋转,磁头保持静止,在盘面划过一圈同心圆轨迹,即为一条磁道。
  • 作用:磁头定位到指定磁道,才能继续读取内部扇区数据。

2. 扇区 Sector

  • 磁盘最小物理存储单元
  • 传统标准扇区:512 字节
  • 形态:盘片被径向切割成无数扇形小块,每一块就是一个扇区
  • 读写约束:硬件只能整扇区读写,哪怕只修改 1 个字节,也要读取整个扇区、修改后再整扇写回

3. 柱面 Cylinder

  • 一块硬盘内部所有盘片上,半径完全相同的多条磁道,纵向堆叠形成一个虚拟圆柱面,称为柱面

如何定位一个扇区呢?(CHS地址定位法)

  1. 定位柱面:磁盘控制器驱动音圈电机,带动磁臂径向移动,将磁头对准指定柱面
  2. 选定磁头 :电路切换,启用对应编号的磁头,对准目标盘面
  3. 等待扇区轮转:盘片高速旋转,直到目标编号扇区转动到磁头正下方

计算磁盘容量公式:
磁盘总容量 = 磁头数 × 柱面数(磁道数) × 每磁道扇区数 × 单扇区字节数

磁盘的逻辑结构

理解过程


真实过程

所以,磁盘的真实情况是:

磁道:

某一盘面的某一磁道展开:

即:一维数组

柱面:

整个磁盘所有盘面的同一个磁道,即柱面展开:

  • 柱面上的每个磁道,扇区个数是一样的
  • 这不就是二维数组吗

整盘:

  • 整个磁盘不就是多张二维的扇区数组表(三维数组?)

所以,寻址一个扇区:先找到哪一个柱面(Cylinder) ,再确定柱面内哪一个磁道(其实就是磁头位置,Head),最后确定扇区(Sector),所以就有了 CHS

总结:

不管是二维数组还是三维数组,其实都是一维数组:

所以,每一个扇区都有一个下标,我们叫做 LBA(Logical Block Address) 地址,其实就是线性地址

CHS 寻址 与 LBA 寻址

CHS、LBA 是磁盘两种扇区定位编码体系 ,核心作用只有一个:唯一确定磁盘上任意一个物理扇区

  • CHS :贴合磁盘机械物理结构的三维坐标寻址,老式磁盘标准
  • LBA :抹平物理差异的一维线性逻辑寻址,当前 Linux、文件系统、硬盘通用标准

上层操作系统、文件系统只使用 LBA;磁盘硬件底层最终会转换为 CHS 完成机械定位,二者可以相互换算

CHS 三维寻址

全称与坐标形式

  • Cylinder (柱面) + Head (磁头) + Sector (扇区)
    用一组三维坐标 (C, H, S) 锁定单个扇区。

CHS 物理定位全过程

  1. 控制器依据柱面号,驱动磁臂移动到目标径向位置
  2. 电路切换,启用指定编号磁头,对准对应盘面
  3. 盘片高速旋转,等待目标扇区转动至磁头正下方
  4. 锁定位置,执行数据读取或写入操作

寻址容量瓶颈

早期 CHS 采用固定位数存储坐标数值,可表示的柱面、磁头、扇区数量有上限,最大只能支持 GB 级小容量硬盘,无法满足如今 TB 级大容量存储需求。

CHS 优缺点

优点

  • 完全匹配磁盘机械结构,硬件底层理解直观
  • 小容量硬盘寻址响应直接

缺点

  • 三维坐标计算繁琐,程序调用复杂度高
  • 地址位数受限,容量扩展性极差

现存使用场景

仅保留在主板 BIOS、磁盘固件底层做兼容适配,现代OS不会直接下发 CHS 地址指令。

LBA 一维逻辑寻址

全称
Logical Block Address 逻辑块寻址

核心原理:抛弃磁盘三维物理结构概念,将所有物理扇区扁平化处理,按顺序编成一维连续数字编号,只用单个数字就能唯一定位一个扇区,彻底解决老式 CHS 寻址的容量瓶颈与兼容难题

LBA 核心设计思想

  • 忽略盘片、柱面、磁头的物理形态,把立体的磁盘存储空间,拉伸成一条笔直的线性存储空间
  • 每一个 LBA 编号,严格对应磁盘上唯一一个物理扇区
  • 软硬件分层解耦:上层系统只操作一维数字地址,无需关心硬件结构;磁盘固件内部自动完成逻辑地址到物理坐标的转换

扇区编排排序规则

通俗排布流程

  1. 先遍历第 0 号柱面,依次切换每一个磁头;
  2. 每个磁头对应的磁道里,按扇区顺序逐个编号;
  3. 第 0 柱面全部扇区编号完成后,继续编号第 1 柱面、第 2 柱面...... 直至整块磁盘所有扇区编完。

即:

LBA 完整寻址执行流程

  1. 系统下发逻辑地址:操作系统、文件系统计算出目标 LBA 编号,仅向磁盘控制器传递这一个数字。
  2. 固件自动地址转换 :磁盘内置固件接收 LBA 值,按照换算公式,自动把一维 LBA 地址,转换成硬件可识别的CHS 三维物理坐标
  3. 机械物理定位:磁盘根据柱面、磁头、扇区坐标,驱动磁臂移动、切换磁头、等待盘片旋转,精准找到目标物理扇区
  4. 完成数据读写:对定位到的扇区执行读取或写入操作,数据原路返回上层系统

LBA 与 CHS 地址换算原理

LBA 只是逻辑编号,最终定位依旧依靠物理 CHS 坐标,二者存在固定数学映射关系

设定参数:

  • Htotal = 磁盘总磁头数
  • Strack = 单条磁道包含扇区数
  • 磁头数 * 每磁道扇区数(Htotal × Strack)= 单个柱面的扇区总数

1. CHS → LBA

  • LBA = 柱面号( C ) × 单个柱面的扇区总数(Htotal × Strack) + 磁头号( H ) × 单条磁道包含扇区数(Strack) + 扇区号(S) − 1

  • 减 1 原因:CHS 扇区从 1 编号,LBA 从 0 编号,对齐数值偏移

2. LBA → CHS

  • 柱面号( C ) = LBA ÷ 单个柱面的扇区总数(Htotal × Strack)
  • 磁头号( H ) = (LBA ÷ 单条磁道包含扇区数(Strack))% 总磁头数(Htotal)
  • 扇区号( S ) = (LBA % 单条磁道包含扇区数(Strack))+ 1

引入文件系统

原始磁盘分区只有物理扇区,操作系统无法直接高效管理文件。文件系统的核心作用就是将无序的磁盘物理空间,规整为有序的逻辑空间,实现文件的存储、检索、权限管理。这里引入三个核心基石概念:块、分区、inode

块(Block):文件系统最小读写单元

磁盘最小物理单元是512字节扇区,操作系统如果以扇区读写,效率极低。因此文件系统将多个连续扇区组合为一个块,作为系统读写的最小单位

块的标准定义

  • 物理构成 :由一段连续的物理扇区聚合而成
  • 层级属性:纯软件逻辑概念,磁盘硬件本身不存在块
  • 是文件系统最小读写单位 和文件系统最小空间分配单位

Linux Ext文件系统默认块大小:4KB(8个512字节扇区),可在格式化时指定(1K/2K/4K)

注意:

  • 磁盘就是一个三维数组,我们把它看待成为一个"一维数组",数组下标就是LBA,每个元素都是扇区
  • 每个扇区都有LBA,那么8个扇区一个块,每一个块的地址我们也能算出来。
  • 知道LBA:块号 = LBA / 8
  • 知道块号:LBA = 块号 * 8 + n (n是块内第几个扇区)

分区(Partition):磁盘空间隔离机制

核心逻辑:磁盘→分区→格式化(生成文件系统)→挂载→可读写文件

物理上整块硬盘依旧完整一体,但软件层面实现彻底隔离:

  • 格式化、清空、损坏某一个分区,不会篡改、破坏其他分区的扇区数据;
  • 系统读写文件时,只会访问当前分区对应的 LBA 区间,不会越界访问其他分区

柱面是分区的最小单位,我们可以利用参考柱面号码的方式来进行分区,其本质就是设置每个区的起始柱面和结束柱面号码。

inode(索引节点):文件的唯一身份证

Linux中文件分为两部分,缺一不可:

  1. 元数据:文件属性(大小、权限、所有者、修改时间、数据块编号),存储在 inode 中。
  2. 数据:文件真实内容,存储在 Data Block(数据块)中

本质:inode 是一份文件的身份档案 + 寻址路标,只存文件属性与数据位置,不存放文件名,也不存放文件实际内容。

inode 内部存放的信息

  • inode 编号:分区内文件唯一标识 ID
  • 文件类型:普通文件、目录、符号链接、设备文件、管道文件
  • 访问权限:r 读 w 写 x 执行,管控用户访问权限
  • 所有者 UID、所属组 GID:记录文件归属用户
  • 文件大小:占用存储空间字节数
  • 硬链接计数:统计有多少个文件名指向该 inode
  • 三个时间戳
    atime:最后访问读取时间
    mtime:最后修改文件内容时间
    ctime:最后修改文件属性 / 权限时间
  • 数据块指针数组(核心)
    共 15 个指针,指向存放真实内容的数据块编号,用来寻址文件内容

inode 核心特性

  • 分区内编号唯一,跨分区可重复
  • 不存储文件名,文件名归属目录管理
  • 每个文件有且仅有一个唯一 inode 号,是文件的唯一标识
  • 删除文件不会立刻擦除磁盘数据
  • inode的大小一般是128字节或者256,我们后面统一128字节

查看 inode 命令

  1. 查看文件 inode 编号
c 复制代码
ls -il
  1. 查看完整 inode 所有属性
bash 复制代码
stat 文件名

示例:

ext2 文件系统

宏观认识

我们想要在硬盘上存储文件,必须先把硬盘格式化为某种格式的文件系统,才能存储文件。文件系统的目的就是组织和管理硬盘中的文件

ext2 是将物理磁盘空间组织成可管理文件体系的软件抽象层 ,通过块组化管理 实现资源分散与并行访问,通过inode 索引机制 实现文件身份标识与数据寻址,通过位图管理实现高效资源分配与回收。

ext2 文件系统将整个分区划分成若干个同样大小的块组 (Block Group),如下图所示。只要能管理一个分区就能管理所有分区,也就能管理所有磁盘文件

上图中启动块(Boot Block/Sector)的大小是确定的,为1KB,由PC标准规定,用来存储磁盘分区信息和启动信息,任何文件系统都不能修改启动块。启动块之后才是ext2文件系统的开始。

块组(Block Group)

块组 = 分区拆分出来的微型独立小文件系统,各自管理本组内的块、inode、空闲资源,实现分片自治管理

层级嵌套

bash 复制代码
物理磁盘
   ↓ 划分
磁盘分区
   ↓ 均等切分
多个大小相同的块组
   ↓ 内部组成
逻辑块 Block
   ↓ 聚合
物理扇区 Sector

核心规则

  • 一个分区包含多个块组
  • 同一个分区内所有块组尺寸、内部结构完全一模一样
  • 块组从 0 开始顺序编号,连续铺满整个分区空间
  • Ext 系列默认:每个块组固定包含 8192 个逻辑块

块组的内部构成

1. 超级块(Super Block)

本质 :整个文件系统的全局总控制台账,记录分区整体规格与资源统计信息

存储特点

  • 并非每一个块组都完整存放,只在0、1、3、5、7... 质数编号块组做冗余备份
  • 块组 0 一定包含完整超级块,是系统挂载识别入口
  • 格式固定为ext2_super_block结构体

核心存放信息

  1. 标识类:文件系统魔数(0xEF53),用来识别是不是 Ext2
  2. 规格类:块大小、inode 大小、每组块数量、每组 inode 数量
  3. 统计类:分区总块数、总 inode 数、空闲块数、空闲 inode 数
  4. 时间类:最后挂载时间、最后写入时间、检查时间

作用

  • 系统挂载时校验文件系统合法性
  • 全局统计磁盘整体使用情况
  • 副本备份防止超级块损坏导致分区无法访问

2. 块组描述符表 Group Descriptor Table(GDT)

本质 :记录所有块组基础属性与位置的索引表,每一条描述符对应一个块组

核心存放字段

  1. 本组块位图所在块号
  2. 本组 inode 位图所在块号
  3. 本组 inode 表起始块号
  4. 本组空闲块数量、空闲 inode 数量
  5. 本组内部目录文件个数

作用

  • 快速定位当前块组内位图、inode 表的物理位置
  • 实时统计本组资源余量,新建文件优先挑选富余块组
  • 是连接超级块与单个块组内部资源的中间索引

3. 块位图(Block Bitmap)

本质二进制位状态表,专门标记当前块组内每一个逻辑块的空闲 / 占用状态

核心规则

  • 1 个比特位 对应 1 个逻辑块
  • 比特值 = 0 → 块空闲,可分配存储数据
  • 比特值 = 1 → 块已被文件占用,不可分配

工作逻辑

  • 新建文件:检索比特 0,置为 1,分配对应块
  • 删除文件:对应比特改回 0,回收空间

作用:极速管理本组数据块资源,避免全局遍历查找空闲块

4. inode 位图(Inode Bitmap)

本质 :和块位图原理完全一致,专门标记inode 索引节点的空闲占用状态

工作逻辑:创建文件分配 inode、删除文件回收 inode,都依靠位图快速判定状态

5. inode 表(Inode Table)

本质 :连续存储空间,按编号顺序整齐存放本组所有 inode 结构体

基础属性

  • Ext2 默认单个 inode 大小:128 字节
  • 块组内 inode 数量格式化固定,顺序排列、编号唯一

作用

  • 存储文件身份信息、元数据、数据寻址地址,是文件在块组里的核心标识
  • 一个 inode 唯一对应一个普通文件 / 目录 / 链接文件

6. 数据块(Data Blocks)

本质 :块组内容量最大的区域,真正存放二进制真实数据的空间

按用途分为 4 类块
1. 普通数据块

存放文本、图片、程序、日志等用户真实文件内容

2. 目录块

存放目录项结构:inode编号 + 文件名 + 文件类型

实现文件名到 inode 的映射关系

3. 间接索引块

不存业务数据,只存放下级数据块指针,支撑大文件多级寻址

4. 符号链接块

存放软链接指向的目标文件路径

特性

  • 文件内容优先全部存放在同一个块组,减少跨组寻道
  • 超大文件空间不足时,才向相邻块组申请数据块

注意:

  • inode和数据块是跨组编号的
  • inode和数据块不能跨分区
  • 所以,在同一个分区内部,inode编号和块号都是唯一的

inode与Data Blocks映射

inode核心功能之一就是通过指针找到文件的数据块,Ext2 inode中定义了 i_block[EXT2_N_BLOCKS] 数组(EXT2_N_BLOCKS = 15),共15个指针,采用直接+间接的映射机制,适配不同大小的文件,兼顾读写速度与存储容量:

1. 前 12 个直接指针(i_block[0] ~ i_block[11]

  • 寻址规则:指针内直接存储数据块编号,无任何中间跳转
  • 访问路径:inode → 逻辑块号 → 数据块(读取内容)
  • 可寻址总容量:12×4KB=48KB

2. 一级间接指针(i_block[12]

  • 位置:第 13 个指针
  • 寻址规则:该指针不指向数据块 ,而是指向一个一级间接块;间接块内部连续存放 1024 个数据块编号。
  • 访问路径:inode → 一级间接块号 → 读取间接块 → 取出数据块号 → 数据块
  • 可寻址总容量:1024×4KB=4MB

3. 二级间接指针(i_block[13]

  • 位置:第 14 个指针
  • 寻址规则:两层间接跳转
    指针 → 二级间接块(存放一级间接块编号)→ 一级间接块(存放数据块编号)→ 数据块
  • 访问路径:两次间接块读取,跳转层级更深。
  • 可寻址总容量:1024×1024×4KB=4GB

4. 三级间接指针(i_block[14]

  • 位置:第 15 个指针
  • 寻址规则:三层间接跳转,是层级最多的寻址方式。
  • 可寻址总容量:1024×1024×1024×4KB≈4TB

系统会根据文件大小,按需启用不同层级的指针,不会强制使用全部 15 个指针

结论:

  • 分区之后的格式化操作,就是对分区进行分组,在每个分组中写入SB、GDT、Block Bitmap、Inode Bitmap等管理信息,这些管理信息统称:文件系统
  • 只要知道文件的inode号,就能在指定分区中确定是哪一个分组,进而在哪一个分组确定是哪一个inode

问题:知道一个文件的inode编号,如何找到这个文件的所有内容和属性?

答:

逻辑流程:

bash 复制代码
已知 inode 编号 → 定位 inode 表 → 读取 inode 结构体 → 直接获取【所有文件属性】
               ↓
               解析 15 级指针 → 遍历所有数据块 → 拼接得到【文件全部内容】

补充:创建一个文件的底层流程

bash 复制代码
用户命令 touch test.txt
    ↓
系统调用 open(O_CREAT)
    ↓
VFS路径解析 → 定位父目录 /home/user/
    ↓
选择块组 → 查找inode位图 → 分配空闲inode
    ↓
初始化inode:权限、时间、链接数=1、指针为空
    ↓
父目录数据块 → 新增目录项(test.txt → inode号)
    ↓
更新超级块、块组描述符、位图
    ↓
加载dentry缓存 + inode缓存
    ↓
返回文件描述符 → 文件创建成功

详细过程:

  • 分配空闲 inode :读取 inode 位图 (Bitmap),找到第一个为 0 的位,标记为 1(占用),记录分配到的 inode 编号 ,从 inode 表 中,取出对应的空闲 inode 结构体
  • 初始化 inode 元数据 :内核向新分配的 inode 写入所有文件属性(文件类型、权限、所有者 UID / 所属组 GID等等)
  • (空文件跳过)分配数据块 :如果是创建非空文件 (如 echo hello > test.txt):读取 块位图 ,找到空闲逻辑块,标记块位图为已占用,将块号写入 inode 的直接指针,写入数据到数据块。
  • 创建目录项(文件名 ↔ inode 绑定) :找到父目录的数据块 ,在父目录中新增一条目录项,将新目录项写入父目录的数据块(磁盘 / 缓存)
  • 更新全局元数据
    1.更新 块组描述符表(GDT) :本块组空闲 inode 数 -1;
    2.更新 超级块(Superblock) :分区总空闲 inode 数 -1;
    3.(如果分配了数据块)同步更新块相关统计。
  • 更新内核缓存 :创建内存 dentry:绑定文件名 + inode,将新 inode 加入 inode 缓存 ,将父目录、新文件加入 路径缓存(dcache)
  • 返回文件描述符,完成创建

目录与文件名

目录本质是一种特殊文件,和普通文件一样拥有 inode 和数据块

目录与普通文件的核心差异

对比维度 普通文件 目录(文件夹)
inode 类型标记 标记为「普通文件」 标记为「目录文件」
数据块内容 文本、程序、二进制业务数据 一条条 目录项(文件名 + inode 映射)
核心作用 存储用户数据 组织文件层级、管理文件名与 inode 的对应关系
权限语义 r/w/x 控制文件内容读写、执行 r/w/x 控制目录的浏览、增删、进入(语义完全不同)

目录项定义 :目录的数据块中,按照固定格式存储的一条条记录,就叫做目录项
目录项的作用:建立 文件名对应文件/子目录 inode 编号 的映射关系

用户通过文件名操作文件,系统底层永远通过 inode 识别文件,目录项就是二者的翻译器

文件名只存在于「父目录」的目录项中,绝对不会存放在 inode、文件自身的数据块里

路径解析

我们访问任何文件,都必须得有路径

所以,找到任何Linux文件,都必须从根目录开始,进行路径解析,直到找到相应文件

路径解析流程

以 绝对路径 /home/alice/note.txt 为例,演示系统如何从路径找到文件内容

  1. 起点:根目录 /:系统默认获取根目录 inode(Ext2 根 inode 固定为 2),读取根目录的数据块
  2. 遍历根目录目录项 :在目录项中匹配名称 home,拿到 home 目录的 inode 编号
  3. 进入 home 目录 :根据 inode 读取 home 目录的数据块,遍历内部目录项
  4. 匹配子目录 alice :找到 alice 目录项,获取其 inode 编号,读取对应目录数据块
  5. 匹配目标文件 note.txt :在 alice 的目录项中找到 note.txt,拿到该文件的 inode 编号
  6. 访问文件

问题:访问任何文件,都要从根目录开始进行路径解析吗?

答:原则上是,但是这样太慢,所以Linux会缓存历史路径结构。

问题:Linux目录的概念,是怎么产生的?

答:打开的文件是目录的话,由OS自己在内存中进行路径维护

路径缓存

频繁的路径逐层解析会消耗大量内核资源,因此Linux引入路径缓存 机制:OS在进行路径解析的时候,会把我们历史访问的所有的目录(路径),形成一棵多叉树,进行保存。再次访问相同路径时,直接从缓存读取inode,无需逐层遍历磁盘目录,大幅提升文件访问速度

Linux中,在内核中维护树状路径结构的内核结构体叫做: struct dentry

struct dentry(directory entry,目录项 )是 Linux 内核 VFS 层 定义的纯内存数据结构,专门用于在内存中表示文件名 / 目录名inode 的映射关系。

它是路径缓存(dentry cache) 的最小存储单元,也是路径解析的核心操作对象

内核源码:

c 复制代码
struct dentry {
	atomic_t d_count;
	unsigned int d_flags; /* protected by d_lock */
	spinlock_t d_lock; /* per dentry lock */
	struct inode *d_inode; /* Where the name belongs to - NULL is
					* negative */
	/*
	* The next three fields are touched by __d_lookup. Place them here
	* so they all fit in a cache line.
	*/
	struct hlist_node d_hash; /* lookup hash list */
	struct dentry *d_parent; /* parent directory */
	struct qstr d_name;
	struct list_head d_lru; /* LRU list */
	/*
	* d_child and d_rcu can share memory
	*/
	union {
		struct list_head d_child; /* child of parent list */
		struct rcu_head d_rcu;
	} d_u;
	struct list_head d_subdirs; /* our children */
	struct list_head d_alias; /* inode alias list */
	unsigned long d_time; /* used by d_revalidate */
	struct dentry_operations *d_op;
	struct super_block *d_sb; /* The root of the dentry tree */
	void *d_fsdata; /* fs-specific data */
#ifdef CONFIG_PROFILING
	struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
	int d_mounted;
	unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};

注意:

  • 每个文件其实都要有对应的dentry结构,包括普通文件。这样所有被打开的文件,就可以在内存中形成整个树形结构
  • 整个树形节点也同时会隶属于LRU(Least Recently Used,最近最少使用)结构中,进行节点淘汰
  • 整个树形节点也同时会隶属于Hash,方便快速查找
  • 更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何文件,都在先在这棵树下根据路径进行查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry结构,缓存新路径

分区挂载

磁盘分区格式化Ext2文件系统后,依然无法直接使用,必须经过挂载(mount)

挂载核心本质:将分区的文件系统,关联到Linux根文件系统的某个目录节点,让该目录成为分区的访问入口。

  • 系统所有文件、目录、设备都统一归属到 / 开始的唯一树形结构下,不支持多棵独立目录树并存。必须通过挂载,把分散的分区 "接入" 这棵大树。
  • 挂载后,访问挂载目录等价于访问对应磁盘分区的所有数据。
  • 卸载(umount)则是切断目录与分区的关联,目录恢复原有状态。

挂载点(Mount Point)

挂载点是全局目录树中一个已经存在的目录,有两条硬性规则:

  1. 目录必须提前创建,不能使用不存在的路径;
  2. 推荐使用空目录
  • 若目录非空,挂载后原有文件 / 目录会被临时隐藏(并非删除);
  • 卸载分区后,原目录内容会自动恢复。

模拟分区挂载:

  1. 制作一个大的磁盘块,当做一个分区
bash 复制代码
dd if=/dev/zero of=./disk.img bs=1M count=5
  1. 格式化写入文件系统
bash 复制代码
mkfs.ext4 disk.img
  1. 将分区挂载到指定目录
bash 复制代码
sudo mount -t ext4 ./disk.img ./dir
  1. 查看磁盘分区挂载
bash 复制代码
df -h
  1. 卸载分区
bash 复制代码
sudo umount ./dir

结论 :所以,可以根据访问目标文件的"路径前缀"准确判断我在哪一个分区。

文件系统总结

核心设计思想

  • 分区块组化:化整为零、分片自治,提升效率、降低碎片、隔离故障;
  • inode + 数据块分离:元数据与内容分开存储,统一寻址规则;
  • 树形目录 :Linux 全局唯一根目录树,无盘符,依靠挂载接入外部分区;
  • 缓存加速:路径缓存 (dentry) 替代重复磁盘 IO,用空间换性能。

完整知识闭环图

bash 复制代码
物理磁盘(扇区)
    ↓ 分区
独立分区(MBR/GPT)
    ↓ 格式化 → 生成Ext文件系统
分区 → 块组 → 超级块/位图/inode表/数据块
    ↓
inode(元数据+15级指针) ←→ 数据块(内容/目录项/间接块)
    ↓
磁盘目录项(文件名+inode)
    ↓ 加载到内存
struct dentry + 路径缓存(加速解析)
    ↓
路径解析(绝对/相对路径)
    ↓
文件增删改查、权限控制、软硬链接、挂载卸载


软硬链接

链接是Linux文件系统的特色机制,分为硬链接和软链接,二者底层原理、特性、用途完全不同,其本质依托于前文的inode与文件名映射关系

硬链接

硬链接本质是给同一个inode新增一个文件名,多个文件名共用同一个inode、同一套数据块,没有创建新文件,仅新增目录项记录

核心特性:

  1. 所有硬链接共享同一个 inode、权限、所有者、时间戳、数据块。修改任意一个链接的文件内容,所有链接同步变化
  2. 链接计数机制
  • 创建硬链接:i_links_count + 1
  • 删除一个硬链接(文件名):仅删除对应目录项,i_links_count - 1
  • 只有当 i_links_count == 0 时,内核才会将该 inode 和对应数据块标记为空闲,文件本体真正被删除。
  1. 不支持跨分区、跨文件系统(inode仅在当前分区唯一)
  2. 不支持目录硬链接(避免目录环路,造成文件系统混乱)

创建硬链接:

bash 复制代码
ln 源文件 硬链接名称

示例:

软链接

软链接又称符号链接,是独立的新文件 ,拥有自己的独立inode和数据块。其数据块中不存储真实文件数据,仅存储目标文件的路径

核心特性:

  • 软链接拥有独立inode号,与原文件是两个不同文件
  • 支持跨分区、跨文件系统、跨主机链接
  • 删除原文件,软链接失效,成为无效链接
  • 支持对目录创建软链接
  • 软链接的文件大小,就是其数据块中存放的路径字符字节数,和原文件大小无关

创建软链接:

bash 复制代码
ln -s 源文件/源目录 软链接名称

示例:

软硬链接对比

对比维度 硬链接(Hard Link) 软链接(Symbolic/Soft Link)
核心本质 同一 inode 对应多条目录项(纯别名) 独立特殊文件,数据块存储目标路径(快捷方式)
inode 归属 与源文件共用同一个 inode 拥有全新独立 inode
数据块 共用源文件数据块,不新增存储块 独立数据块,仅存放路径字符串
链接计数 依赖 inode 的 i_links_count(创建 + 1、删除 - 1) 无链接计数,与源文件计数相互独立
跨分区 / 跨挂载 完全不支持 支持(可跨磁盘、跨文件系统)
目录支持(普通用户) 禁止(会造成目录树环路) 允许,目录别名场景高频使用
文件大小 和源文件大小完全一致 等于路径字符串的字节长度
权限生效规则 共用源文件权限,修改同步生效 自身 rwx 权限基本无效,以目标文件权限为准
源文件删除后 链接数>0:链接正常可用;数 = 0 才回收文件本体 变为悬空 / 死链接,跳转失败,无法访问内容

软硬链接的用途

硬链接:

  • 防止重要文件被误删除
  • 同一文件多路径访问,避免重复复制
  • 文件备份

软链接:

  • 简化超长 / 深层路径(路径别名)
  • 跨分区 / 跨磁盘 / 外接设备访问
相关推荐
ITyunwei09871 小时前
主流 SaaS 工单系统对比
运维·服务器·人工智能
weixin_548444262 小时前
爆红处理APK 自动化编译流水线 v2026(英文名:APK AutoPipeline)
运维·自动化
枳实-叶2 小时前
【Linux驱动开发】第16天:按键中断完整实战
linux·运维·驱动开发
難釋懷3 小时前
Nginx-UrlRewrite
运维·nginx
qq_白羊座3 小时前
CI/CD 与 DevOps 四
运维·ci/cd·devops
杨云龙UP3 小时前
Oracle Recycle Bin 回收站详解:DROP TABLE 后还能找回吗?
linux·运维·数据库·sql·mysql·oracle
GISer_Jing3 小时前
AI数字营销全链路自动化闭环_CSDN
运维·人工智能·自动化
蠢货爱好者3 小时前
Docker基础操作
运维·docker·容器
Drache_long4 小时前
DevOps
运维·devops