Linux 基础 02:/ 底下为什么是这些目录,inode 里到底存了什么

发布于 2022-04-10 20:30 更新于 2022-04-10 22:00 1708 字 9 min read ... 访问量 手写 每个字都是我自己敲的。

Linux 基础 25:收尾——自查清单与继续深入的方向Linux 基础 24:启动流程与救援——UEFI、GRUB、initramfs 与 emergency modeLinux 基础 23:容器与内核边界——namespace、cgroup 与 docker exec 背后Linux 基础 22:日志与故障排查方法论——从现象到根因的六步Linux 基础 21:定时任务——crontab 的坑与 systemd timerLinux 基础 20:Shell 脚本(下)——trap、日志、幂等与并发锁Linux 基础 19:Shell 脚本(上)——引号、条件与退出码Linux 基础 18:性能观测与 strace——机器到底卡在哪Linux 基础 17:防火墙——iptables、nftables、firewalld 与 ufw 的关系Linux 基础 16:SELinux——当权限都对,服务还是被拒绝Linux 基础 15:权限进阶——sudoers 的通配陷阱、ACL 与 capabilitiesLinux 基础 14:SSH 与远程运维——密钥、权限与三种隧道Linux 基础 13:网络基础——自下而上的排错顺序Linux 基础 12:磁盘与文件系统——从块设备到挂载点Linux 基础 11:systemd——unit、systemctl 与 journalctl 的正确用法Linux 基础 10:包管理——apt 到底做了什么,以及四个高频报错Linux 基础 09:用户与组——passwd、shadow、sudoers 三件套Linux 基础 08:环境变量与 shell 启动文件——为什么 ssh 跑命令找不到你的 PATHLinux 基础 07:进程与信号——TERM 和 KILL 到底差在哪Linux 基础 06:管道与重定向——三条流、一个顺序问题Linux 基础 05:文本处理——把 grep/sort/uniq 变成你的分析工具Linux 基础 04:权限与属主——rwx 在文件和目录上不是一回事Linux 基础 03:ls、cp、mv、rm 的真实语义,以及那个由 shell 展开的 *Linux 基础 02:/ 底下为什么是这些目录,inode 里到底存了什么Linux 基础 01:终端、Shell,和命令是怎么被找到的
FHS 每个目录的职责与"谁会写它",再往下一层:文件名其实不属于文件,rm 不是删除,而"磁盘有空间却写不进"通常是 inode 用满了。

这一节要解决什么

多数人对 / 的印象是:/etc 放配置,/home 放用户。但真正决定排障方向的,是另外几个问题:谁在往这个目录写、重启后会不会消失、它是磁盘还是内存。再往下还有一层更根本的东西:在 Linux 里,文件名和文件本身是分开的。理解了这一点,rm、mv、硬链接、以及那句著名的 No space left on device 才有统一的解释。

一、FHS:每个目录是谁的地盘

目录放什么谁在写特别提醒
/bin、/sbin基础命令(ls、ip)包管理器现代发行版是指向 /usr/bin、/usr/sbin 的符号链接
/usr系统装的大部分东西:bin/ lib/ share/ local/包管理器体积最大的地方;/usr/local 留给手工安装
/etc配置你和包管理器只放配置,别在这里写日志
/var运行时会增长的东西:log/ cache/ spool/ lib/各种服务磁盘写满的头号嫌疑人就是 /var/log
/home、/root用户与 root 的家目录你备份的重点
/tmp临时文件任何人常被挂成 tmpfs 或定期清理,别放重要数据
/opt第三方独立软件你与包管理器无关的整套软件
/srv对外服务的数据你约定俗成,很多机器空着
/run本次启动产生的运行时数据(PID、socket)服务早年的 /var/run 现在指向它
/proc、/sys内核暴露的虚拟文件内核读它们是在读内核状态,不是读磁盘
/dev设备文件内核/udev/dev/sda、/dev/null 都在这里

先看清自己这台机器的实际情况(比背 FHS 有用得多):

ls -ld /bin /sbin /lib /usr/bin /tmp /var /run
findmnt /tmp /var /home /            # 各自挂在哪个设备上、是不是 tmpfs

我这边一台 Ubuntu 的实际输出(节选):

$ ls -ld /bin
lrwxrwxrwx 1 root root 7  2月  2 08:55 /bin -> usr/bin

$ findmnt /tmp
TARGET SOURCE FILESYSTEM OPTIONS
/tmp   tmpfs  tmpfs      rw,nosuid,nodev,size=...

两个结论直接落地:/bin 只是入口,真身在 /usr/bin;/tmp 是内存里的 tmpfs —— 重启即清空,且占用的是内存不是磁盘(这点在排查“内存去哪了”时经常被忽略)。

二、inode:文件真正的身份证

用 ext4 举例,inode 里存的是:文件类型与权限、属主与属组、文件大小、三个时间戳(atime/mtime/ctime)、链接计数、以及指向数据块的 extent 指针。它不存文件名——名字存在目录项(directory entry)里,由目录自己维护一张“名字 → inode 号”的表。

ls -i  a.txt                # 最左边那列就是 inode 号
stat   a.txt                # 完整元数据:Inode / Links / Access / Modify / Change
df   -h /                   # 容量
df   -i /                   # inode 使用率(这一行最容易被忽略)

我的批注:ls -l 看到的信息大部分来自 inode,只有一个字段来自目录——文件名。这也是“同一份数据可以有很多个名字”的物理基础。

三、硬链接、软链接,以及“删除”的真相

echo hello > a.txt
ln    a.txt hard.txt        # 硬链接
ln -s a.txt soft.txt        # 软链接
ls -li a.txt hard.txt soft.txt
131072 -rw-r--r-- 2 user user 6  ... a.txt
131072 -rw-r--r-- 2 user user 6  ... hard.txt     ← 同一个 inode 号,Links=2
131073 lrwxrwxrwx 1 user user 3  ... soft.txt -> a.txt
硬链接软链接
本质同一 inode 的另一个名字一个单独的 inode,内容是路径字符串
inode 号与源文件相同不同
链接数Links 增加不影响源文件计数
跨文件系统❌ 不行(inode 号只在单个文件系统内唯一)✅ 可以
指向目录❌(只有内核自己造的 . 与 .. 例外)✅ 可以
源文件被删数据仍在,直到计数归零变成悬空链接(readlink 还能看到路径)

然后是关键一句:

rm a.txt        # 实际发生的是 unlink:链接计数 2 → 1

rm 不删数据,只把名字从目录里摘掉;当链接计数减到 0、且没有进程还开着这个文件时,内核才回收数据块。所以“误删之后磁盘空间没释放”也是同一套机制:进程还持有那个已删除文件的句柄。

还有一个由此推出的日常现象:mv 在同一个文件系统内只是改目录项(瞬间完成);跨文件系统时是复制 + unlink(大文件会很慢,也可能因为空间不足而失败)。

顺手验证跨设备:

findmnt -no SOURCE /          # 例:/dev/sda2
findmnt -no SOURCE /boot      # 例:/dev/sda1  ← 不同文件系统,mv 过去就是复制

四、真实故障:df -h 还有空间,却写不进去

这是我这几年遇到最“反直觉”的一类报障:df -h 显示还有几个 G,可写文件就是报 No space left on device。原因通常是 inode 用满,而不是容量用满。

df -h /
df -i /
Filesystem      Inodes  IUsed  IFree IUse% Mounted on
/dev/sda2      6553600 6553600     0  100% /

IUse% 100% 时,容量再大也写不进新文件——因为每个新文件都要占一个 inode。

高发位置:/var/spool(邮件队列、任务队列)、会话文件目录、以及被程序疯狂创建小文件的地方。定位方法不是找“最大的文件”,而是找“文件数最多的目录”:

# 按“文件数”排序,而不是按体积(GNU find)
sudo find /var -xdev -type f -printf '%h\n' 2>/dev/null \
  | sort | uniq -c | sort -rn | head

顺带记住 du 与 df 会对不上账的三种常见原因:已删除但被进程占用的文件、稀疏文件、以及 du 会按块向上取整。

五、动手清单

# 1. 目录职责的“实证”
ls -ld /bin /sbin /lib; findmnt -o TARGET,SOURCE,FSTYPE /tmp /var

# 2. inode 与链接
echo hi > f; ln f g; ln -s f s; ls -li f g s; stat -c '%i %h %n' f g s

# 3. 删除的真相:数据块在链接归零前不消失
ln f f2; rm f; ls -li f2      # f2 还在,inode 号不变

# 4. 两个空间维度
df -h /; df -i /

小结

  • 目录职责的判据是三条:谁写、重启后是否消失、是磁盘还是内存(/tmp、/run、/proc、/sys 都是“假文件系统”)。
  • 文件名属于目录项,不属于文件;inode 才是文件系统的身份证,且只在单个文件系统内唯一。
  • rm 是 unlink,mv 同盘是改名、跨盘是复制。
  • 报“没空间”时,df -h 和 df -i 都要看。

下一节预告

下一节回到最日常的几个命令:ls、cp、mv、rm 的真实语义——glob 是 shell 展开的、-- 有什么用、cp -a 到底保留哪些东西,以及 rm -rf 为什么不该随手敲。

执笔 手写

喜欢的话,留下你的评论吧~

加载中...