Files
2026-03-22 17:40:44 +08:00

6.7 KiB
Raw Permalink Blame History

你可以把 **inodei节点**当成一句话记住: 👉 inode = 文件的“唯一身份 + 元数据 + 数据定位入口” 它不存文件名,只描述“这个文件是什么、数据在哪”。

下面给你一版从磁盘结构 → 内核对象 → 系统调用全链路的高密度说明,直接对齐现代 Linuxext4 / XFS / Btrfs 共性 + 差异)。


一、inode在磁盘上的本质结构on-disk

以 ext4 为典型其他FS思想类似但结构不同

inode (128B / 256B / 可扩展)
├── i_mode        (文件类型 + 权限 rwx)
├── i_uid / i_gid (属主)
├── i_size        (文件大小)
├── i_atime       (访问时间)
├── i_mtime       (修改时间)
├── i_ctime       (状态变更时间)
├── i_links_count (硬链接数)
├── i_blocks      (占用块数)
├── i_flags       (immutable / append-only等)
├── i_block       (核心:数据指针 or extent root)
└── extra         (ACL / xattr / checksum ...)

关键点:

inode号inode number= 文件的唯一ID在同一文件系统内

👉 磁盘布局:

[superblock][group desc][inode table][data blocks]
                           ↑
                        inode存在这里

👉 每个文件 = 一个 inode 👉 inode 是预分配的ext4 or 动态分配XFS/Btrfs


二、inode不存什么非常关键

inode 不存文件名,文件名在目录里:

目录项directory entry
"name" → inode number

所以:

多个文件名 → 同一个 inode硬链接

三、inode如何定位数据核心机制

现代FS的关键就在这里。

1多级索引ext2/3

inode.i_block:
  [ direct pointers ]
  [ single indirect ]
  [ double indirect ]
  [ triple indirect ]

访问路径:

offset → block index → 指针跳转 → 数据块

2 现代extent treeext4

inode
 └── extent tree root
       ├── (logical → physical, length)
       ├── ...

👉 一个extent表示一段连续空间

(0 → block100, len=50)

优点:

减少元数据 + 提高顺序读性能 + 降低碎片

3 XFS / BtrfsB+tree / B-tree

inode中只存

root pointer

真正的数据结构在树里:

inode → B+tree → extent → block

👉 本质inode只是入口数据在树结构中


四、inode在内核中的结构in-memory

磁盘inode加载到内存后变成

struct inode {
    umode_t i_mode;
    kuid_t  i_uid;
    loff_t  i_size;

    struct super_block *i_sb;

    struct address_space *i_mapping;  // page cache

    struct inode_operations *i_op;
    struct file_operations  *i_fop;

    atomic_t i_count;  // 引用计数
}

关键理解:

磁盘inode = 静态数据
内存inode = 活跃对象 + 行为(函数指针)

👉 i_op / i_fop

  • read / write / lookup / create 等操作入口
  • 实现“多文件系统统一接口”VFS

五、VFS层inode的统一抽象非常关键

Linux不是直接操作ext4/XFS而是通过

VFSVirtual File System

统一结构:

struct file   // 打开的文件
struct inode  // 文件本体
struct dentry // 路径缓存

关系:

path → dentry → inode → data

六、一次 open() 的完整inode路径你要重点理解这个

open("/a/b/file")

内核流程:

1. 路径解析
   "/" → "a" → "b" → "file"

2. 查 dentry cache
   (name → inode) 是否命中

3. 若未命中:
   → 从磁盘目录读取
   → 找到 inode number

4. 读取 inodeinode table / B-tree

5. 创建 struct file

6. 返回 fd

👉 最核心的一跳:

filename → inode number → inode → data

七、read() 时 inode 的作用

read(fd, buf, size)

路径:

fd → struct file → inode → address_space → page cache

关键:

inode.i_mapping → page cache

流程:

1. 查 page cache按 inode + offset
2. 命中 → 直接返回
3. 未命中:
   → inode 找 blockextent/B-tree
   → 触发磁盘IO
   → 填充 page cache

👉 所以:

inode = page cache 的索引根

八、写入write时 inode 的变化

write(fd, ...)

流程:

1. 写 page cachedirty
2. 更新 inode
   - size
   - mtime
3. 延迟写回writeback
4. journaling / CoW 保证一致性

九、删除文件unlink的本质

rm file

不是“删数据”,而是:

1. 目录删除:
   name → inode 映射移除

2. inode.i_links_count--

3. 如果 == 0
   → 回收 inode
   → 回收数据块

👉 重要结论:

文件内容存在与否 ≠ 是否有文件名

这解释了:

  • 删除但进程还在用 → 文件仍存在
  • 临时文件机制

十、硬链接 vs 软链接inode视角

硬链接

file1 → inode 100
file2 → inode 100

👉 同一个 inode


link → inode 200 → "path/to/file"

👉 inode里存路径字符串


十一、不同文件类型的 inode 行为

inode.type 决定行为:

普通文件      → 数据块
目录          → name→inode映射
字符设备      → device id
块设备        → device id
socket        → 内核对象
pipe          → 内核缓冲区

👉 所以:

“一切皆文件” = 一切皆 inode

十二、现代文件系统中的inode演化

ext4

  • inode固定大小
  • extent tree
  • inode table分组

XFS

  • inode动态分配
  • B+tree管理
  • 更适合大规模

Btrfs

  • inode只是B-tree中的一项
  • 没有“固定inode表”
  • 完全对象化:
(key = inode_id, value = metadata)

十三、最重要的统一理解(帮你打通)

inode = 文件系统中的“对象object

它承担:

1. 身份inode number
2. 属性metadata
3. 数据入口block mapping
4. 行为VFS函数指针

十四、一句话终极总结

文件名只是入口inode才是文件本体

十五、如果你继续往下(强烈建议)

下一步你应该打通这一整条链(非常关键):

fd → file → inode → page cache → block → disk

如果你要,我可以给你一版:

👉 “从用户态read()到磁盘IO的完整内核调用路径 + 所有结构体关系图(源码级)”

这个一旦通了你的OS理解会直接上一个台阶。