Linux设备与存储精读 · L02-02 | inode 与目录项:名字、元数据、数据分别在哪

模块 :L02 文件、路径与元数据

篇号 :L02-02 / 38

预计阅读 :40 分钟

主线:Linux 设备与存储


文章目录

    • 本篇目标
    • [30 秒速览](#30 秒速览)
    • 正文
      • [1. 为什么不能把「文件」想成一团东西](#1. 为什么不能把「文件」想成一团东西)
      • [2. inode:元数据住在这里](#2. inode:元数据住在这里)
      • [3. 目录项:名字住在这里](#3. 目录项:名字住在这里)
      • [4. 目录本身也是特殊文件](#4. 目录本身也是特殊文件)
      • [5. 数据块:内容住在这里](#5. 数据块:内容住在这里)
      • [6. 和块设备、镜像、挂载怎么接起来](#6. 和块设备、镜像、挂载怎么接起来)
      • [7. 用 inode 号做两个实验直觉](#7. 用 inode 号做两个实验直觉)
        • [7.1 同 FS:两个名字,一个 inode](#7.1 同 FS:两个名字,一个 inode)
        • [7.2 不同 FS:inode 号可以「撞号」](#7.2 不同 FS:inode 号可以「撞号」)
      • [8. 路径查找在干什么(串起来)](#8. 路径查找在干什么(串起来))
      • [9. 超级块:整盘说明书(够用即可)](#9. 超级块:整盘说明书(够用即可))
    • [Android 对照](#Android 对照)
    • 检查清单
    • 练习
    • 本篇边界
    • 下一篇预告

本篇目标

把「一个文件」拆成三块:名字 (目录项)、元数据 (inode)、数据(数据块)。弄清目录本身也是带 inode 的特殊文件,其内容是「文件名 → inode 号」。并能把这套结构和块设备上的文件系统镜像、挂载后的路径访问对上号,为硬链接(L02-03)与权限(L03)打地基。


30 秒速览

  • 路径上的名字 ≠ inode ≠ 文件内容;三者分开存放。
  • 目录项 :名字 → inode 号;inode :类型、权限、大小、数据在哪;数据块:普通文件的字节内容。
  • 目录也是文件:自己有 inode;目录的「内容」就是一条条目录项。
  • 同一 inode 可以有多个名字(硬链接雏形);删一个名字不等于立刻删光数据。
  • FS 镜像刷到分区块设备后,上述结构已以二进制形式躺在设备上;挂载后由文件系统驱动解析,路径才能用。

正文

1. 为什么不能把「文件」想成一团东西

口语里说「有个文件 /data/local/tmp/a.txt」,心里容易当成一整块。

在文件系统里,至少要拆开看:

部分 回答什么问题 存在哪里(概念)
名字 叫什么、挂在哪个目录下 目录项(dentry)
元数据 谁的、什么权限、多大、类型 inode
数据 文件里真正的字节 数据块(data blocks)
text 复制代码
目录项:  "a.txt"  ──→  inode #1442
                         │
                         ├─ 类型:普通文件
                         ├─ 权限、属主、大小、时间戳 ...
                         └─ 指向哪些数据块
                                │
                                ▼
                         数据块:Hello\n ...

后面凡是「改名」「硬链接」「权限」「删除后空间是否释放」,都建立在这张分离图上。


2. inode:元数据住在这里

inode (index node)是文件系统里描述一个对象的核心结构。

用户通常不直接「打开 inode 号」,而是通过路径找到它;但可用探针看见编号:

bash 复制代码
# Android / 服务器均可试
ls -li /data/local/tmp 2>/dev/null | head
# 服务器:
ls -li /tmp | head
stat -c '%i %n' /tmp 2>/dev/null

ls -li 最左侧一列一般是 inode 号(同一文件系统内标识一个对象)。

inode 里典型包含(不同 FS 细节不同,心智模型够用即可):

类别 例子
类型 普通文件 / 目录 / 符号链接 / 设备节点 ...
权限与属主 mode、uid、gid(L03)
大小与时间 size、atime/mtime/ctime
链接计数 有多少个名字指向本 inode(L02-03)
数据位置 指向哪些数据块,或符号链接目标等

inode 一般不存文件名。

文件名在目录项里;所以同一个 inode 可以对应多个名字。


3. 目录项:名字住在这里

目录项把「人类可读的名字」接到「inode 号」:

text 复制代码
目录 /data/local/tmp 的内容(概念上)≈

  "."      →  该目录自己的 inode
  ".."     →  父目录的 inode
  "a.txt"  →  1442
  "b.bin"  →  1443

因此:

  • 改名(同文件系统内):多半是改目录项里的名字,inode 与数据可以不动。
  • 移动到另一目录(同 FS):从旧目录删一项、在新目录加一项,仍可指向同一 inode。
  • 跨文件系统「移动」:往往变成复制 + 删除,因为 inode 号空间不跨 FS 共用。

4. 目录本身也是特殊文件

L02-01 里目录行首是 d。再精确一步:

  1. 目录自己有 inode(类型为目录)。
  2. 目录的「文件内容」在概念上就是目录项列表(名字 → inode)。
  3. 现代 FS(ext4、f2fs 等)磁盘上可能用树/哈希等结构存这些项,但对外仍是「查名字得到 inode」。
text 复制代码
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 与本篇拼成一条:

text 复制代码
(制作阶段)目录树 + 权限等
        ↓ e2fsdroid / mkfs+填充 / 构建系统等
FS 镜像文件(普通文件 -)
  内含:超级块、inode 表、目录项、数据块......(二进制)
        ↓ 刷写到 eMMC 某分区
分区块设备(b)上已是同一套二进制布局
        ↓ mount(文件系统驱动认超级块并接管)
挂载点目录(d)下出现可路径访问的文件树

要点:

  1. 很多系统/用户分区镜像在刷入前就已经带好文件系统结构;刷写 ≈ 把这段二进制放到对应地址范围。
  2. 刷完后内核先暴露块设备;未挂载时,上面已是 FS 二进制,但还只是原始数据。
  3. 挂载 时,对应 文件系统驱动解析超级块 / inode / 目录项,经 VFS 提供路径访问。
  4. 元数据占用空间,所以常见:blockdev 分区大小 > df 显示的文件系统空间(L11 再量化)。

不是所有分区镜像都是「可挂载的 FS 镜像」(如部分 boot/raw);本篇默认讨论 ext4/f2fs/erofs 这类。


7. 用 inode 号做两个实验直觉

7.1 同 FS:两个名字,一个 inode

服务器示例(勿在系统盘上乱做;家目录或 /tmp):

bash 复制代码
cd /tmp
echo hello > inode-demo.txt
ln inode-demo.txt inode-demo-hard.txt   # 硬链接;机制详见 L02-03
ls -li inode-demo.txt inode-demo-hard.txt

示意:两行 inode 号相同 ,链接计数为 2。

说明:两个目录项指向同一 inode,共享元数据与数据块。

7.2 不同 FS:inode 号可以「撞号」

/data 上的 inode 100/system 上的 inode 100 不是 同一个对象。

inode 号只在同一个文件系统(同一次挂载的那棵 FS)内有唯一含义。

bash 复制代码
adb shell ls -li /data/local/tmp 2>/dev/null | head
adb shell ls -li /system/bin 2>/dev/null | head
# 两边都可能出现相同数字,并不表示同一文件

8. 路径查找在干什么(串起来)

访问 /data/local/tmp/a.txt 时,概念步骤是:

text 复制代码
从挂载点 /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 镜像 → 块设备二进制 → 挂载 → 路径」说成一条链
  • 明白改名/硬链接为何可以不动文件内容

练习

判断题(对 / 错)

  1. 文件名保存在 inode 里,所以改名一定要改 inode。
  2. 目录没有 inode,只有目录项。
  3. 同一块磁盘上两个不同挂载的文件系统,可以各自存在 inode 号为 2 的对象。
  4. 分区块设备在未挂载时,若已刷入 FS 镜像,盘上可以已经有 inode/目录项的二进制布局。

参考答案

  1. 错。名字在目录项;同 FS 改名通常改目录项。
  2. 错。目录自己也有 inode。
  3. 对。编号空间按文件系统(挂载实例)区分。
  4. 对。挂载是解析与接入目录树,不是「这时才凭空生成全部元数据」(首次 mkfs 的情况除外)。

读输出题

text 复制代码
$ 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
  1. 这两个名字对应几个 inode?
  2. 第三列的 2 通常表示什么?
  3. 若删除 inode-demo.txt,数据是否一定立刻消失?

参考答案

  1. 一个(都是 1442)。
  2. 硬链接计数为 2(仍有两个名字指向该 inode)。
  3. 不一定。通常链接计数减为 1,另一个名字仍在,数据仍在;计数到 0 且无进程占用时才回收(细节 L02-03)。

操作题

远程服务器:

bash 复制代码
cd /tmp
rm -f inode-demo.txt inode-demo-hard.txt
echo hello > inode-demo.txt
ln inode-demo.txt inode-demo-hard.txt
ls -li inode-demo.txt inode-demo-hard.txt
rm inode-demo.txt
ls -li inode-demo-hard.txt
cat inode-demo-hard.txt
rm inode-demo-hard.txt

观察:删一个名字后,另一个名字的 inode 号是否不变、内容是否仍在。

Android(只读观察即可):

bash 复制代码
adb shell ls -li /data/local/tmp 2>/dev/null | head
adb shell ls -lid /data /data/local

确认目录行也能看到 inode 号。


本篇边界

  • 不讲硬链接 / 符号链接命令全选项(L02-03)
  • 不讲 ls/stat 常用选项必会总表(L02-04)
  • 不讲权限位语义与 umask(L03)
  • 不讲 ext4/f2fs 磁盘布局的实现级细节(L06 够用深度)
  • 不讲 fstab/fs_mgr 谁发起挂载(后续专栏)

下一篇预告

L02-03 :《硬链接与符号链接:lnreadlinkrealpath》--- 在 inode 图上区分两种「多名字」,并收口常用选项。

相关推荐
AOwhisky3 小时前
Linux(CentOS)系统管理入门笔记(第二十一期)——防火墙管理(Firewalld)——zone、服务端口、富规则与端口转发
linux·运维·笔记·安全·centos·防火墙
lsh曙光10 小时前
延时at指令和定时cron指令
linux·服务器·网络
圆山猫10 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
似的83511 小时前
一步一步学习使用FireMonkey动画() 使用TAnimator类创建动画
linux·学习·nginx
我不管我就要叫小猪12 小时前
嵌入式Linux----网络通信
linux·运维·服务器
泡沫冰@12 小时前
ECS 的介绍和使用
linux·服务器·网络
姜太小白13 小时前
【Linux】df -h 卡住问题的通用排查与解决方案总结
linux·运维·php
fengyehongWorld13 小时前
Linux 终端快捷键
linux·运维
哎呦喂我去去去14 小时前
C#实现屏幕墙:同时监控多个电脑桌面(支持Windows、信创Linux、银河麒麟、统信UOS)
linux·windows·c#