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

本页目录

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

📅 创建时间:2026-06-17 🏷️ 标签:#文件系统 #inode #Journal #COW #超级块 📚 前置知识:[[03-partition-table]]


📋 本章目标 ​

  • 理解文件系统的核心职责——从"文件名"到"磁盘块"
  • 掌握 inode 的概念——为什么文件名和数据是分开存储的
  • 理解目录的本质——一张"文件名→inode号"的映射表
  • 掌握超级块——文件系统的元数据之锚
  • 理解 Journal 日志——为什么突然断电不会损坏文件系统
  • 理解 COW 写时复制——btrfs/ZFS 的核心设计哲学
  • 理解硬链接 vs 符号链接的 inode 视角区别
  • 理解 UGO/rwx 权限的存储方式

第1部分:文件系统到底做什么? ​

1.1 一个看似简单的操作背后 ​

当你执行:

bash
cat /home/Jaten/hello.txt
1

发生了一系列事情:

┌─────────────────────────────────────────────────────────────┐
│              cat hello.txt 的完整路径                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 找到 `/` 的 inode                                       │
│     └→ 根目录的 inode 号是固定的 (ext4 上是 2)              │
│                                                             │
│  2. 在 `/` 的目录项中查找 `home`                            │
│     └→ 目录本质上是一张表: {文件名 → inode号}              │
│                                                             │
│  3. 找到 `home` 的 inode 号                                 │
│     └→ 读取 inode → 知道"这是一个目录" + "它的数据在哪些块" │
│                                                             │
│  4. 在 `home` 的目录项中查找 `Jaten`                        │
│     └→ 同上,逐级索引                                       │
│                                                             │
│  5. 在 `Jaten` 的目录项中查找 `hello.txt`                   │
│     └→ 找到 inode 号                                       │
│                                                             │
│  6. 读取 `hello.txt` 的 inode                               │
│     └→ 知道: 文件大小、权限、数据块位置                      │
│                                                             │
│  7. 从数据块读取文件内容                                     │
│     └→ inode 里存储了数据块的地址,据此去读磁盘              │
│                                                             │
│  关键认知:                                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ "文件名" 不在 inode 里!                             │   │
│  │ 文件名存在目录的数据块中                             │   │
│  │ inode 只存元数据(大小/权限/数据位置),不存名字      │   │
│  │ 这就是为什么 rename/mv 只在目录里改一行,极快         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第2部分:inode — 文件的"身份证" ​

2.1 inode 里存了什么 ​

┌─────────────────────────────────────────────────────────────┐
│              ext4 inode 结构(简化)                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  inode 编号: 42                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 文件类型:     普通文件 (-)                           │   │
│  │ 权限:         rw-r--r-- (0644)                      │   │
│  │ 所有者:       uid=1000 (Jaten)                      │   │
│  │ 所属组:       gid=1000 (Jaten)                      │   │
│  │ 文件大小:     1234 字节                             │   │
│  │ 时间戳:                                              │   │
│  │   atime: 最后访问时间                               │   │
│  │   mtime: 最后修改时间                               │   │
│  │   ctime: 最后元数据变更时间                           │   │
│  │ 链接计数:     1  (指向这个 inode 的目录项数量)       │   │
│  │ 数据块指针:                                          │   │
│  │   12 个直接指针 → 指向前 12 个数据块                │   │
│  │   1 个间接指针 → 指向一个"存满指针"的块              │   │
│  │   1 个二级间接 → 两重指针                            │   │
│  │   1 个三级间接 → 三重指针                            │   │
│  │ ext4 额外: extent tree 根 (取代间接指针)              │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  注意 inode 里没有的东西:                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ ❌ 文件名 — 存在目录项里                             │   │
│  │ ❌ 文件内容 — 存在数据块里,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

2.2 目录的本质 ​

┌─────────────────────────────────────────────────────────────┐
│              目录的数据块内容(概念图)                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  /home/ 目录的数据块(简化):                                │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ inode号   |  条目长度  |  类型  |  名称              │   │
│  │ ──────────┼───────────┼───────┼────────────────── │   │
│  │ 2         |  12       |  DIR  |  .                 │   │
│  │ 16777217  |  12       |  DIR  |  ..                │   │
│  │ 16809985  |  24       |  DIR  |  Jaten             │   │
│  │ 16809986  |  20       |  DIR  |  root              │   │
│  │ 16809987  |  28       |  REG  |  hello.txt         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  .  = 指向当前目录自己(inode 2 是 / 的 inode)              │
│  .. = 指向父目录 (inode 16777217)                          │
│                                                             │
│  mv 操作的本质:                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 1. 在目标目录加一行 "hello.txt → inode 16809987"      │   │
│  │ 2. 从源目录删掉那一行                                │   │
│  │                                                     │   │
│  │ inode 完全没动。数据块完全没动。                     │   │
│  │ 这就是为什么 mv 一个 10GB 的文件在一瞬间完成          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

2.3 硬链接和符号链接 — inode 视角 ​

┌─────────────────────────────────────────────────────────────┐
│              硬链接 vs 符号链接                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  硬链接 (Hard Link):                                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  目录 /a/:  "file" → inode 42    ← 原始目录项        │   │
│  │  目录 /b/:  "link" → inode 42    ← 硬链接!          │   │
│  │                                                     │   │
│  │  inode 42:                                          │   │
│  │    链接计数 = 2                                     │   │
│  │    数据块指针 → [真正的文件数据]                       │   │
│  │                                                     │   │
│  │  "file" 和 "link" 是平等的,都是这个 inode 的入口       │   │
│  │  删除 "file" → 链接计数减为 1 → 数据还在             │   │
│  │  删除 "link"  → 链接计数减为 0 → inode 和数据被回收 │   │
│  │                                                     │   │
│  │  限制: 硬链接不能跨文件系统 (inode 号只在同一个 FS 内) │   │
│  │        目录通常不允许硬链接 (防止循环)               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  符号链接 (Symbolic Link / Symlink):                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  目录 /a/:  "link" → inode 99                       │   │
│  │                                                     │   │
│  │  inode 99:                                          │   │
│  │    类型 = 符号链接 (l)                              │   │
│  │    数据块存: "/b/file"   ← 就是一段文本,存储路径!    │   │
│  │                                                     │   │
│  │  访问 "link" → 读 inode 99 → 看到路径 "/b/file"    │   │
│  │  → 用这个路径重新查找 → 找到真正的文件               │   │
│  │                                                     │   │
│  │  符号链接可以跨文件系统                               │   │
│  │  如果目标被删了 → 悬空链接 (dangling symlink)        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第3部分:超级块 — 文件系统的"身份证" ​

3.1 超级块存了什么 ​

┌─────────────────────────────────────────────────────────────┐
│              超级块 (Superblock) 的关键字段                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 魔数 (Magic Number):                                │   │
│  │    ext4: 0xEF53                                    │   │
│  │    btrfs: "_BHRfS_M"                               │   │
│  │    NTFS: "NTFS     "                               │   │
│  │                                                     │   │
│  │  用途: mount 时,内核读超级块 → 看魔数               │   │
│  │        识别格式 → 调用对应驱动                       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ext4 超级块的其他关键字段:                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 块大小           1024/2048/4096 字节               │   │
│  │ inode 总数       文件系统创建时决定                  │   │
│  │ 块总数           整个文件系统可用的块数              │   │
│  │ 空闲块数         还剩多少块可用                     │   │
│  │ 空闲 inode 数    还剩多少 inode 可用               │   │
│  │ 挂载计数/最大挂载  触发 fsck 的阈值                 │   │
│  │ 最后挂载时间      用于检测不干净卸载                 │   │
│  │ 文件系统 UUID     全局唯一标识 (用在 fstab 里)       │   │
│  │ 卷名             给人类看的名字 (如 "root")          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  使用 dumpe2fs 可以看到超级块:                              │
│  # dumpe2fs -h /dev/nvme0n1p3 | head -20                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第4部分:Journal — 为什么断电不丢数据 ​

4.1 没有 Journal 的可怕场景 ​

┌─────────────────────────────────────────────────────────────┐
│              没有 Journal: 创建文件的崩溃时刻                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  操作: 在 /home/ 下创建一个 100MB 的文件                     │
│                                                             │
│  需要的步骤:                                                │
│  1. 分配一个新的 inode (改 inode 位图)                       │
│  2. 写 inode (填大小/权限/时间戳)                            │
│  3. 在 /home 目录项中添加一行 (文件名 + inode 号)            │
│  4. 分配数据块 (改块位图)                                    │
│  5. 在 inode 中写数据块指针                                  │
│  6. 写 100MB 数据 (100MB / 4KB = 25600 个数据块)            │
│  7. 更新超级块 (空闲块数、空闲 inode 数)                     │
│                                                             │
│  如果在第 4 步后断电:                                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 位图标记了块已分配,但 inode 没有指向它们               │   │
│  │ → 这些块永久"丢失" (空间泄漏)                         │   │
│  │                                                     │   │
│  │ 需要 fsck 扫描整个磁盘来修复                          │   │
│  │ 在 TB 级磁盘上,fsck 可能需要数小时                   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

4.2 Journal 的工作原理 ​

┌─────────────────────────────────────────────────────────────┐
│              Journal —— 先写日记,再做正事                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  带 Journal 的创建文件流程:                                  │
│                                                             │
│  1. 在 Journal 区域写: "我打算: 分配 inode #99,             │
│     分配块 1000-35600, 在 /home 目录加 'bigfile → 99'"     │
│     → 这个叫 Journal 事务 (Transaction)                     │
│                                                             │
│  2. 标记这个事务为"正在提交"                                │
│                                                             │
│  3. 实际执行操作:                                           │
│     - 写 inode #99                                         │
│     - 分配并写数据块                                        │
│     - 更新目录项                                            │
│     - 更新超级块                                            │
│                                                             │
│  4. 标记这个事务为"已完成"                                  │
│                                                             │
│  如果在步骤 3 中间断电:                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 重启后,文件系统检查 Journal:                         │   │
│  │ "有个事务标记了'正在提交'但没'已完成'"                │   │
│  │ → 重放 (Replay) 这个事务 → 把该写的写完               │   │
│  │                                                     │   │
│  │ 不会丢数据,不需要全盘 fsck                           │   │
│  │ 恢复只需要几秒                                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ext4 的三种 Journal 模式:                                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  journal (data=journal):                            │   │
│  │    文件数据和元数据都写 Journal → 最安全, 最慢, 很少用│   │
│  │                                                     │   │
│  │  ordered (data=ordered, 默认):                       │   │
│  │    元数据写 Journal, 数据先于元数据写入 → 中等安全     │   │
│  │    文件数据不会丢失, 但可能不完整 (文件大小可能是旧的) │   │
│  │                                                     │   │
│  │  writeback (data=writeback):                        │   │
│  │    只元数据写 Journal, 数据写入顺序不限 → 最快        │   │
│  │    断电后新文件可能包含文件系统原有的旧数据 → 安全风险 │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第5部分:COW — btrfs/ZFS 的核心哲学 ​

5.1 COW = Copy-On-Write ​

┌─────────────────────────────────────────────────────────────┐
│              COW vs 传统覆盖写入                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  传统文件系统 (ext4): 修改一个块 = 直接在原位置覆盖写入       │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 修改前:                                              │   │
│  │   块 A: [旧数据]                                     │   │
│  │   块 B: [元数据, 指向 A]                              │   │
│  │                                                      │   │
│  │ 修改:                                                │   │
│  │   块 A: [旧数据] → 直接覆盖 → [新数据]               │   │
│  │                                                      │   │
│  │ 如果在覆盖过程中断电:                                  │   │
│  │   块 A 可能新旧数据混合 (torn write)                  │   │
│  │   这就是为什么需要 Journal                           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  COW 文件系统 (btrfs/ZFS): 修改一个块 = 写到新位置            │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 修改前:                                              │   │
│  │   块 A: [旧数据]                                     │   │
│  │   元数据树: ...→ 块 A                               │   │
│  │                                                      │   │
│  │ 修改:                                                │   │
│  │   1. 分配新块 C                                     │   │
│  │   2. 把修改后的内容写到 C                            │   │
│  │   3. 更新元数据树: ...→ 块 C                        │   │
│  │   4. 只有元数据树更新完成的那一刻,才"提交"修改       │   │
│  │                                                      │   │
│  │ 块 A 原封不动 —— 旧版本还在!                         │   │
│  │                                                      │   │
│  │ 如果在步骤 3 断电:                                    │   │
│  │   元数据树没有更新 → 仍然指向块 A → 旧版本完好        │   │
│  │   新写的块 C 是孤立的,会被 GC 回收                  │   │
│  │   永远不会有"半旧半新"的状态                         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  COW 的两个直接好处:                                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │ 1. 天然的快照 (Snapshot)                             │   │
│  │    旧数据块没有被覆盖 → 它们就是天然的快照            │   │
│  │    创建一个快照几乎不占额外空间                       │   │
│  │                                                     │   │
│  │ 2. 不需要 Journal                                   │   │
│  │    COW 本身保证了原子性 → 写操作要么完整完成          │   │
│  │    要么完全不生效 → 不需要单独的 Journal 区域          │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  COW 的代价:                                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 1. 碎片化 —— 频繁修改的文件数据散落在各处              │   │
│  │ 2. 写放大 —— 更新一棵 B-tree 的叶子需要复制整条路径   │   │
│  │ 3. 不适合 VM 镜像/数据库 —— 频繁随机写导致大量碎片    │   │
│  │    (btrfs 对此有 nocow 选项)                         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

第6部分:权限模型 — UGO/rwx ​

6.1 权限的存储 ​

┌─────────────────────────────────────────────────────────────┐
│              inode 中的权限字段                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  inode 里的权限用一个 16 位整数存储:                          │
│                                                             │
│  类型(4bit)  suid sgid sticky  rwx(owner) rwx(group) rwx(other) │
│  ───────────────────────────────────────────────────────────── |
│  1000        -     -    -       111       101       101     │
│                                                             │
│  解读:                                                      │
│  1000  = 普通文件                                           │
│  111   = rwx (读+写+执行)  ← owner                         │
│  101   = r-x (读+执行)      ← group                         │
│  101   = r-x (读+执行)      ← other                         │
│                                                             │
│  显示为: -rwxr-xr-x                                         │
│           ↑                                                │
│         '-' = 普通文件                                      │
│         'd' = 目录                                         │
│         'l' = 符号链接                                     │
│                                                             │
│  权限的 inode 视角:                                         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  目录的 'x' (执行权限) = 可以进入这个目录             │   │
│  │  目录的 'r' (读权限)   = 可以列出目录内容 (ls)        │   │
│  │  目录的 'w' (写权限)   = 可以增删目录中的文件          │   │
│  │                                                     │   │
│  │  删除一个文件不需要文件本身的 'w' 权限                │   │
│  │  只需要 文件所在目录 的 'w' 权限!                   │   │
│  │  (因为删除只是从目录中移除一项)                       │   │
│  │                                                     │   │
│  │  这就是 sticky bit 的作用 (/tmp 的 1777):            │   │
│  │  任何人都能在 /tmp 创建文件,                          │   │
│  │  但只有文件所有者和 root 能删除                        │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
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

核心总结 ​

总结1:文件系统的核心数据结构 ​

inode:   文件的元数据(大小/权限/时间戳/数据块指针)— 没有文件名
目录:    一张表 {文件名 → inode 号} — 文件名存在这里
超级块:  文件系统的元数据(块大小/inode 数/UUID/魔数)
1
2
3

总结2:Journal 的哲学 ​

先写日记 (Journal), 再做正事 (实际写入)
断电后: 看日记 → 重放 → 恢复完成
这就是为什么现代文件系统断电不坏
1
2
3

总结3:COW 的利弊 ​

利: 天然快照、不需要 Journal、写操作原子性
弊: 碎片化、写放大、不适合频繁随机写的场景
1
2

章节测试 ​

测试1:inode 不含文件名 ​

为什么 mv 一个 10GB 的文件瞬间完成?

测试2:硬链接和符号链接 ​

硬链接不能跨文件系统的根本原因是什么?

测试3:Journal ​

突然断电时,文件系统如何利用 Journal 恢复?

测试4:COW ​

为什么 COW 文件系统不需要单独的 Journal?

测试5:目录权限 ​

/tmp 是 drwxrwxrwt。所有人都能读写 /tmp。一个普通用户能否删除 /tmp 下另一个用户创建的文件?为什么?


参考答案 ​

测试1答案 ​

mv 只修改目录项:在目标目录中加一行 {oldname → inode X},从源目录中删除 {oldname → inode X}。inode 和数据块完全不变。文件不管多大,这个操作是 O(1) 的。

测试2答案 ​

硬链接的本质是两个目录项指向同一个 inode 号。inode 号只在同一个文件系统内部有意义——它是文件系统内部的编号。跨文件系统时,inode 号在另一个文件系统中有完全不同的含义。符号链接不受此限制,因为符号链接存储的是路径字符串(跨文件系统通用)。

测试3答案 ​

重启后,文件系统检查 Journal 区域:未完成的事务(标记了"正在提交"但没有"已完成")会被重放——按照事务记录的操作重新执行,直到完成。已完成的事务可以直接跳过。这个过程就是 Journal Replay。

测试4答案 ​

因为 COW 本身提供了原子性保护。修改操作永远不覆盖原始数据,而是写到一个新位置。只有当元数据树更新完成、指向新位置的那一刻,修改才算"生效"。如果在更新过程中断电,元数据树仍然指向旧位置,旧数据完整。不存在"半旧半新"的中间状态需要 Journal 来修复。

测试5答案 ​

不能。虽然目录 w 权限允许增删文件,但 /tmp 的最后一个 t(sticky bit)改变了这个规则:只有文件所有者、目录所有者和 root 才能删除文件。即使别人能写 /tmp,也无法删除你的临时文件。


相关笔记 ​

  • [[03-partition-table]] - 分区划分了区域,文件系统在里面建 inode
  • [[05-filesystem-formats]] - ext4/btrfs/NTFS 分别如何实现这些概念
  • [[12-ext4-deep-dive]] - ext4 的 inode 和 journal 的源码级细节

下一步学习 ​

  • [ ] 阅读 05 - 常见文件系统格式详解

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇4. 磁盘分区表 — GPT 与 MBR / Disk Partition Tables: GPT and MBR
下一篇6. 常见文件系统格式详解 — FAT 到 ZFS 的进化史 / Filesystem Formats from FAT to ZFS

持续记录,持续成长

Copyright © Tidenflow