Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 系统与高性能 / Systems & Performance

操作系统 / Operating Systems

1. OS 底层知识学习路线 / A Learning Path for Operating System Internals

2. 存储硬件基础 — 磁盘到底怎么存数据 / Storage Hardware Fundamentals: How Disks Store Data

3. BIOS vs UEFI — 固件的本质 / BIOS and UEFI: Understanding Firmware

4. 磁盘分区表 — GPT 与 MBR / Disk Partition Tables: GPT and MBR

5. 文件系统核心概念 — inode、journal、COW / Filesystem Concepts: Inodes, Journaling, and Copy-on-Write

6. 常见文件系统格式详解 — FAT 到 ZFS 的进化史 / Filesystem Formats from FAT to ZFS

7. Linux 启动全流程 — 从通电到登录提示符 / The Linux Boot Process from Power-On to Login

8. Windows 启动全流程 — 与 Linux 的对比视角 / The Windows Boot Process in Comparison with Linux

9. Linux 文件系统层次结构 (FHS) — 目录树的哲学 / The Linux Filesystem Hierarchy Standard

10. Linux 挂载机制 — mount、VFS 与 fstab / Linux Mounting with Mount, VFS, and Fstab

11. Linux 磁盘管理实战 — 从分区到挂载全流程 / Practical Linux Disk Management from Partitioning to Mounting

12. Windows 磁盘与文件系统 — 盘符帝国的秩序 / Windows Disks and Filesystems

13. ext4 深入 — 从超级块到 Extent Tree / Ext4 in Depth from Superblocks to Extent Trees

14. btrfs 深入 — B-tree 是万能的 / Btrfs in Depth and Its B-Tree Architecture

15. 双系统 — EFI 分区共存与 GRUB chainload / Dual Boot with Shared EFI Partitions and GRUB Chainloading

本页目录

Linux 挂载机制 — mount、VFS 与 fstab / Linux Mounting with Mount, VFS, and Fstab ​

📅 创建时间:2026-06-17 🏷️ 标签:#Linux #mount #VFS #fstab #挂载 📚 前置知识:[[04-filesystem-concepts]], [[08-linux-fhs]]


📋 本章目标 ​

  • 理解 mount 系统调用的本质——把块设备"插"到目录树上
  • 掌握 VFS(Virtual File System)——Linux 如何用统一的接口支持几十种文件系统
  • 理解 /etc/fstab 每一列的含义和常见错误
  • 理解 UUID 为什么替代 /dev/sda1——设备名不是稳定的
  • 掌握 bind mount、tmpfs、挂载选项的实战用法
  • 理解 mount umount findmnt lsblk 之间的关系

第1部分:mount 本质——把设备插到树上 ​

1.1 mount 做什么 ​

┌─────────────────────────────────────────────────────────────┐
│              mount 操作的直观理解                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  初始的根文件系统 (initramfs 或 光盘启动后):                  │
│                                                             │
│        /                                                    │
│        ├── bin/                                             │
│        ├── etc/                                             │
│        └── mnt/          ← 空目录, 等待用作"挂钩点"           │
│                                                             │
│  执行 mount /dev/nvme0n1p3 /mnt:                            │
│                                                             │
│        /                                                    │
│        ├── bin/                                             │
│        ├── etc/                                             │
│        └── mnt/          ← 挂载点 (mount point)              │
│            ├── boot/      ← 来自 nvme0n1p3 的 boot 目录      │
│            ├── home/      ← 来自 nvme0n1p3 的 home 目录      │
│            ├── etc/       ← 来自 nvme0n1p3 的 etc 目录       │
│            └── ...                                          │
│                                                             │
│  关键: nvme0n1p3 上的文件系统被"嫁接"到了 /mnt 位置           │
│        原有的 /mnt 下如果有什么内容, 会被暂时"遮盖"            │
│        umount 后又能看到原来的内容                            │
│                                                             │
│  这就是 Arch 安装时的操作:                                   │
│  mount /dev/nvme0n1p3 /mnt        ← 挂载根分区               │
│  mount /dev/nvme0n1p1 /mnt/boot   ← 挂载 ESP 到 /boot        │
│                                                             │
│  第二个 mount 在已挂载的树里再加一层:                         │
│        /mnt/                                                │
│        └── boot/  ← 现在指向 nvme0n1p1 (ESP, FAT32)          │
│             ├── vmlinuz-linux                               │
│             ├── initramfs-linux.img                         │
│             └── EFI/                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

1.2 挂载前必须做的事 ​

┌─────────────────────────────────────────────────────────────┐
│              Arch 安装时的 mount 序列                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  # 1. 挂载根分区                                            │
│  mount /dev/nvme0n1p3 /mnt                                  │
│                                                             │
│  # 2. 创建挂载点 (必须在已有树内)                             │
│  mkdir -p /mnt/boot                                         │
│  mkdir -p /mnt/home                                         │
│                                                             │
│  # 3. 挂载其他分区                                          │
│  mount /dev/nvme0n1p1 /mnt/boot                             │
│                                                             │
│  # 4. (如果是 btrfs) 挂载 subvolume                         │
│  mount -o subvol=@home /dev/nvme0n1p3 /mnt/home             │
│                                                             │
│  顺序很重要: 必须先挂 /, 才能在 / 的子目录上挂别的东西          │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

第2部分:VFS — Linux 的文件系统抽象层 ​

2.1 VFS 是什么 ​

┌─────────────────────────────────────────────────────────────┐
│              VFS (Virtual File System) — 统一的翻译层         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  问题: Linux 要支持 ext4, btrfs, FAT32, NTFS, XFS, NFS...  │
│        几十种文件系统, 每种内部实现完全不同                     │
│        但应用程序不应该关心底层是什么文件系统                    │
│                                                             │
│  解法: VFS 层                                               │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  应用程序 (cat, ls, cp, mv...)                      │   │
│  │       ↓ 系统调用 (open, read, write, stat...)       │   │
│  │  ┌─────────────────────────────────────────────┐   │   │
│  │  │              VFS 层                          │   │   │
│  │  │                                             │   │   │
│  │  │  统一的: inode, dentry, file, super_block   │   │   │
│  │  │  (在内存中的通用数据结构)                      │   │   │
│  │  │                                             │   │   │
│  │  │  每个文件系统注册自己的函数指针表:             │   │   │
│  │  │    → .read_inode, .write_inode, .create... │   │   │
│  │  └──────────┬──────────────────────────────────┘   │   │
│  │             │ 根据 super_block → 分发到具体驱动      │   │
│  │     ┌───────┼───────┬──────────┬──────────┐        │   │
│  │     ↓       ↓       ↓          ↓          ↓        │   │
│  │   ext4   btrfs   FAT32     NTFS       NFS         │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  关键概念:                                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  super_block  → 对应一个"挂载了的文件系统"             │   │
│  │                  从磁盘超级块读取, 存块大小、inode 总数│   │
│  │                                                     │   │
│  │  inode        → 对应一个"文件"或"目录"               │   │
│  │                  VFS 维护的是 VFS inode (内存)         │   │
│  │                  文件系统驱动负责: 磁盘 inode ↔ VFS inode│   │
│  │                                                     │   │
│  │  dentry       → 对应一个"目录项"                     │   │
│  │                  存文件名 → VFS inode 的映射           │   │
│  │                  VFS 维护 dentry cache (快速路径查找)  │   │
│  │                                                     │   │
│  │  file         → 对应一个"打开的文件"                 │   │
│  │                  存偏移量、访问模式                   │   │
│  │                  多个 file 可以指向同一个 inode       │   │
│  │                  (多个进程打开同一个文件)             │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

第3部分:/etc/fstab — 开机自动挂载 ​

3.1 fstab 的六列 ​

┌─────────────────────────────────────────────────────────────┐
│              /etc/fstab 六列详解                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  # <文件系统>  <挂载点>  <类型>  <选项>     <dump> <pass>   │
│                                                             │
│  例:                                                        │
│  UUID=xxx-xxx  /        btrfs  defaults,compress=zstd  0  0 │
│  UUID=yyy-yyy  /boot    vfat   defaults,noatime        0  2 │
│  UUID=zzz-zzz  /home    btrfs  defaults,subvol=@home   0  0 │
│                                                             │
│  第1列: 文件系统 (Filesystem)                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 三种写法:                                            │   │
│  │                                                     │   │
│  │ UUID=xxx-xxx-xxx       ← 推荐! 稳定, 不随插槽改变     │   │
│  │ PARTUUID=xxx-xxx       ← GPT 分区自身的 UUID          │   │
│  │ /dev/nvme0n1p3         ← 不推荐! 内核设备名可能变化    │   │
│  │ LABEL=mylabel          ← 可读, 但不如 UUID 唯一        │   │
│  │                                                     │   │
│  │ 查看 UUID:                                           │   │
│  │ blkid /dev/nvme0n1p3                                │   │
│  │ ls -la /dev/disk/by-uuid/                           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  第2列: 挂载点 (Mount Point)                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 必须是已存在的目录                                   │   │
│  │ swap 分区用 "none" 或 "swap"                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  第3列: 文件系统类型 (Type)                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ext4, btrfs, vfat, ntfs3, xfs, swap, tmpfs, ...    │   │
│  │ auto: 让内核自动检测                                 │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  第4列: 挂载选项 (Options)                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ defaults = rw,suid,dev,exec,auto,nouser,async      │   │
│  │                                                     │   │
│  │ 常用选项:                                            │   │
│  │ noatime   不更新访问时间 → 减少 SSD 写入              │   │
│  │ compress=zstd  btrfs 透明压缩                        │   │
│  │ subvol=@   btrfs 子卷选择                           │   │
│  │ discard=async  SSD TRIM (4.19+ 建议用 async)        │   │
│  │ nofail    设备不存在也不阻止启动                      │   │
│  │ _netdev   网络设备, 等网络就绪后再挂载                 │   │
│  │ ro        只读挂载                                   │   │
│  │ noexec    禁止执行此文件系统上的程序                   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  第5列: dump (备份)                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 0 = 不备份  (常用)                                   │   │
│  │ 1 = 备份     (dump 命令使用, 基本没人用了)            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  第6列: fsck 检查顺序 (pass)                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 0 = 不检查                                          │   │
│  │ 1 = 最先检查 (只能给 / 根文件系统)                    │   │
│  │ 2 = 其余依次检查 (可并行)                            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

3.2 为什么用 UUID 而不是 /dev/sda1 ​

┌─────────────────────────────────────────────────────────────┐
│              设备名不稳定的经典案例                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  场景:                                                      │
│  你的 fstab 里写着:                                         │
│  /dev/sda1  /boot  vfat  defaults  0  2                    │
│                                                             │
│  某天你插了一块 U 盘 → 内核把它分配为 /dev/sda               │
│  → 原 /dev/sda 变成了 /dev/sdb                             │
│  → fstab 里的 /dev/sda1 现在指向了 U 盘!                   │
│  → 启动失败 (找不到 /boot)                                 │
│                                                             │
│  用 UUID:                                                   │
│  UUID=ABCD-1234  /boot  vfat  defaults  0  2               │
│  → 不管设备名怎么变, UUID 不变                              │
│  → 总是能正确挂载                                          │
│                                                             │
│  查看 UUID:                                                 │
│  $ blkid                                                    │
│  /dev/nvme0n1p1: UUID="ABCD-1234" TYPE="vfat"              │
│                                                             │
│  内核在 /dev/disk/by-uuid/ 下创建了快捷方式:                  │
│  $ ls -la /dev/disk/by-uuid/                               │
│  ABCD-1234 -> ../../nvme0n1p1                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

第4部分:特殊挂载类型 ​

4.1 bind mount — 把目录挂到另一个位置 ​

┌─────────────────────────────────────────────────────────────┐
│              bind mount 的应用                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  bind mount = 把目录树的某个节点"镜像"到另一个位置             │
│                                                             │
│  # 让 /mnt 也能访问 /home                                    │
│  mount --bind /home /mnt/home-ext                           │
│                                                             │
│  # 实际上: /home 和 /mnt/home-ext 是同一个 inode 树          │
│  # 修改任何一个都影响同一个数据                               │
│                                                             │
│  关键区别: bind mount vs 符号链接                            │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │ 符号链接: ls -la /link → /target → 是一个路径快捷方式 │   │
│  │ bind mount:  文件系统级别的镜像, 和原始位置完全等价    │   │
│  │                                                     │   │
│  │ 符号链接的问题:                                       │   │
│  │  chroot 环境里 /link 指到 /target → 但 /target 不存在!│   │
│  │  bind mount 不受 chroot 影响 (因为是独立挂载)         │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Arch 安装时的重要用途:                                     │
│  # mount --bind /dev  /mnt/dev        ← 设备节点           │
│  # mount --bind /proc /mnt/proc       ← 进程信息            │
│  # mount --bind /sys  /mnt/sys        ← 内核接口             │
│                                                             │
│  然后 arch-chroot /mnt → chroot 后的环境有完整的 /dev/proc/sys│
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

4.2 tmpfs — 内存里的文件系统 ​

┌─────────────────────────────────────────────────────────────┐
│              tmpfs — 重启就消失的文件系统                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  tmpfs 把数据存在 RAM + swap 里, 而不是磁盘上.                │
│                                                             │
│  mount -t tmpfs tmpfs /tmp -o size=4G                       │
│                                                             │
│  系统默认的 tmpfs 挂载 (/proc/mounts 可见):                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ tmpfs on /dev/shm    共享内存                        │   │
│  │ tmpfs on /run        运行时数据 (PID/锁/套接字)        │   │
│  │ tmpfs on /tmp        临时文件 (如果配置了的话)         │   │
│  │ tmpfs on /sys/fs/cgroup  cgroup 控制组接口           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  tmpfs 的关键属性:                                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • 大小可伸缩 — 实际使用多少才占多少内存                │   │
│  │ • 重启消失 — 适合不需要持久化的临时数据               │   │
│  │ • 极快 — 没有磁盘 IO                                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  与之对比: ramfs — 只能用物理 RAM, 不能 swap                 │
│           tmpfs → 可以用 swap → 更灵活                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

第5部分:挂载选项实战 ​

5.1 btrfs 特有的挂载选项 ​

bash
# 你 Arch 上实际使用的挂载选项:
# /etc/fstab 里的典型 btrfs 根分区:
UUID=xxx / btrfs rw,noatime,compress=zstd,ssd,discard=async,subvol=@ 0 0

# 各选项含义:
# rw              → 读写模式
# noatime         → 不更新访问时间 (减少 SSD 写)  → 省 IO
# compress=zstd   → zstd 压缩 (btrfs 特有)       → 省空间
# ssd             → SSD 优化 (btrfs 自动检测, 但可手动指定)
# discard=async   → 异步 TRIM (btrfs 特有)       → 省 IO
# subvol=@        → 挂载名为 @ 的子卷             → btrfs 特有
1
2
3
4
5
6
7
8
9
10
11

5.2 常用通用挂载选项 ​

┌─────────────────────────────────────────────────────────────┐
│              常用挂载选项速查                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  async/sync     异步/同步写入 (sync 极慢, 一般不用)          │
│  atime/noatime  更新/不更新访问时间 (SSD 建议 noatime)        │
│  relatime       只在 mtime/ctime 更新时更新 atime (折中)     │
│  exec/noexec    允许/禁止执行可执行文件                       │
│  suid/nosuid    允许/禁止 SUID 位生效                        │
│  dev/nodev      允许/禁止设备节点                            │
│  rw/ro          读写/只读                                   │
│  user/nouser    允许/禁止普通用户挂载                         │
│  auto/noauto    启动时自动挂载/不自动挂载                    │
│  nofail         设备不存在不报错 (关键选项, 见下文)            │
│                                                             │
│  nofail 的使用场景:                                         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 你有一块外部硬盘, 有时插着有时不插                     │   │
│  │ 如果 fstab 里有它, 启动时会因为找不到设备而进 emergency│   │
│  │ 加了 nofail → 找不到就跳过 → 正常启动                │   │
│  │ 这对可移动设备和网络挂载 (NFS) 尤其重要               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

核心总结 ​

总结1:mount 的本质 ​

mount <设备> <挂载点> = 把<设备>上的文件系统"嫁接"到<挂载点>
umount <挂载点>       = 切断这个嫁接, 恢复挂载点原来的内容
1
2

总结2:VFS 的价值 ​

应用不需要知道文件系统类型 → VFS 提供统一接口
所有文件系统驱动都实现同一套函数指针 → 一个 open() 系统调用就够了
1
2

总结3:fstab 核心要素 ​

6 列: 设备(UUID) → 挂载点 → 类型 → 选项 → dump → fsck序
UUID 替代 /dev/sda1 → 设备名变也不怕
nofail → 可选设备不要阻止启动
1
2
3

章节测试 ​

测试1:mount 遮盖 ​

如果你 /mnt 下有一个文件 hello.txt,然后 mount /dev/sdb1 /mnt。hello.txt 还在吗?umount /mnt 之后呢?

测试2:VFS ​

VFS 层解决的核心问题是什么?

测试3:UUID 必要性 ​

为什么 fstab 用 UUID 而不用 /dev/nvme0n1p3?

测试4:fstab 格式 ​

UUID=xxx /home btrfs defaults,subvol=@home,nofail 0 0 中 nofail 的作用是什么?


参考答案 ​

测试1答案 ​

mount /dev/sdb1 /mnt 后,原来的 hello.txt 被"遮盖"了——它物理上还在磁盘上,但因为挂载点现在指向了 sdb1,访问 /mnt/hello.txt 会去 sdb1 上找。umount /mnt 后,原来的内容重见天日——hello.txt 完好无损。这就是 mount 的"遮盖"特性。

测试2答案 ​

VFS 解决了文件系统类型多样性和应用程序通用性之间的矛盾。Linux 支持几十种文件系统,但每个应用程序不可能针对每种文件系统写不同的代码。VFS 层定义了一套统一的抽象(super_block, inode, dentry, file)和操作接口(函数指针表),每个文件系统驱动只需实现这些接口,上层所有应用自动支持该文件系统。

测试3答案 ​

因为内核设备名(如 /dev/nvme0n1p3)不是稳定的。添加/移除磁盘、改变 SATA 端口、甚至只是内核探测顺序的变化,都可能导致设备名改变。UUID 存储在文件系统的超级块里,除非重新格式化,否则永远不会变。所以用 UUID 保证 fstab 在所有条件下都能正确挂载。

测试4答案 ​

nofail 告诉 systemd:如果这个设备不存在(比如外部硬盘没插),不要报错,不要进入 emergency 模式,直接跳过,继续正常启动。没有 nofail 的设备缺失会导致启动失败。


相关笔记 ​

  • [[08-linux-fhs]] - fstab 挂载的目标——目录树
  • [[10-linux-disk-practice]] - 从分区到 fstab 编辑的完整流程
  • [[04-filesystem-concepts]] - VFS 抽象了什么——inode/超级块/dentry

下一步学习 ​

  • [ ] 阅读 10 - Linux 磁盘管理实战

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇9. Linux 文件系统层次结构 (FHS) — 目录树的哲学 / The Linux Filesystem Hierarchy Standard
下一篇11. Linux 磁盘管理实战 — 从分区到挂载全流程 / Practical Linux Disk Management from Partitioning to Mounting

持续记录,持续成长

Copyright © Tidenflow