3538 words
18 minutes
Linux 学习笔记 4 —— 磁盘与文件系统
首次发布: 2026-04-11
... 次访问

Linux 将硬件设备抽象为文件,磁盘也不例外。在 Linux 看来,硬盘、U盘、光驱都只是位于 /dev/ 目录下的一个文件(例如 /dev/sda)。这种设计使得操作系统可以使用统一的接口(读/写)来操作不同的硬件。

4.1 磁盘分区#

磁盘分区是将物理磁盘划分为多个独立区域的过程。Linux 内核通过分区表来记录这些边界。

4.1.1 分区表类型#

目前主要有两种分区表标准:

  • MBR(Master Boot Record)

    • 传统的分区表,位于磁盘的最开始处
    • 限制:最多支持 4 个主分区(或 3 个主分区 + 1 个扩展分区),最大寻址 2TB 磁盘
    • 结构:包含引导代码、分区表项(4 个 16 字节的条目)和魔数
  • GPT(GUID Partition Table)

    • 现代标准,作为 UEFI 的一部分
    • 优势:支持超过 2TB 的大磁盘,支持几乎无限数量的分区(通常限制为 128 个)
    • 具有 CRC 校验保证数据完整性

4.1.2 常用分区工具#

工具名称特点适用场景
fdisk交互式,功能强大,不立即写入直到确认创建、删除、修改分区表(推荐用于 MBR)
parted命令即时生效,支持脚本化操作需要脚本自动化分区,或处理 GPT 磁盘
gpartedparted 的图形化前端桌面环境下的可视化磁盘管理

4.1.3 分区操作实战#

使用 fdisk 修改磁盘 /dev/sdd 的典型流程:

  1. 启动交互:fdisk /dev/sdd
  2. 查看现状:输入 p 打印当前分区表
  3. 删除旧分区:输入 d,选择分区号
  4. 创建新分区:输入 n,选择分区类型,设定起始扇区和大小(如 +200M
  5. 写入磁盘:输入 w 保存并退出(在此之前所有操作仅在内存中)

4.1.4 物理几何与对齐#

  • CHS(Cylinder-Head-Sector):早期的磁盘寻址方式。现代磁盘使用 LBA(Logical Block Addressing),将扇区线性编号
  • SSD 对齐:对于固态硬盘,分区起始位置应与物理页或块对齐(通常工具默认对齐到 1MB 或 2048 扇区),否则会导致读写性能下降

4.2 文件系统基础#

文件系统是内核与用户空间之间的抽象层,它将线性的块设备转化为树状的目录和文件结构。

4.2.1 常见文件系统类型#

  • ext4:Linux 传统默认文件系统,稳定,支持大文件,向后兼容 ext2/3
  • Btrfs:现代写时复制文件系统,支持快照、压缩和动态卷管理
  • XFS:高性能日志文件系统,常用于大文件服务器(如 Red Hat 默认)
  • vfat/exfat:Windows FAT 系列的变种,常用于 U 盘和 SD 卡,兼容性好但无权限管理
  • iso9660:光盘标准文件系统

4.2.2 创建与挂载文件系统#

创建文件系统

mkfs 是一个前端工具,实际会调用具体的工具(如 mke2fs 用于 ext 系列):

mkfs -t ext4 /dev/sdf2

挂载文件系统

mount -t ext4 /dev/sdf2 /home/extra
umount /home/extra   # 卸载

4.2.3 文件系统 UUID#

设备名(如 /dev/sda1)可能因硬件变动而改变,因此推荐使用 UUID 来标识和挂载文件系统:

# 查看 UUID
blkid

# 通过 UUID 挂载
mount UUID=b600fe63-d2e9-461c-a5cd-d3b373a5e1d2 /home/extra

4.2.4 /etc/fstab 配置文件#

系统启动时自动挂载文件系统的配置表,每行 6 列:

UUID=... / ext4 errors=remount-ro 0 1
[设备标识] [挂载点] [文件系统类型] [选项] [dump备份] [fsck检查顺序]
  • dump 字段:通常设为 0(已废弃)
  • fsck 字段:0 = 不检查;1 = 根分区(最先检查);2 = 其他分区

4.2.5 文件系统检查与修复#

当系统非正常关机时,文件系统元数据可能不一致,需要在下次挂载前修复:

# 交互式检查
fsck /dev/sdb1

# 自动修复
fsck -p /dev/sdb1

4.3 交换空间#

当物理内存耗尽时,Linux 使用磁盘上的交换空间来存储不活跃的内存页。

4.3.1 交换空间类型#

  • 交换分区:专用的磁盘分区(类型 ID 通常为 82),性能略好,无需文件系统开销
  • 交换文件:文件系统中的一个普通文件,灵活性高,无需重新分区即可调整大小

4.3.2 管理命令#

# 初始化分区
mkswap /dev/sda5

# 初始化文件
dd if=/dev/zero of=/swapfile bs=1M count=100
mkswap /swapfile

# 启用/禁用
swapon /dev/sda5
swapoff /dev/sda5

# 查看状态
free -h
swapon --show

4.3.3 Swap 使用策略#

  • 传统规则:Swap 大小 = 2 倍物理内存(适用于内存很小的旧时代)
  • 现代建议
    • 桌面/休眠:需要至少等于物理内存大小的 Swap,以支持休眠功能
    • 服务器:内存较大(>16GB)时,仅需少量 Swap(2GB-4GB)用于应急
    • 可设置 vm.swappiness=1,告诉内核尽量避免使用 Swap,防止性能抖动

4.4 文件系统内部机制#

4.4.1 Inode 结构#

  • Inode(索引节点):存储文件的元数据(权限、所有者、时间戳、指向数据块的指针),但不包含文件名
  • 文件名:存储在目录文件的条目中,目录文件本质上是一个将文件名映射到 Inode 号的列表

4.4.2 硬链接#

  • 定义:多个文件名指向同一个 Inode
  • 特点:删除其中一个链接,Inode 的链接计数减 1,只有当计数为 0 时,数据块才会被真正释放
  • 限制:硬链接不能跨文件系统,也不能链接目录(防止循环引用)

4.4.3 块位图#

文件系统使用位图来追踪数据块的使用状态:

  • 0:块空闲
  • 1:块已占用

fsck 在检查文件系统时,会重新生成位图并与 Inode 中记录的使用情况进行比对。

4.5 文件系统日志机制#

为什么现代文件系统(ext3/4、XFS、Btrfs)在断电后重启极快,而古老的 ext2 需要漫长的 fsck 检查?答案在于日志。

4.5.1 文件系统不一致的原因#

当写入一个文件时,涉及多个步骤:

  1. 更新 Inode(元数据)
  2. 更新位图(标记块已占用)
  3. 写入实际数据块

如果在这些步骤中间断电,元数据与实际数据就会不一致。

4.5.2 日志的工作流程#

日志文件系统引入”预写日志”的概念:

  1. 提交事务:在修改实际文件系统结构之前,先将”意图”写入日志区
  2. 检查点:一旦日志写入成功,系统就认为事务已提交
  3. 执行:按日志中的记录去修改实际的 Inode 和位图
  4. 清除:修改完成后,从日志中清除该记录

系统崩溃重启时,文件系统驱动只需读取日志区:

  • 如果有未完成的记录,直接重做
  • 如果记录已完成但标记未清除,忽略即可

4.5.3 日志模式(针对 ext4)#

  • Journal(数据日志):元数据和文件数据都记日志,最安全但速度最慢
  • Ordered(有序模式,默认):只记元数据日志,但保证数据块先写入磁盘再提交元数据日志,兼顾安全与性能
  • Writeback(回写模式):只记元数据日志,速度最快但断电后可能出现数据不一致

4.6 逻辑卷管理#

LVM 在物理磁盘和文件系统之间增加了一层抽象,解决了传统分区”一旦分配难以调整”的痛点。

4.6.1 核心概念#

LVM 的结构类似于”存储池”:

  • PV(Physical Volume):物理卷,通常是磁盘分区(类型 8e)或整块磁盘
  • VG(Volume Group):卷组,由多个 PV 组成的大池子
  • LV(Logical Volume):逻辑卷,从 VG 池子中切分出来的空间,相当于”虚拟分区”

4.6.2 LVM 实战流程#

1. 准备物理分区

使用 fdiskparted 将磁盘分区,并将分区类型设为 Linux LVM(8e)。

2. 创建 PV 和 VG

pvcreate /dev/sdb1 /dev/sdc1
vgcreate myvg /dev/sdb1 /dev/sdc1

3. 创建 LV

# 从卷组 myvg 中创建一个 10GB 的逻辑卷
lvcreate --size 10g --name mylv1 myvg
# 设备路径:/dev/myvg/mylv1 或 /dev/mapper/myvg-mylv1

4. 使用 LV

mkfs.ext4 /dev/myvg/mylv1
mount /dev/myvg/mylv1 /mnt/data

4.6.3 动态调整#

LVM 的最大优势是可以在不卸载的情况下调整大小(仅限支持在线调整的文件系统):

# 扩展逻辑卷并自动调整文件系统
lvextend -r --size +100%FREE /dev/myvg/mylv1

4.7 设备映射器#

LVM 的底层依赖于内核的设备映射器驱动。它位于物理块设备和逻辑块设备之间。

4.7.1 核心架构#

  • dm-mod 内核模块:DM 的核心驱动
  • dmsetup 工具:用户空间命令行工具,用于直接与内核的 DM 驱动交互
  • 目标类型
    • linear:LVM 默认模式,将多个物理区域拼接成线性逻辑区域
    • mirror:提供 RAID 1 镜像功能
    • snapshot:提供快照功能(写时复制)
    • crypt:提供透明加密(LUKS 的基础)

4.7.2 工作原理#

  1. 用户空间的 LVM 工具计算好映射关系
  2. 通过 ioctl 系统调用将映射表写入内核的 /dev/mapper/control 设备
  3. 内核空间的 Device Mapper 根据映射表,将对逻辑卷的读写请求翻译为对物理卷上具体位置的读写请求

4.7.3 多路径技术#

在企业级存储环境中,服务器到存储设备通常有多条物理连接:

  • 问题:操作系统会看到同一个 LUN 通过不同路径出现多次
  • 解决方案:使用 device-mapper-multipath 将多个路径聚合成一个虚拟设备
  • 功能:故障切换(一条路径断,IO 自动切换)和负载均衡(IO 在多条路径间轮询分发)
# 查看多路径状态
multipath -ll

4.8 虚拟文件系统与挂载机制#

如果说文件系统是数据的存储格式,那么虚拟文件系统就是内核用来统一访问这些数据的”万能翻译官”。

4.8.1 VFS 的抽象层作用#

Linux 支持几十种文件系统,应用程序不需要知道底层具体是哪种格式:

  • 工作原理:VFS 定义了一组通用的接口,具体的文件系统驱动负责实现这些接口
  • 流程用户程序系统调用VFS具体文件系统驱动块设备驱动

4.8.2 挂载的本质#

挂载是将一个文件系统及其目录树附加到现有 VFS 树中某个目录的过程:

  • 挂载点:被附加的目录,一旦挂载,该目录原本的内容会被”隐藏”,直到卸载
  • 绑定挂载:允许将同一个文件系统或目录挂载到不同的位置
    mount --bind /source/dir /target/dir

4.8.3 挂载命名空间#

在现代 Linux 中,挂载不是全局唯一的:

  • 不同的进程可以看到不同的挂载点列表
  • 这是 Docker/容器技术的基础——容器内部看到的挂载点可能与宿主机完全不同,互不干扰

4.9 磁盘配额#

当多个用户共享同一个文件系统时,管理员需要限制每个用户能使用的磁盘空间。

4.9.1 配额类型#

  • 块限制:限制用户能使用的磁盘空间总量
  • Inode 限制:限制用户能创建的文件总数(防止耗尽 Inode)

4.9.2 软限制与硬限制#

  • 软限制:警告线,超过后系统会发出警告,但允许在宽限期内继续写入
  • 硬限制:绝对红线,一旦达到立即禁止写入

4.9.3 管理工具#

  • edquota:编辑用户配额
  • repquota:报告配额使用情况
  • quotaon / quotaoff:开启或关闭配额功能

4.10 磁盘 I/O 调度器#

当多个进程同时请求读写磁盘时,内核通过 I/O 调度器决定处理顺序。

4.10.1 调度器的作用#

  • 合并请求:将相邻扇区的读写请求合并,减少磁头移动
  • 排序:根据算法决定请求顺序
  • 公平性:防止某个进程独占磁盘带宽

4.10.2 常见调度算法#

调度器名称特点适用场景
mq-deadline保证请求在截止时间前完成,注重低延迟适合数据库等对延迟敏感的应用
bfq基于预算的公平队列,保证每个进程获得公平带宽适合桌面环境,防止界面卡顿
kyber针对多队列设备优化,简单高效适合高性能 SSD
none不进行调度,直接下发给硬件适合自带复杂控制器的现代 NVMe SSD

4.10.3 查看与修改#

# 查看当前调度器
cat /sys/block/sda/queue/scheduler

# 临时修改
echo kyber > /sys/block/sda/queue/scheduler

4.11 实战演练:综合故障排查#

4.11.1 场景:磁盘空间”假性”不足#

用户报告无法写入文件,提示”设备无空间”,但 df -h 显示还有剩余空间。

排查步骤:

  1. 检查块空间:

    df -h
    # Use% 未达 100%,说明块空间未满
  2. 检查 Inode 空间:

    df -i
    # IUse% 显示 100%,说明 Inode 耗尽
  3. 定位问题文件:

    # 统计各目录下的文件数
    find /var -xdev -type f | cut -d "/" -f 3 | sort | uniq -c | sort -nr | head
  4. 清理不必要的小文件(如旧的缓存、会话文件)

4.11.2 场景:恢复误删但仍被进程占用的文件#

如果文件被删除但进程仍持有句柄,空间不会立即释放:

  1. 查找被删除但仍被占用的文件:

    lsof | grep deleted
  2. 恢复方法(不要重启进程):

    cp /proc/<PID>/fd/<FD> /tmp/recovered_file
Linux 学习笔记 4 —— 磁盘与文件系统
https://adalovelemon.github.io/blog/en/posts/content/technotes/linux/linux4/
Author
Ada Lovelemon
Published at
2026-04-11

Comments Section