ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux 文件系统与磁盘排查:从 inode、挂载到空间释放的实战指南

Linux 文件系统与磁盘排查:从 inode、挂载到空间释放的实战指南 这段时间好几个同事来问我说背了一堆 Linux 命令什么 ls、cd、grep、awk 都滚瓜烂熟可真遇到磁盘满了但找不到大文件删除文件后空间没释放开发板挂不上根文件系统这种实操问题还是两眼一抹黑该敲哪条命令、输出怎么看、下一步查什么完全没有头绪。我跟他们说别急着记命令先把 Linux 文件系统这根主线理顺。命令只是文件系统之上的操作接口你理解了文件、目录、inode、挂载这几层关系大部分命令根本不用背遇到问题自然能顺藤摸瓜。这篇内容就当作一本按场景组织的速查手册来写以 Linux 文件系统为核心骨架把常用命令按实际用途重新梳理一遍包括 VFS 与 inode 原理、挂载链路、权限与属性、空间排查、嵌入式根文件系统这几个高频场景。适合刚入门 Linux 的开发者、需要频繁处理文件的运维人员以及准备 Linux 面试、想建立系统化知识体系的朋友。1. 先建立一个直觉把文件系统想象成一棵倒挂的树1.1 为什么很多人背了命令却不会解决问题我观察到的通病是大家学命令的时候是按命令字母表背的ls 完了背 cdcd 完了背 cpcp 完了背 mv。这种学习方式最大的问题是命令之间是孤立的你记住了每个命令的语法却没搞清它们操作的对象——文件、目录、块设备这些东西之间是什么关系。一旦问题稍微绕个弯比如为什么 df 显示满了但 du 加起来没多少孤立的知识点就拼不出完整的排查链路。正确的方式是先建立文件系统的整体模型。Linux 下一切目录都从根目录 / 开始向下长成一棵倒挂的树/bin、/etc、/home、/var、/mnt 各自承担不同的职责。普通用户接触到的所有文件、目录、设备节点、进程信息、内核参数都被抽象成了这棵树上的一批文件。命令做的事无非是对这棵树进行增删改查、移动、复制、权限调整、空间管理。1.2 文件系统的类型决定了你该怎么挂载和使用同样是文件系统四个字底层却有很多完全不同的实现。搞清楚它们各自适合什么场景很多选型问题就不会纠结了比如 U 盘分区格式选什么、嵌入式设备为什么用 littlefs。文件系统类型典型用途关键特点使用注意ext4Linux 常规磁盘分区稳定成熟支持日志默认多数发行版主文件系统不跨系统Windows 原生读不了XFS大规模数据存储、高并发写入单文件 8EiB 上限在线扩容强RHEL 系列默认不能直接缩容删除大量小文件性能略弱Btrfs快照、压缩、子卷管理支持写时复制功能多复杂度高对小白不友好vfat/exFATU 盘、SD 卡、跨平台移动盘Windows/Linux/macOS 通用exFAT 无日志异常断电容易丢数据tmpfs内存盘跑临时文件、编译缓存数据在内存读写极快重启消失占内存要控制 size 上限proc/sysfs/devtmpfs内核暴露信息给用户态不在磁盘上是内核的视图千万不要直接写 proc除非你在调内核参数littlefs嵌入式 NOR/NAND Flash掉电安全、磨损均衡、写放大小容量小不适合当作常规磁盘文件系统这里特别提示一点proc、sysfs 这套特殊文件系统并不存在于物理磁盘上你 ls /proc 看到的一大堆数字目录其实是内核运行时动态生成的。理解这一点后面看系统状态命令比如 free、ps解析 /proc 下的文件时就不会困惑它们的数据从哪来。2. VFS与inode为什么说一切皆文件不是一句口号2.1 VFS让不同文件系统共用一套操作接口Linux 之所以能用同一套 ls、cat、cp 命令操作 ext4、XFS、NFS、littlefs靠的是内核里的 VFSVirtual File System虚拟文件系统这一抽象层。你可以把它理解成一个翻译官用户态进程调用 open()、read()、write() 时VFS 负责把这些通用请求转译成具体文件系统比如 ext4 或 littlefs的实现函数。这个设计的好处体现得很直接你在 NFS 网络盘上操作和本地磁盘操作命令没有任何区别换个文件系统格式也不需要改应用代码。正因为有 VFS前面说的一切皆文件的哲学才真正落地——普通文件是文件目录是文件块设备节点是文件socket 也是文件。你甚至可以 cat /proc/cpuinfo 直接看到 CPU 信息因为在 VFS 眼里那也是一个文件。2.2 inode文件清单里最重要的隐藏字段用 ls -l 看文件你只能看到大小、权限、时间这类信息但文件真正放在磁盘上的索引信息藏在 inode索引节点里。每创建一个文件文件系统就分配一个 inode里面记录文件类型、权限、属主、大小、时间戳、数据块的位置。文件名只是目录项dentry里的一个字符串它和 inode 通过一个数字编号关联。用 ls -i 就能看到每个文件的 inode 编号。这个设计直接解释了三个操作系统和面试里反复出现的经典问题为什么硬链接能共享同一份内容因为两个不同的文件名指向同一个 inode你可以用 ln 创建硬链接。文件内容的引用计数链接数大于 1 时删除任何一个名字都不会真正释放数据块只有链接数归零文件才被删除。为什么软链接符号链接会失效因为软链接是自己独立的 inode它的内容是目标路径字符串。目标文件被删软链接就指向一个不存在的路径表现为红底白字的链接断裂。为什么 df 和 du 显示的空间不一致df 统计的是文件系统层面块设备的使用量包括被删但依然被进程占用的空间du 统计的是目录树里实际可见的文件大小总和。大文件被删但进程还持有句柄时df 不减du 当然也统计不到。验证硬链接共享 inode 的实操非常简单echo hello linux /tmp/a.txt ln /tmp/a.txt /tmp/b.txt ls -li /tmp/a.txt /tmp/b.txt你会看到两条记录的 inode 编号完全相同而且链接数变成 2。删除 /tmp/a.txt 后 /tmp/b.txt 内容依然完整因为数据块始终被那个 inode 引用着。2.3 stat一条命令看透文件全部状态快速了解一个文件的完整元信息用 stat 比 ls 可靠得多stat /etc/hosts输出里会显示文件名、大小、块数、inode 编号、硬链接数、访问权限、UID/GID以及三个时间戳Access最后访问时间、Modify内容最后修改时间、Change元数据最后变更时间。三个时间戳很容易搞混我一般这样记Modify 是文件内容变了Change 是文件的身份证信息变了比如改了权限、改了属主、硬链接数变化Change 就会更新。面试官如果问ctime 是什么你答元数据变更时间比创建时间专业得多——因为大多数文件系统并不记录真正的创建时间。3. 挂载不只是mount命令从fstab到根文件系统3.1 挂载的本质把一块存储接到目录树上很多人以为 mount 就是把分区打开其实挂载的本质是建立一个映射关系把一个文件系统在某个块设备或网络路径上关联到当前目录树的一个空目录上。关联之后你 cd 进这个目录看到的就是那个文件系统里的内容。卸载umount就是把映射关系切断目录恢复成普通空目录。这个机制适用于本地磁盘分区也适用于 NFS 网络目录、USB 设备、ISO 镜像文件。很多时候排错你要先明白这块设备挂在了哪个目录才能判断数据写在哪儿、空间算在谁头上。查看当前所有挂载点mount df -hT lsblk -f三条命令各有侧重mount 列出挂载项和挂载参数df 显示各挂载点的空间和文件系统类型lsblk 显示块设备的分区关系和文件系统格式。排查某目录空间不够时先用 df 看它落在哪个挂载点再用 lsblk 确认底层设备是谁思路一下就清晰了。3.2 /etc/fstab 逐字段拆解为什么开机挂载失败开机自动挂载不是 mount 命令完成的而是系统读取 /etc/fstab 一条条执行。每一行由六个字段组成我按顺序解释一下# device dir type options dump pass UUID8f23-9a2c /data ext4 defaults,noatime 0 2 192.168.1.10:/srv /mnt/nfs nfs defaults,_netdev 0 0前两个字段是要挂载什么和挂到哪里。第三个字段是文件系统类型。第四个字段是挂载选项defaults 表示读写、自动挂载、允许设备等常用选项的组合noatime 可以避免每次读取文件都更新访问时间对 SSD 和嵌入式 Flash 能明显减少写入磨损_netdev 表示网络设备等网络就绪后再挂载避免开机时网络没起来导致挂载失败卡住启动流程。第五、六字段平时很少动dump 是备份标记0 表示不备份pass 是 fsck 检查顺序根分区设 1其他本地分区设 2网络文件系统设 0。一个非常常见的坑是fstab 里写了错误的 UUID 或文件系统类型开机就会进入 emergency mode。解决办法是用 live 环境或单用户模式登录把那一行注释掉再重启。强烈建议 fstab 里写 UUID 而不是 /dev/sda1 这种设备名。设备名会随内核识别顺序变化UUID 是文件系统创建时生成的全局唯一标识写入 fstab 后设备名怎么换都不会挂错。可以用 blkid 查询 UUIDblkid3.3 NFS 和 NAS 挂载不同协议的命令差异嵌入式开发和服务器环境里远程文件系统几乎是日常。NFS 挂载常规写法mount -t nfs -o vers3,nolock,timeo600 192.168.1.10:/srv/nfs /mnt/nfs这个命令里值得记的是vers3 指定 NFS 协议版本。为什么嵌入式调试时经常强制用 v3一方面很多精简内核或老掉的内核默认只支持 v3另一方面 v3 不需要额外的 rpcbind/lockd 服务协议逻辑简单开发板上更容易调通。timeo600 是超时时间网络不稳定的嵌入式环境设短一点可以加快失败重试不至于让进程长时间卡死。连接 NAS 或 Windows 共享则要用 CIFSmount -t cifs -o usernameuser,passwordpass,uid1000,gid1000 //192.168.1.20/share /mnt/nas用 NAS 时踩得最多的坑是权限错乱Windows 共享服务端解析的用户和 uid 跟本机对不上挂载后文件属主显示成 nobody 或数字。通过 uid/gid 参数强制映射成你本机的用户 ID能省掉很多 chown 的麻烦。关于 Ventoy 做启动盘时分区文件系统类型选哪个的问题我的建议是用 exFAT。它的兼容性最好Windows、Linux、macOS 都能直接读写也不像 NTFS 那样在 Linux 下需要依赖 ntfs-3g 才能写。ext4 虽然对 Linux 最友好但拿到 Windows 上完全读不了。当启动盘兼顾 PE、Linux 镜像和日常拷贝文件时exFAT 是少数不用折腾的选择。4. 权限与属性普通权限、特殊权限、属性三层分开记4.1 普通权限目录的执行权限到底在管什么ls -l 第一列的 rwxrwxrwx 大多数人都认识但目录的 x 权限经常被误解。文件上的 x 表示可执行目录上的 x 表示能穿过这道门也就是说你必须拥有目录的 x 权限才能 cd 进去、才能访问其中的任何文件。只有 r 权限只能列出文件名但没有 x 就没法 stat 文件也打不开文件内容。只有 w 权限不能新建文件因为创建文件需要在目录里同时有 w 和 x。遇到我能 ls 目录但 cat 文件提示无权限这种问题基本就是目录缺 x 权限。排查时别只盯着文件本身沿路径把每一级目录的权限过一遍很多时候问题出在中间层。4.2 SUID、SGID、Sticky三个特殊权限的作用机制普通权限之外还有三个特殊权限位它们是 Linux 安全模型里绕不开的部分也是面试题常客。特殊权限表示位作用典型示例SUIDs 出现在 owner 的 x 位程序运行时临时获得文件属主的身份/usr/bin/passwdSGIDs 出现在 group 的 x 位程序运行时临时获得属组身份目录设置后新建文件自动继承目录属组团队共享目录Stickyt 出现在 other 的 x 位目录里每个人只能删自己的文件/tmp为什么 /usr/bin/passwd 需要 SUID普通用户要改密码必须写 /etc/shadow但 /etc/shadow 只有 root 能读写。没有 SUID普通用户根本无法完成这个操作。有了 SUID用户执行 passwd 时进程的 uid 临时变成 root于是它可以以 root 身份修改 shadow 文件。这就是为什么 ls -l /usr/bin/passwd 里能看到 rwsr-xr-x。数字表示法里 SUID4、SGID2、Sticky1所以 chmod 4755 表示添加 SUIDchmod 1777 表示给 /tmp 这类目录加粘滞位。这里要给一个很实在的安全建议特意找一下系统里异常带 SUID/SGID 位的文件。恶意提权工具最常见的做法就是把一个程序设置 SUID 后丢到某个目录你再以 root/普通用户身份运行它就可能获得超出预期的权限。定期执行下面这条命令检查全盘 SUID 文件是个好习惯find / -type f -perm -4000 -ls 2/dev/null把输出和系统原始情况对比多出来的文件就要警惕。这个动作放到理解 SUID 机制的语境里既是排查手段也是安全的加固手段。4.3 chattr/lsattr属性层是最后一道防线很多人以为 chmod 就管完权限了其实 chmod 管的是权限位而 chattr/lsattr 管理文件系统属性attribute是更底层的一层防线。最常用的两个属性是 iimmutable不可变和 aappend只可追加chattr i /etc/ssh/sshd_config # 锁住配置文件root也不能改 lsattr /etc/ssh/sshd_config # 查看属性 chattr -i /etc/ssh/sshd_config # 解除锁定再改配置chattr i 的效果是任何人包括 root都不能修改、删除、重命名该文件。对重要配置文件如 sshd_config、fstab加上 i 属性能有效防止误操作和恶意篡改。chattr a 则只允许追加不能截断或覆盖已有内容非常适合挂接日志文件保证日志只增不减避免被清空。注意chattr 只在使用 ext4、XFS 这类 Linux 原生文件系统时有效在 vfat、NFS 上通常不支持。5. 磁盘空间与inode两条满了排查的完整链路5.1 磁盘满但找不到大文件的定位顺序谈磁盘满之前先记住一个反直觉的事实df 和 du 统计口径完全不同。df 看的是文件系统块的占用du 是遍历目录树计算每个文件实际大小。真正排查的顺序应该这样走用 df -h 确认是哪个挂载点满了用 du -sh /* 从根目录扫起一级一级缩小范围定位到大目录后 du -sh * 排序找出最大文件或目录如果 du 统计出来明明很小但 df 显示满了那几乎可以断定有已删除但仍被进程占用的文件。第 4 步是运维排障里最常见的隐藏坑。程序打开一个日志文件后运维用 rm 把日志文件删了但程序还持有文件描述符空间一直没释放。df 还满着du 却找不到这个文件。处理方法是找出哪个进程占用lsof | grep deleted看到被删除但仍打开的进程后要么重启进程要么杀掉进程空间才会归还。如果暂时不能重启进程可以用清空代替删除: /var/log/xxx.log # 或者 truncate -s 0 /var/log/xxx.log这样文件描述符还指向同一个文件但文件内容清空了空间立即释放。这是处理不能停服务但必须释放空间最实用的办法。为了避免走到删除那一步也可以提前给日志做轮转。logrotate 配置好按天/按大小切割日志保留期内的日志压缩存放比等磁盘告警再手动清要省心得多。5.2 inode 耗尽df -h 没满但创建不了文件系统还有另一种满inode 耗尽。df -i 查看 inode 使用率df -i如果 inode 使用率显示 100%哪怕 df -h 还剩十几个 G你依然无法创建任何新文件。原因很简单每个文件都要占用一个 inodeinode 用完了文件系统就无法再记录新文件的信息。这种情况通常是小文件太多造成的大量几 KB 的缓存文件、临时文件、邮件队列堆在一起几百万个 inode 很快就没了。定位办法是先确认哪个挂载点 inode 满再到对应目录下统计文件数find /var -xdev -type f | wc -lxdev 参数限制不跨文件系统避免扫到其他挂载点导致统计膨胀。找到数量异常庞大的目录后清理旧文件或合并小文件即可。如果业务场景本身就需要海量小文件在格式化分区时可以用 mkfs.ext4 -i 调整 inode 密度但这是规划层面的动作改起来得重新格式化生产环境慎用。5.3 sync写缓存、脏页和掉电风险文件系统为了性能写入操作大量使用 page cachewrite() 调用把数据写进内存缓存就返回了内核后台再异步把脏页dirty page刷到磁盘。这个设计极大提升了写性能但也带来了掉电丢数据的风险。sync 命令的作用就是强制把所有脏页刷回磁盘sync拔 U 盘、移动硬盘之前必须 sync这是我从第一次格式化 U 盘起就记住的硬规矩。虽然现代桌面环境在弹出设备时已经自动执行了同步但在服务器命令行环境、嵌入式开发板、或手动卸载设备前先 sync 再 umount 是最稳妥的顺序。顺带一提umount 卸载本身就会同步数据所以很多老手就说卸载就是最好的 sync。涉及哪些脏页、多久刷一次的参数在 /proc/sys/vm/ 下可调dirty_ratio、dirty_background_ratio、dirty_writeback_centisecs 等等。服务器重要数据盘可以调低 dirty_ratio让内核更积极地把数据落盘代价是写入性能下降但对数据安全敏感的场景完全值得。6. 特殊文件系统与嵌入式场景tmpfs、proc、littlefs和NFS根文件系统6.1 proc、sysfs、devtmpfs、tmpfs 各自管什么/ 目录树里有一批不落盘的特殊文件系统理解它们对读懂系统状态异常关键/proc 是 procfs 的挂载点存放进程信息和内核运行时参数。ps、top、free 这些命令的数据源就是 /proc 下的文件。/sys 是 sysfs 的挂载点提供设备、驱动、内核对象的层级视图。ls /sys/class 能看到系统里的设备类别。/dev 是 devtmpfs由内核动态创建和管理设备节点。所以你在 /dev 下看到的 sda、ttyS0 都是内核自动创建的。/tmp 在某些发行版上使用 tmpfs数据放在内存里速度快重启就清空。如果业务把重要数据放在 /tmp 下而系统重启了数据就没了这个坑要提前知道。如果想手动做一个内存盘可以用mount -t tmpfs -o size2G tmpfs /mnt/ramdisk现在很多现代机器的 /run、/dev/shm 都是 tmpfs好处是对 SSD 零磨损、读写速度极快代价是占内存和重启失数据。编译软件时把临时构建目录放到 tmpfs 能显著提速我之前用这种方法把大型 C 项目的编译耗时缩短了不少。6.2 根文件系统是什么嵌入式环境怎么用 NFS 挂载传统 Linux 启动时内核先加载 initramfs一个内存里的临时根文件系统再挂载真正的根文件系统也就是 / 所在的分区或网络路径。根文件系统里要包含内核启动用户态进程所需的最小集合init 程序、shell、动态库、必要的配置文件。嵌入式开发里根文件系统通常先做成一个目录再打包成 rootfs.ext4 或其他镜像格式烧写到 Flash。但开发调试阶段反复烧写 Flash 非常浪费时间所以更高效的做法是通过 NFS 挂载根文件系统把开发主机上的目录直接给开发板使用。启动参数这样写内核 cmdlineroot/dev/nfs nfsroot192.168.1.5:/opt/rootfs,v3 rw ipdhcp主机侧需要先配置 NFS 服务导出 /opt/rootfs 目录编辑 /etc/exports然后开发板启动时内核会通过 NFS 挂载 rootfs 作为根文件系统。这样改代码、改库、加配置直接在开发机上操作开发板重启就能生效省掉整个烧写环节。手动调试时也可以先启动到一个最小系统再手动挂载 NFS rootfsmount -t nfs -o nolock,vers3 192.168.1.5:/opt/rootfs /mnt/target6.3 闪存文件系统 littlefs 与 PlatformIO 场景嵌入式设备上Flash 存储和普通机械盘/SSD 差别很大Flash 有擦写寿命限制写入前必须先擦除意外断电时如果文件系统没有掉电保护很容易损坏整块分区。littlefs 就是专门为这类场景设计的文件系统两个核心特性值得记住掉电安全任何时刻断电都不会导致已有文件损坏或元数据崩溃动态磨损均衡自动把写入分散到不同块避免某几个块频繁擦写提前报废写放大小相比 FAT 类文件系统写放大更小能在小容量 Flash 上更耐用。在 PlatformIO 中使用 ESP32 这类 MCU 时可以在 board_build 配置里指定文件系统board_build.filesystem littlefs然后在代码里通过 LittleFS 库挂载和读写文件。同样是在 Flash 分区上做文件存储选 littlefs 比 SPIFFS 更稳littlefs 面对掉电更可靠目录支持也更完整文件大小限制更友好。如果你曾经遇到 MCU 设备断电后配置数据丢失换成 littlefs 后大概率能解决。7. 把命令学活的思路按问题反查而不是按字母背7.1 高频命令按场景归纳速查手册的价值在于需要时能快速找到所以我按真实问题场景重新归纳一批高频命令而不是按字母排序场景要解决的问题该敲的命令文件管理复制、移动、删除、链接cp、mv、rm、ln文件查看快速看内容、实时跟踪日志cat、less、head、tail -f内容处理搜关键词、按列处理输出的文本grep、awk、sed、cut、sort磁盘与挂载看空间、看块设备、挂载/卸载df、du、lsblk、blkid、mount、umount权限处理改权限、改属主、查属性、查 ACLchmod、chown、chattr、lsattr、getfacl进程管理看进程、杀进程、查占用句柄ps、top、kill、lsof网络排查看端口、测连通、查连接ss、ping、telnet、curl系统日志看内核和系统日志dmesg、journalctlgrep 是文本处理里最值得花时间学的命令。它的 -E 支持扩展正则、-r 递归目录、-l 只显示文件名、-v 反向过滤。命令行处理日志时grep 过滤 awk 取列 sort/uniq 统计这一组合基本能解决 80% 的现场需求。反而是那些花哨的管道组合平时用不到也记不住用到时再翻 man 就行。7.2 面试里占大头的问题其实都集中在几个模块结合我参与面试和被面试的经验Linux 相关的题如果涉及文件系统高频考点非常集中硬链接和软链接的区别硬链接共享 inode、不能跨文件系统、不能链目录软链接是独立文件、可以跨文件系统、可以链目录但会失效。inode 是什么inode 耗尽会怎样文件元信息存储区inode 满时磁盘有空间也无法创建文件。df 和 du 的区别与联系df 看文件系统块占用、du 遍历目录统计文件大小已删除文件场景两者不一致。为什么 rm 文件后磁盘空间没释放文件仍被进程占用句柄lsof 查看 deleted 文件。SUID 的用途和风险临时获得属主身份异常 SUID 文件是提权排查的重点对象。目录的 r/w/x 分别代表什么r 列出文件名、w 增删改文件名、x 进入目录和访问文件。这个清单不复杂但它恰恰说明一个问题面试官不是要考你背诵能力而是考你能否把现象和知识串起来。你把文件系统模型理解透了这些问题都只是模型的具体展开而已。7.3 两条值得养成的习惯第一遇到奇怪的文件系统行为先跑 stat 再看 dmesg。stat 能快速确认文件的真实元信息dmesg 能告诉你内核层面的错误比如 I/O 错误、文件系统只读切换。很多时候顺序反了会绕远路你以为是权限问题结果 stat 一看 is 普通目录、ctime 异常再查 dmesg 才发现磁盘有坏块系统把挂载点切换成了只读。第二改配置文件之前先备份或者用 diff 对比。加注释掉一行 fstab 导致开不了机绝大多数情况下是因为没有备份也没有核对字段含义。先 cp 一份 .bak再动手改最后 mount -a 验证这个流程能避免 90% 的误操作。专业运维和混日子的差别往往就在这些操作习惯上。我最早也是从背命令开始的那会儿记了厚厚一本笔记见了新命令就抄结果一到现场还是抓瞎。后来想明白了命令只是文件系统这个骨架上的操作接口先把文件、目录、inode、挂载这几层关系弄通命令自然就串起来了。这篇速查手册我没有把所有命令都列出来如果列全了它反而没法用了。遇到问题先想这个问题在文件系统里对应哪一层再想该查哪条命令这个顺序比背一百个命令都管用。最后送一个自己常用的经验任何奇怪的文件系统现象先 stat 再 dmesg通常答案就在这两条命令的输出里。
返回列表