ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Linux只读文件系统与磁盘挂载:fsck修复和fstab配置实战

2026/9/18 1:51:08 拓冰建站 浏览量
Linux只读文件系统与磁盘挂载:fsck修复和fstab配置实战 凌晨两点被电话叫醒登上服务器一看日志里清一色刷着Read-only file system应用的写操作全部失败——这是做运维或者自建服务器的朋友几乎都绕不开的一幕。Linux 只读文件系统并不等于磁盘坏了绝大多数情况下是内核在替你把数据先保护起来而磁盘挂载出问题往往又是文件系统变成只读的前因。这篇内容把两件事放在一起讲文件系统为什么会被切成只读、怎么判断是哪一层只读、磁盘挂载背后的机制与/etc/fstab该怎么写以及我这些年处理根分区只读、数据盘掉线、开机挂载失败的真实流程。刚上手 Linux 服务器的同学能照着操作有几年经验但没系统梳理过挂载机制的朋友也能把散落的知识点串成一条线。1. 先搞懂文件系统为什么会被切成只读1.1 三种典型的只读触发路径很多人第一次遇到只读反应是权限不对然后去改chmod、改属主折腾半天没效果。这里要先分清一个概念只读是文件系统层面的状态不是文件权限层面的状态。chmod 777改的是 inode 上的模式位而只读是超级块superblock上挂着的一个标志位两者根本不在一个层级。指望改权限让只读盘恢复可写方向从一开始就错了。排除掉权限问题之后真正把文件系统切成只读的路径我归纳下来主要是三类。第一类是文件系统自身检测到不一致。以 ext4 为例它在挂载选项里有一个errors参数取值可以是continue、remount-ro、panic。当内核在读写过程中发现元数据对不上目录项指向了不存在的 inode、块位图冲突、日志回放失败等就会按照这个参数决定动作。如果配的是remount-ro它就会立刻把整个文件系统重挂成只读防止错误扩散到更多数据块。这是最常见的一类也是保护性只读这个名字的由来。第二类是底层 I/O 错误。磁盘出现坏道、SATA 数据线接触不良、云主机上的云盘发生瞬时断连、RAID 阵列降级重建失败这些都会让块设备层向上抛 I/O error。内核收到持续性的读写失败后同样会触发只读保护。这种场景下dmesg里通常能直接看到设备名和错误码定位相对明确。第三类是人为或工具触发。比如有人手动执行了mount -o remount,ro /data或者用fsck修复完之后系统处于保护状态又或者容器场景里镜像层本来就是只读挂载。还有一种是物理写保护——SD 卡、U 盘侧面那个小开关拨到锁定位置插上来就是只读这个坑新手踩得最多检查半天软件结果是硬件开关的事。提示遇到只读先别急着重启。重启能解决一部分问题但会掩盖真正的错误原因下次还会复发。先把dmesg的关键行留下来。1.2 内核 remount-ro 到底改了什么要理解只读得知道内核改的是哪个数据结构。Linux 上每个挂载好的文件系统在内存里对应一个super_block结构它记录了块大小、inode 数量、挂载选项、状态标志等。其中有一个状态标志位叫MS_RDONLY只要这个位被置上VFS虚拟文件系统层就会拒绝一切写操作应用层收到EROFSRead-only file system错误码。remount-ro的整个过程大致是这样ext4 的写路径在提交事务时检测到异常调用错误处理逻辑内核把该文件系统的MS_RDONLY置位同时把这次错误写进内核环形缓冲区也就是dmesg能看到的那条日志。之后所有 write、create、unlink 系统调用都会在 VFS 层被拦下来根本到不了磁盘驱动。这里有个细节值得记住文件系统被切成只读已经打开的文件描述符仍然可以继续读但写入会失败。所以有些服务表现为能查不能写有些数据库表现为连接还在但事务提交报错都是同一个原因的不同表象。理解了这一点你排查时就不会去怀疑网络、怀疑连接池而是直接去看挂载状态。1.3 报错信息怎么快速对号入座现场排查最怕的是信息太多不知道先看哪条。我整理了一张对照表把常见报错和优先动作列出来遇到时按表走基本不会跑偏。报错 / 现象大概率原因优先动作Read-only file system文件系统已被重挂为只读mount或findmnt确认挂载状态Structure needs cleaningext4 元数据不一致备份数据后fsckInput/output error块设备层读写失败dmesg看设备名查硬件与线缆No space left on device空间或 inode 耗尽df -h与df -i一起看mount: wrong fs type文件系统类型或工具缺失确认blkid结果与内核支持mount: unknown filesystem type缺少对应驱动模块检查模块是否加载或安装工具包表格里的顺序基本就是我的排查顺序先确认状态再看日志最后才动手修。跳过前两步直接fsck在数据盘上是很危险的操作后面会详细说。2. 磁盘挂载背后的机制与关键参数2.1 mount 这一步究竟发生了什么想彻底弄明白挂载绕不开几个核心对象VFS、superblock、inode、dentry还有挂载点。用生活化的比喻解释磁盘是一栋楼superblock 是楼的产权登记和总台账inode 是每个房间的档案卡记录房间归属和大小dentry 是走廊里的门牌索引负责从哪走到哪能找到这个房间VFS 是物业前台所有找房间的请求都先经过它统一调度。执行mount /dev/sdb1 /data时内核大致做了这么几件事通过设备号找到块设备读取它的超级块并校验魔法数字识别出文件系统类型ext4、xfs、btrfs 等在内存里建立对应的super_block结构然后把这个文件系统的根目录嫁接到/data这个目录节点上。嫁接完成之前/data只是根文件系统下的一个普通空目录嫁接之后访问/data就跳到新文件系统的根了。这里有个很实用的推论挂载点在被挂载覆盖前里面原有的文件会被藏起来。我见过有人在/mnt/data里存了几百 G 文件然后挂载了一块新盘上去回头发现文件不见了其实数据还在原分区里只是被新挂载遮住了。处理办法是卸载后就能重新看到或者用mount --bind把旧目录临时映射到别的位置取数据。查看当前挂载状态我常用三条命令各有分工# 人类可读的树状结构最直观 findmnt # 原始挂载表脚本里解析用这个更稳 cat /proc/mounts # 看某个具体目录 mount | grep /data findmnt的好处是会自动标出挂载参数、源设备、文件系统类型而且默认按树形展示谁挂在谁下面一目了然。/proc/mounts是内核直接导出的永远是真实的传统的/etc/mtab在现代发行版里通常是指向/proc/self/mounts的软链接但如果你在容器里遇到/etc/mtab内容怪异的情况优先信/proc/mounts。2.2 /etc/fstab 六个字段逐个拆解开机自动挂载靠的是/etc/fstab这个文件写错的后果可能比只读更严重——轻则服务起不来重则系统进不了正常模式。它每一行有六个字段字段之间用空格或 Tab 分隔字段含义如下。字段序号名称含义常见取值示例1设备要挂载的块设备UUIDxxxx、/dev/sdb12挂载点挂到哪个目录/、/data、/boot3文件系统类型分区格式ext4、xfs、swap4挂载选项挂载时的参数defaults、noatime5dump是否被备份工具dump一般写06fsck 顺序开机自检顺序根分区1其他2不查0第五个字段现在基本只在老式dump备份工具里有意义绝大多数场景写0就行。第六个字段要稍微讲究一点根分区写1表示最先检查其他需要检查的分区写2swap、光盘、网络文件系统写0表示跳过检查。如果所有分区都写1开机自检会变成串行速度慢如果一块数据盘上写了2但它其实不该被自检比如是大型存储盘开机时间会被fsck拖得很长。一个容易被忽略的点fstab 里的注释用#但行内#后面不会像 shell 那样自动被识别为注释开始。我见过有人把注释写在选项字段后面导致挂载参数被解析成一堆莫名其妙的字符串报bad option。要注释就老老实实另起一行。2.3 UUID 与设备名为什么劝你别偷懒/dev/sdb1这种写法读起来直观但我在生产环境里几乎不用原因是设备名不稳定。机器插拔一块硬盘、加一块 NVMe、BIOS 里调整了启动顺序、甚至只是换了个 USB 控制器sda、sdb的编号都可能整体挪位。原来 fstab 里写的/dev/sdb1指向数据盘某次重启后sdb1变成了系统盘或者另一块盘开机挂载直接把不该挂的挂上去后果很难收拾。UUID 是文件系统创建时就写进超级块的唯一标识只要不重新格式化它永远跟着这块文件系统走跟接口顺序无关。查看方式# 列出所有块设备的 UUID、TYPE、LABEL blkid # 只看某个设备 blkid /dev/sdb1 # 用 lsblk 结合查看树形结构 lsblk -flsblk -f我个人最推荐它把设备树、文件系统类型、UUID、挂载点放在一起展示排查哪块盘挂了什么非常高效。除了 UUID还有 LABEL卷标也可以写进 fstab但卷标可能重复我一般只在临时挂载场景用。注意给已经有数据的盘改 UUID 是危险操作tune2fs -U改完之后必须同步更新 fstab 和引导参数否则系统直接起不来。除非有明确需求不要轻易动 UUID。2.4 挂载参数怎么选取舍在哪defaults是大多数教程里的默认写法它实际等价于一组合集rw,suid,dev,exec,auto,nouser,async。也就是说它并不是什么都不配而是悄悄配了一堆。生产环境里我更倾向把常用参数显式写出来因为不同业务对 I/O 行为的要求差别很大。下面这张表是我实际项目里高频用到的参数。参数作用适合场景代价noatime不更新文件访问时间绝大多数服务器盘失去访问时间统计nodiratime不更新目录访问时间高并发读目录同上范围更小nofail设备不存在也继续启动可插拔数据盘、云盘失败时静默不报错x-systemd.automount首次访问时才挂载不常用的大容量盘首次访问有延迟ro只读挂载归档盘、共享镜像无法写入discardSSD 支持 TRIM固态盘部分老盘有兼容问题noexec禁止执行其中程序上传目录、数据盘脚本无法直接在此执行noatime是我改得最多的一个。默认挂载每次读文件都会顺手更新一次访问时间对机械盘是额外的随机写对 SSD 是额外的写入放大。除了极少数需要审计文件什么时候被读过的场景我都会加上它。nofail要重点说如果你在 fstab 里挂了外置 USB 盘却没写nofail开机时这块盘不在系统会卡在启动阶段等它超时极端情况下进入紧急模式。加上nofail之后设备缺失就跳过不影响系统正常起来对可插拔盘、云上可能延迟挂载的数据盘特别重要。3. 实操只读状态的定位与恢复3.1 第一步永远是确认只读发生在哪一层现场别慌先做三个动作看挂载状态、看磁盘空间、看内核日志。顺序不要乱因为它们回答的是不同问题。# 1. 看哪些挂载点是 ro 状态 mount | grep -E ^/dev| on | grep -w ro # 或者更清晰 findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS | grep -w ro # 2. 看空间和 inode两个都要看 df -h df -i # 3. 看最近的磁盘和文件系统报错 dmesg -T | tail -n 100 journalctl -k -b | grep -iE error|read-only|I/O这里有两个小坑值得提醒。一是df -i一定要和df -h一起看我就遇到过空间还剩 40%但 inode 用光了新文件创建失败日志里报的却是别的错误绕了好一阵。二是dmesg建议加-T显示人类可读时间否则一串单调递增的秒数很难和你重启的时间点对上。如果在dmesg里看到类似下面的输出基本可以定案EXT4-fs error (device sdb1): ext4_lookup: ... inode #... EXT4-fs (sdb1): Remounting filesystem read-only后面那句Remounting filesystem read-only就是内核明确告诉你我按errorsremount-ro的约定把它切成只读了。这时候你要找的不是怎么改回可写而是上面那条 error 到底说了什么。只读是结果error 才是原因。3.2 根分区变成只读怎么应急抢救根文件系统只读是最紧张的场景因为/没法umount——系统正在跑很多进程都开着根分区上的文件。这时候标准动作是重挂载# 尝试把根分区重挂为读写 mount -o remount,rw / # 如果上面失败可能是因为内核已经把它标记为不可恢复 # 这时候要看具体错误必要时进入救援环境处理成功重挂之后你会看到findmnt /的输出里ro变成rw。但别就此收工这只解决了表面问题。接下来必须做几件事把关键业务数据先备份出来查清楚dmesg里那条 error 的性质如果确认是文件系统不一致安排一次维护窗口做离线检查。根分区做fsck有个硬性前提不能挂着做。/更是没法直接卸载。正规做法是重启进入单用户模式或者挂载一个救援镜像在文件系统未挂载的状态下执行fsck -y /dev/xxx。有些发行版支持在启动参数里加fsck.modeforce强制开机自检但生产机器上我一般不这么干因为自检结果不可控——数据量大时fsck可能跑几个小时期间的业务中断你未必批得下来。3.3 数据盘只读按停、查、修、挂四步走非根分区就从容多了因为没有正在使用的包袱。我处理数据盘只读固定四步顺序不能颠倒。第一步是停业务把依赖这块盘的进程全部停掉。别嫌麻烦fsck期间如果有进程还在读写轻则检查不彻底重则加速损坏。第二步是卸载umount /data # 如果提示 target is busy先找谁占着 fuser -vm /data lsof f -- /data第三步是检查修复# ext4 fsck -y /dev/sdb1 # xfs 用 xfs_repair注意 xfs_check 已废弃 xfs_repair /dev/sdb1第四步是重新挂载并验证mount /data mount | grep /data 这里必须强调一条铁律fsck -y的-y表示对所有询问自动回答 yes它会直接修改文件系统。在执行前如果数据重要先尝试用只读方式把能拷的数据拷出来。我见过人抱着先修了再说的心态直接上-y结果目录被清空事后追悔莫及。数据无价多做一步备份永远不亏。3.4 卸载不掉时的排查路子umount报target is busy是最常见的拦路虎。排查思路是从谁在用倒推到怎么让开。简单的场景某个程序把工作目录设在了/data下面。用lsof找到进程让它切走或者重启就行lsof f -- /data fuser -vm /data更隐蔽的是内核层面的持有比如某个挂载点嵌套在/data下面或者有loop设备关联着上面的镜像文件又或者 NFS 客户端还挂在这个目录下。这种情况可以用findmnt -R /data列出所有相关挂载逐个卸载后再处理外层。实在急着腾地方可以加-llazy umount它会先解绑再等引用归零umount -l /data但我把-l当临时手段不当代替方案。懒卸载之后设备可能还处于半占用状态直接拔出或者格式化非常容易出事。真正要彻底处理还是得找到那个占着不放的进程。4. 开机自动挂载的配置与验证4.1 一份完整的 fstab 示例先给一份我实际在用的 fstab主要分区都用 UUID注释写清楚新手可以直接参照格式替换自己的 UUID。# /etc/fstab # 设备 挂载点 类型 选项 dump fsck UUID3f2a1b4c-...-9e7d / ext4 defaults,noatime 0 1 UUID8a1c2d3e-...-4f6a /boot ext4 defaults,noatime 0 2 UUIDb7e5f9a0-...-1c2b /data xfs defaults,noatime,nofail 0 0 UUIDc1d2e3f4-...-5a6b none swap sw 0 0几个要点/和/boot的最后一个字段分别是 1 和 2保证自检顺序正确/data用 xfs最后的 fsck 字段写 0因为 xfs 有自己的修复工具不参与传统自检swap 分区类型写none选项写sw。4.2 参数是怎么定下来的前面的选项不是拍脑袋定的每一条都有原因。noatime是为了减少无意义写入尤其对 xfs 这种大文件吞吐场景省下的 I/O 很可观。nofail是因为/data在云环境里偶尔会因为块设备挂载顺序问题延迟出现不加它系统开机可能卡住。/data的 fsck 字段写 0是因为它容量大一旦参与开机自检就是灾难级的等待时间。至于挂载点目录一定要提前建好这是新手最容易漏的一步。要么在安装系统时勾选好分区方案要么手动mkdir -p /data否则mount: mount point does not exist这个错会反复出现。目录建好之后属主和权限也要对比如给某个服务专用就chown到对应用户别图省事chmod 777那是给自己挖坑。如果这块盘是不常访问的冷数据盘还可以考虑x-systemd.automount。它的原理是让 systemd 生成一个自动挂载单元开机时不真正挂载等你第一次访问挂载点时才触发真实挂载。这样开机速度更快也避免了某些设备延迟识别导致的问题。UUIDxxxx /archive ext4 defaults,noatime,nofail,x-systemd.automount 0 04.3 改完 fstab务必要做的验证动作fstab 是那种改对了没感觉、改错了系统都进不去的文件。我的习惯是改完立刻验证绝不直接重启赌运气。# 1. 语法级验证把还没挂载的都挂一遍 mount -a # 2. 让 systemd 重新读取挂载单元 systemctl daemon-reload # 3. 确认目标挂载点状态 findmnt /datamount -a会遍历 fstab 里所有auto选项的条目能挂的就挂上。如果某一行写错了它会当场报错并指出是哪一行比开机后进不了系统强太多。这里有个技巧如果只是想测试某一行的正确性可以临时把它做成独立文件用mount --fstab指定避免污染全局配置mount --fstab /tmp/test.fstab -a验证通过之后再合并回/etc/fstab稳妥很多。4.4 fstab 写错导致进不了系统怎么救万一真的写错了开机卡在某种提示界面别急着重装。常见表现有两种一种是提示emergency mode或者You are in emergency mode这时候通常还能输入 root 密码进去另一种是卡在A start job is running for ...转圈等超时。进到紧急模式后第一件事是把根分区重挂为可写mount -o remount,rw /然后编辑 fstab把出问题的那行注释掉或者改对vi /etc/fstab改完mount -a验证一次没问题再reboot。如果连紧急模式都进不去那就需要用安装 U 盘或救援镜像启动chroot到原系统里改 fstab这是最后手段。我个人的防呆做法是改动 fstab 前先cp /etc/fstab /etc/fstab.bak出问题随时能回退成本几乎为零。5. 常见问题与排查技巧实录5.1 一张速查表解决八成问题下面这张表是我从多次实战里攒下来的遇到只读或挂载异常时按现象查命中率很高。现象可能原因解决方向根分区只读日志报 ext4 error元数据不一致备份数据救援环境跑fsck数据盘只读dmesg有 I/O error线缆/坏道/云盘断连检查物理连接换盘位联系云厂商umount报 busy进程占用或嵌套挂载fuser、lsof、findmnt -R定位开机卡在启动提示挂载失败fstab 条目错误或设备缺失紧急模式修 fstab加nofailU 盘/SD 卡只读写保护开关或卡寿命到期检查物理开关换新卡df空间够但写不进去inode 耗尽df -i确认清理小文件挂载后原目录文件消失被挂载点覆盖卸载后可见或换挂载点mount: wrong fs type缺文件系统工具安装对应工具包如xfsprogs5.2 我踩过的几个坑都是血泪第一个坑是拿df -h当唯一依据。早年有台机器应用一直报写入失败我看了空间还剩一大截就怀疑是代码问题查了半天才发现是 inode 用光了。后来我把df -i加进了日常巡检脚本再没犯过。这个坑的教训是空间有两个维度块和 inode缺一不可。第二个坑是在挂载状态下对数据盘跑 fsck。当时觉得只是检查一下应该没事结果fsck直接报了文件系统正在使用我还用-f强行跑最后目录结构被搞得一团糟恢复数据花了两天。从那以后我给自己立了规矩fsck之前必卸载不卸载不 fsck。第三个坑和 fstab 有关。我给一块外置盘写了自动挂载但忘了nofail某次这块盘没插服务器开机后卡在启动等超时远程重连了很久才进去。后来所有非系统必需的挂载点我一律加上nofail开机再没被这种事绊住。第四个坑比较隐蔽是UUID 重复。有一次克隆虚拟机之后没有重新生成 UUID新老机器上的盘 UUID 一样fstab 里指向的盘在克隆机上变成了另一块开机直接把系统盘挂错。这个问题排查起来特别费劲因为表象是乱七八糟的启动错误。虚拟机克隆或者用工具部署镜像后记得检查并重置设备 UUID。5.3 让它别再犯我日常做的几件小事只读和挂载问题七成靠预防。我日常做这几件事成本很低收益很大。监控上我把findmnt的输出接进巡检脚本定时检查关键挂载点是不是还在、是不是还是rw。一旦发现某块盘变只读立刻告警而不是等业务报错。日志上配置journalctl持久化确保重启后还能回溯内核报错不然现场一重启线索全没了。硬件上看到dmesg里出现 I/O error 或者SMART预警别拖该换线换线该换盘换盘等它真挂了再处理代价是数据。还有一条经验值得单拎出来说对重要数据盘不要只依赖文件系统的自愈能力。ext4 的errorsremount-ro是保护机制不是修复机制它只能保证错误不扩散修不了已经损坏的结构。真正靠谱的做法是定期做只读校验、定期演练从备份恢复、关键数据做多副本。我见过太多人把系统还能启动当成数据是安全的这两件事没有必然联系。实际操作这么多年我的体会是Linux 的只读和挂载问题难的从来不是命令本身那几条mount、umount、fsck谁都背得下来难的是现场能不能冷静下来按确认状态、定位原因、评估风险、再动手的顺序走而不是一上来就重启、就强修。把dmesg的第一条报错看进去把 fstab 每一次改动都验证到位把nofail和noatime这种小参数养成习惯你会发现这类问题出现的频率其实能降到很低。真遇到了也不要怕先保住数据再恢复服务最后才是查根因——这个优先级值得在每个运维人心里排在第一。