Linux设备与存储精读 · L02-02 | inode 与目录项:名字、元数据、数据分别在哪
模块:L02 文件、路径与元数据
篇号:L02-02 / 38
预计阅读:40 分钟
主线:Linux 设备与存储
文章目录
- 本篇目标
- 30 秒速览
- 正文
- 1. 为什么不能把「文件」想成一团东西
- 2. inode:元数据住在这里
- 3. 目录项:名字住在这里
- 4. 目录本身也是特殊文件
- 5. 数据块:内容住在这里
- 6. 和块设备、镜像、挂载怎么接起来
- 7. 用 inode 号做两个实验直觉
- 7.1 同 FS:两个名字,一个 inode
- 7.2 不同 FS:inode 号可以「撞号」
- 8. 路径查找在干什么(串起来)
- 9. 超级块:整盘说明书(够用即可)
- Android 对照
- 检查清单
- 练习
- 判断题(对 / 错)
- 读输出题
- 操作题
- 本篇边界
- 下一篇预告
本篇目标
把「一个文件」拆成三块:名字(目录项)、元数据(inode)、数据(数据块)。弄清目录本身也是带 inode 的特殊文件,其内容是「文件名 → inode 号」。并能把这套结构和块设备上的文件系统镜像、挂载后的路径访问对上号,为硬链接(L02-03)与权限(L03)打地基。
30 秒速览
- 路径上的名字 ≠ inode ≠ 文件内容;三者分开存放。
- 目录项:名字 → inode 号;inode:类型、权限、大小、数据在哪;数据块:普通文件的字节内容。
- 目录也是文件:自己有 inode;目录的「内容」就是一条条目录项。
- 同一 inode 可以有多个名字(硬链接雏形);删一个名字不等于立刻删光数据。
- FS 镜像刷到分区块设备后,上述结构已以二进制形式躺在设备上;挂载后由文件系统驱动解析,路径才能用。
正文
1. 为什么不能把「文件」想成一团东西
口语里说「有个文件/data/local/tmp/a.txt」,心里容易当成一整块。
在文件系统里,至少要拆开看:
| 部分 | 回答什么问题 | 存在哪里(概念) |
|---|---|---|
| 名字 | 叫什么、挂在哪个目录下 | 目录项(dentry) |
| 元数据 | 谁的、什么权限、多大、类型 | inode |
| 数据 | 文件里真正的字节 | 数据块(data blocks) |
目录项: "a.txt" ──→ inode #1442 │ ├─ 类型:普通文件 ├─ 权限、属主、大小、时间戳 … └─ 指向哪些数据块 │ ▼ 数据块:Hello\n …后面凡是「改名」「硬链接」「权限」「删除后空间是否释放」,都建立在这张分离图上。
2. inode:元数据住在这里
inode(index node)是文件系统里描述一个对象的核心结构。
用户通常不直接「打开 inode 号」,而是通过路径找到它;但可用探针看见编号:
# Android / 服务器均可试ls-li/data/local/tmp2>/dev/null|head# 服务器:ls-li/tmp|headstat-c'%i %n'/tmp2>/dev/nullls -li最左侧一列一般是inode 号(同一文件系统内标识一个对象)。
inode 里典型包含(不同 FS 细节不同,心智模型够用即可):
| 类别 | 例子 |
|---|---|
| 类型 | 普通文件 / 目录 / 符号链接 / 设备节点 … |
| 权限与属主 | mode、uid、gid(L03) |
| 大小与时间 | size、atime/mtime/ctime |
| 链接计数 | 有多少个名字指向本 inode(L02-03) |
| 数据位置 | 指向哪些数据块,或符号链接目标等 |
inode 一般不存文件名。
文件名在目录项里;所以同一个 inode 可以对应多个名字。
3. 目录项:名字住在这里
目录项把「人类可读的名字」接到「inode 号」:
目录 /data/local/tmp 的内容(概念上)≈ "." → 该目录自己的 inode ".." → 父目录的 inode "a.txt" → 1442 "b.bin" → 1443因此:
- 改名(同文件系统内):多半是改目录项里的名字,inode 与数据可以不动。
- 移动到另一目录(同 FS):从旧目录删一项、在新目录加一项,仍可指向同一 inode。
- 跨文件系统「移动」:往往变成复制 + 删除,因为 inode 号空间不跨 FS 共用。
4. 目录本身也是特殊文件
L02-01 里目录行首是d。再精确一步:
- 目录自己有 inode(类型为目录)。
- 目录的「文件内容」在概念上就是目录项列表(名字 → inode)。
- 现代 FS(ext4、f2fs 等)磁盘上可能用树/哈希等结构存这些项,但对外仍是「查名字得到 inode」。
inode #100(类型:目录,名字通过父目录项关联为 tmp) └─ 数据(目录内容): a.txt → #1442 b.bin → #1443所以「打开一个目录 / 列出目录」本质上是:找到该目录 inode → 读它的目录项 → 再按需读每个子对象的 inode。
5. 数据块:内容住在这里
对普通文件:inode 记录「内容在哪些数据块」;读文件就是按这些指针去块设备上取字节。
对目录:数据区(或等价结构)里是目录项,不是「文本小说」。
对符号链接:目标路径可能存在 inode 内或数据块中(短链接常优化进 inode);L02-03 再看操作。
对块/字符设备节点:inode 描述「这是设备节点 + major/minor」;没有「文件正文数据块」这种普通文件含义——真正的数据在块设备介质上,由驱动按块访问(L05)。
6. 和块设备、镜像、挂载怎么接起来
把 L01 / L02-01 与本篇拼成一条:
(制作阶段)目录树 + 权限等 ↓ e2fsdroid / mkfs+填充 / 构建系统等 FS 镜像文件(普通文件 -) 内含:超级块、inode 表、目录项、数据块……(二进制) ↓ 刷写到 eMMC 某分区 分区块设备(b)上已是同一套二进制布局 ↓ mount(文件系统驱动认超级块并接管) 挂载点目录(d)下出现可路径访问的文件树要点:
- 很多系统/用户分区镜像在刷入前就已经带好文件系统结构;刷写 ≈ 把这段二进制放到对应地址范围。
- 刷完后内核先暴露块设备;未挂载时,上面已是 FS 二进制,但还只是原始数据。
- 挂载时,对应文件系统驱动解析超级块 / inode / 目录项,经 VFS 提供路径访问。
- 元数据占用空间,所以常见:
blockdev分区大小 >df显示的文件系统空间(L11 再量化)。
不是所有分区镜像都是「可挂载的 FS 镜像」(如部分 boot/raw);本篇默认讨论 ext4/f2fs/erofs 这类。
7. 用 inode 号做两个实验直觉
7.1 同 FS:两个名字,一个 inode
服务器示例(勿在系统盘上乱做;家目录或/tmp):
cd/tmpechohello>inode-demo.txtlninode-demo.txt inode-demo-hard.txt# 硬链接;机制详见 L02-03ls-liinode-demo.txt inode-demo-hard.txt示意:两行inode 号相同,链接计数为 2。
说明:两个目录项指向同一 inode,共享元数据与数据块。
7.2 不同 FS:inode 号可以「撞号」
/data上的 inode100与/system上的 inode100不是同一个对象。
inode 号只在同一个文件系统(同一次挂载的那棵 FS)内有唯一含义。
adb shellls-li/data/local/tmp2>/dev/null|headadb shellls-li/system/bin2>/dev/null|head# 两边都可能出现相同数字,并不表示同一文件8. 路径查找在干什么(串起来)
访问/data/local/tmp/a.txt时,概念步骤是:
从挂载点 /data 对应的 FS 根 inode 出发 → 在「根目录」目录项中查 "local" → 得到目录 inode → 在该目录项中查 "tmp" → 得到目录 inode → 在该目录项中查 "a.txt" → 得到文件 inode → 按 inode 读数据块任一层目录缺少「遍历权限」x,查找会在中途失败(L03)。
中间若碰到符号链接,还要先解析目标路径(L02-03)。
9. 超级块:整盘说明书(够用即可)
**超级块(superblock)**记录文件系统级信息:类型、块大小、容量、inode 总量与空闲等。
挂载时驱动先认超级块(含魔数),才能知道如何解读后面的 inode 与数据区。
本篇只需记住:超级块是「这盘 FS 的总头」;不是「每个文件名对应一个固定字节偏移」的对照表。
Android 对照
| 现象 | 用本篇语言解释 |
|---|---|
ls -li看到编号 | 该 FS 内的 inode 号 |
| by-name 是符号链接 | 另有 inode;目标字符串指向块设备路径 |
| 刷入的 userdata/system 类镜像 | 块设备上已含超级块/inode/目录项/数据 |
mount之后/data下能ls | FS 驱动已把二进制解析成路径可访问的树 |
| 自定义分区挂上后权限「不对」 | 看的是该 FS 根 inode / 目录 inode 的元数据(L03、L07) |
检查清单
- 能分开说:名字、inode、数据块各存什么
- 能说明:目录也有 inode,目录内容是名字→inode
- 知道 inode 号只在同一文件系统内比较才有意义
- 能把「FS 镜像 → 块设备二进制 → 挂载 → 路径」说成一条链
- 明白改名/硬链接为何可以不动文件内容
练习
判断题(对 / 错)
- 文件名保存在 inode 里,所以改名一定要改 inode。
- 目录没有 inode,只有目录项。
- 同一块磁盘上两个不同挂载的文件系统,可以各自存在 inode 号为 2 的对象。
- 分区块设备在未挂载时,若已刷入 FS 镜像,盘上可以已经有 inode/目录项的二进制布局。
- 错。名字在目录项;同 FS 改名通常改目录项。
- 错。目录自己也有 inode。
- 对。编号空间按文件系统(挂载实例)区分。
- 对。挂载是解析与接入目录树,不是「这时才凭空生成全部元数据」(首次 mkfs 的情况除外)。
读输出题
$ ls -li 1442 -rw-r--r-- 2 user user 6 ... inode-demo.txt 1442 -rw-r--r-- 2 user user 6 ... inode-demo-hard.txt- 这两个名字对应几个 inode?
- 第三列的
2通常表示什么? - 若删除
inode-demo.txt,数据是否一定立刻消失?
- 一个(都是 1442)。
- 硬链接计数为 2(仍有两个名字指向该 inode)。
- 不一定。通常链接计数减为 1,另一个名字仍在,数据仍在;计数到 0 且无进程占用时才回收(细节 L02-03)。
操作题
远程服务器:
cd/tmprm-finode-demo.txt inode-demo-hard.txtechohello>inode-demo.txtlninode-demo.txt inode-demo-hard.txtls-liinode-demo.txt inode-demo-hard.txtrminode-demo.txtls-liinode-demo-hard.txtcatinode-demo-hard.txtrminode-demo-hard.txt观察:删一个名字后,另一个名字的 inode 号是否不变、内容是否仍在。
Android(只读观察即可):
adb shellls-li/data/local/tmp2>/dev/null|headadb shellls-lid/data /data/local确认目录行也能看到 inode 号。
本篇边界
- 不讲硬链接 / 符号链接命令全选项(L02-03)
- 不讲
ls/stat常用选项必会总表(L02-04) - 不讲权限位语义与 umask(L03)
- 不讲 ext4/f2fs 磁盘布局的实现级细节(L06 够用深度)
- 不讲 fstab/fs_mgr 谁发起挂载(后续专栏)
下一篇预告
L02-03:《硬链接与符号链接:ln、readlink、realpath》— 在 inode 图上区分两种「多名字」,并收口常用选项。