上周半夜两点多,值班手机响了:有个同事的测试环境突然全面挂掉,登录上去一看,整个系统盘变成了只读。touch /tmp/test 直接回一句 Read-only file system,但机器没死,ping 也通,SSH 照样能登进去。这种「能看不能写」的状态最让人抓狂,因为你会下意识地以为是自己某个服务把权限改了,甚至去折腾 chattr、去改 mount 参数,绕了一大圈,真正的原因其实早就写在 dmesg 里了。
这事的本质是 EXT4 的保护机制:当内核在这个文件系统上发现某些「再写下去可能扩大损坏」的信号时,会主动把整个文件系统重挂载成只读,用来阻止你继续往一块可能有硬件问题的盘上写数据,防止一个坏道被反复覆盖成更大的数据丢失。理解这个机制,你才明白「只读」不是故障本身,而是内核给你下的最后通牒。
如果你正打算给服务器配一块大容量的数据盘,或者需要一台能扛住全天候写入的机器,这两家可以先看看配置和技术说明:raksmart(全球云服务器,独立服务器与裸金属方案)、100tb(企业级大容量存储云平台)。文件系统能不能扛住,主要还是看底层盘的稳定性和机房环境,选机器的时候把这块提前考虑进去,比出事后再抢救省事得多。

一、先定位:是文件系统只读,还是整台机器只读
第一条命令永远是 mount | grep ' / ',看根分区的挂载参数里有没有 ro。如果输出里是 rw,那说明内核层面还是可写的,只读是某个具体分区或者某个挂载点的事,比如某个数据盘被单独设了 ro。
第二条命令是 dmesg -T | grep -iE 'remount|read-only|I/O error|EXT4-fs error'。这一步是全文最关键的。如果你在 dmesg 里看到了 EXT4-fs (sda1): re-mounted. Opts: errors=remount-ro 这类字样,那结论就明确了:EXT4 自己把根分区降级成了只读。
第三条命令确认内核参数有没有开自动修复:cat /sys/fs/ext4/sda1/errors_policy。这个值如果是 remount-ro,就是默认行为;如果你在排查期间把它临时改成 continue 让机器继续跑,那只是止血,不是治病,改完记得改回去。

二、EXT4 到底在什么情况下会触发 remount-ro
要理解触发条件,得先知道 EXT4 默认挂载参数里那个 errors=remount-ro 的含义。它的作用很直白:EXT4 在遇到自己无法安全处理的错误时,把文件系统降级为只读。常见的触发来源有这么几类:
1)journal 提交失败。EXT4 的日志(journal)默认放在同一个块设备上。日志是元数据操作的事务保证,一旦某个日志事务提交失败,文件系统就无法保证一致性。这时 EXT4 会拒绝继续写入,直接降级只读。这通常伴随 EXT4-fs error (device sda1): jbd2 commit transaction failed 或者 JBD2: commit transaction failed 之类的日志行。
2)块设备层面的 I/O 错误。就是内核报 blk_update_request: I/O error、Buffer I/O error on dev sda1 这类。这类信号往往是硬盘本体、RAID 卡、或者线缆的问题。EXT4 只是「看见了 IO 错误」,但它不知道这些错误是零星的还是致命的,所以保守起见先把整个文件系统锁住。
3)孤儿 inode / inconsistent 状态无法自动修复。某些情况下内核发现文件系统结构不一致且无法在运行态修复(比如 orphaned inode、inode checksum failure),也会触发降级。
这里有个容易误判的点:remount-ro 是结果,不是原因。它只是把「盘可能已经坏了」这件事用最醒目的方式告诉你。如果你只把文件系统重新挂载成 rw 然后继续跑,那基本等于在坏道上继续写数据,小问题会被放大成整盘报废。真正要做的是往下看内核日志,找那条最早出现的错误它才是根因。

三、正确姿势:先备份,再卸载,再 fsck
确认盘还在、错误只是逻辑层面之后,修复流程其实很标准,但顺序绝对不能错。
第一步,能读就先抢救数据。文件系统的元数据可能已经不一致,但绝大部分文件内容其实还在。如果这台机器上还有业务,先用 mount -o ro,noload /dev/sda1 /mnt/rescue 挂一个只读且不加载 journal 的副本出来,把重要的东西 cp 走。注意是 noload,它能让你在不修复的情况下读取数据,避免挂载动作本身进一步写坏元数据。
第二步,务必 umount 干净。对正在使用的文件系统直接跑 fsck 是很危险的操作,fsck 会重写超级块和 inode 链表,在挂载状态下跑等于拿着正在使用的账本改账。确认 mount | grep sda1 没有结果再动手。如果这台机器是根盘所在,只能进 rescue 系统或者用 LiveCD 挂载后再修。
第三步,跑 fsck。EXT4 的正确姿势是先修日志,再修文件系统本体:
e2fsck -f -y /dev/sda1
如果报出来是 journal 相关的错误,先单独修复日志:e2fsck -f -E journal_only /dev/sda1,然后再跑一次完整的 e2fsck -f -y /dev/sda1。文件系统如果当初是用 mke2fs 创建的,也可以用 e2fsck -f -y -t ext4 /dev/sda1 明确指定类型。
第四步,修完别急着重启服务。挂载回去之后先做一次写入验证:mount /dev/sda1 && touch /mnt/test && dd if=/dev/zero of=/mnt/test bs=1M count=100 oflag=direct,确认没有 IO 错误再让业务起来。如果 fsck 报告了大量 inode 错误、或者报 UNEXPECTED INCONSISTENCY 并且修完还反复出现,那基本可以判定是硬盘本体的物理故障,直接换盘,不要再折腾了。

四、把这些坑提前堵上
最后聊几个能减少下次痛苦的实践。第一,重要数据不要只依赖文件系统自身的 journal,journal 只能保证一致性,保证不了持久性。核心数据该做快照还是做快照,该异地还是异地。
第二,给数据盘做定期的 e2fsck 巡检不如做好监控。smartd 对 SATA/SAS 盘的 attribute 5(重分配扇区数)、attribute 197、attribute 198 变黄,基本就是明确的换盘信号。EXT4 的 EXT4-fs 内核日志和 mdadm 的 mdmonitor 告警也都该接进你的告警通道,别等业务来投诉。
第三,errors=remount-ro 这个默认值别乱改。有些人为了让机器「不要因为一点小错就挂掉」,把 errors_policy 改成 continue,结果文件系统带着元数据不一致继续跑,写出一堆半截文件,问题排查起来比重装还痛苦。默认值是内核工程师权衡出来的保守策略,别自作主张改。
第四,服务器上如果部署了容器,Docker 的 overlay2 目录会因为文件系统只读而直接让容器写不进日志甚至起不来,报错还特别有迷惑性。遇到「容器莫名退出 + 宿主机某个目录变只读」这种组合,第一反应应该是去 dmesg 里翻 EXT4 的错误,而不是去查镜像。
说到底,EXT4 变只读这件事本身并不复杂,复杂的是它在几天前就悄悄埋下了伏笔。把 dmesg 纳入日常巡检、把 SMART 数据接进监控、在有条件的地方用 Ext4Explore 这类工具在另一套环境里核对分区内容,你会发现绝大多数「突然只读」,其实早就有预告了。



下载 
下载 
下载
下载
下载 
下载
喜欢
顶
难过
囧
围观
无聊



