凌晨两点被电话叫醒说业务服务器写不进日志了登录上去一敲命令屏幕上冷冰冰地回一句Read-only file system——这是我做运维这些年遇到过最能让人瞬间清醒的提示之一。Linux 只读文件系统这个问题表面上看只是盘不能写了实际上它牵扯到内核的容错机制、磁盘硬件健康、/etc/fstab挂载配置、文件系统修复工具、开机挂载时序等一整套东西。磁盘挂载配置写错会导致开机进 emergency 模式硬件坏道会导致内核主动把文件系统切成只读外接 U 盘选项不对会导致中文文件名乱码这些问题的根因可能完全不同但现象都是写不进去。这篇文章我打算把自己这些年踩过的坑和固定的排查套路完整梳理一遍从底层原理讲到可直接抄的fstab配置和巡检脚本。无论你是刚接手几台 CentOS 7.9 的运维新人还是在自己 Ubuntu 桌面上挂移动硬盘的普通用户或者做嵌入式 Linux 开发要处理存储异常都能从这里找到能直接用的东西。1. 只读文件系统不是故障而是内核踩了刹车1.1 先搞清楚只读到底是谁干的很多人第一次遇到这个问题第一反应是我是不是把权限改坏了然后去chmod 777结果当然是没用的因为权限问题和只读挂载是完全两回事。文件系统的挂载状态由内核维护写在超级块superblock的内存副本里与文件权限、SELinux 上下文、用户属主都不在一个层面上。当你执行touch /data/test得到Read-only file system时内核其实是在说这个挂载点当前的挂载标志位里带着ro我拒绝任何写入请求连创建 inode 这一步都不做。所以在动手之前第一件要做的事永远是确认挂载状态而不是去改权限、改属主、重启服务。只读的来源大致分三类第一类是内核主动切的检测到元数据不一致或者底层 IO 报错后自我保护第二类是人为配置的fstab里写了ro或者手工mount -o ro挂的再或者是某些数据卷为了防误改故意设计成只读第三类是硬件层比如 SSD 主控检测到闪存寿命耗尽或者颗粒故障会把自己的写保护锁打开整块盘在系统看来就是只读设备这种情况换文件系统、换挂载参数都没用。区分这三类是解决问题的第一步。1.2 内核为什么要把能写的盘切成只读要理解这个行为得先知道文件系统的元数据有多脆弱。以 ext4 为例每次写入都要先改块位图、inode 表、目录项还要往日志journal里记一笔事务。如果中途底层磁盘返回 IO 错误磁盘上的元数据就可能处于写了一半的状态——块位图说这个块已被占用但 inode 里根本没引用它或者目录项指向一个已经不存在的 inode。这种状态下如果内核继续放行写操作损坏会像雪球一样越滚越大最后整个文件系统彻底没法修。所以 ext4 的默认挂载选项里有一条errorsremount-ro含义就是一旦检测到文件系统级错误立即把该文件系统重新挂载为只读让整个系统停在最后一个相对一致的状态上。这就像高速公路上出了事故交警第一反应是封路而不是让后面的车继续往前冲。xfs 的做法更激进一点默认直接 shut down 文件系统日志里会打印Filesystem has been shut down效果类似。btrfs 在遇到校验和不匹配csum failed时也会转只读因为它的数据块和元数据块都带校验和一旦对不上它宁可停下来也不愿意把坏数据交出去。注意不要因为嫌麻烦就把errorsremount-ro改成errorscontinue。改成 continue 的意思是遇到错误当无事发生继续写在坏盘上这么干基本等于亲手把可恢复的数据变成不可恢复。1.3 三类成因的典型特征对照在大量实际案例里只读问题基本都能归到下面这张表里的某一类。记住这些特征能帮你把排查时间从几小时压到几分钟。成因类别典型现象日志特征处置方向硬件故障单盘只读、SMART 异常、读写速度骤降Buffer I/O error、I/O error, dev sdb、ata3.00: status: { DRDY ERR }先保数据再换盘换线文件系统损坏突然只读fsck报大量错误EXT4-fs error、Corruption detected、csum failed离线fsck/xfs_repair挂载配置重启后必现、所有挂载点一致、新挂的盘日志里无 errorfindmnt显示ro改fstab、重新 remount云盘/网络存储云主机块设备掉线后只读云厂商底层 IO 报错重启实例或重建卷联系云商我再补一条经验如果同一个挂载点在短期内反复变成只读尤其是修完没几天又犯那基本可以断定是硬件层面的问题不要再花时间去研究文件系统参数了直接安排换盘。反过来说如果一台机器上是所有文件系统同时变只读那要优先怀疑挂载配置或者更底层的东西而不是某一块盘坏了。2. 定位根因我雷打不动的五步排查法2.1 第一步确认挂载点和实际生效的选项mount命令的输出在不同发行版上格式略有差异我更喜欢用findmnt它的输出是树状结构一眼就能看出哪个挂载点用了哪个设备、什么文件系统、什么选项。# 看整棵挂载树重点看 OPTIONS 列 findmnt # 只看某个挂载点 findmnt /data # 只输出关心的四列方便脚本处理 findmnt -rn -o TARGET,SOURCE,FSTYPE,OPTIONS # 直接筛出所有只读挂载排除 cgroup、proc 这些虚拟文件系统 findmnt -rn -o TARGET,FSTYPE,OPTIONS | grep -E ext4|xfs|btrfs | grep -w ro这里有个细节findmnt的 OPTIONS 列里如果出现ro说明文件系统确实是只读的但如果看到的是errorsremount-ro那只是说明出错时会切成只读不代表现在已经是只读。这两个字符串极容易看混我刚开始做运维的时候就因为这个绕过一圈冤枉路。另外/proc/mounts和/proc/self/mountinfo是最权威的数据来源findmnt本质上也是在读这两个文件只是帮你格式化了一下。如果你的环境特别精简比如容器的 init 环境里没装 util-linux直接cat /proc/mounts也一样能干活。2.2 第二步从内核日志里捞关键证据只读这件事内核一定会留下痕迹问题只是你有没有去看。dmesg是最直接的工具加上-T参数可以把时间戳转成人能看懂的时间方便和故障发生时间对齐。# 看最近 200 行只读相关的信息通常就在末尾 dmesg -T | tail -n 200 # 关键词过滤一次捞干净 dmesg -T | grep -Ei ext4|xfs|btrfs|I/O error|read-only|remount|failed # systemd 环境下 journal 里也有内核日志而且能跨重启保留 journalctl -k -b | grep -Ei error|fail journalctl -k --since 2 hours ago -p warning下面这张表是我平时最常撞见的几类日志认得它们能省掉大量猜测时间。日志关键字含义下一步动作EXT4-fs (sda1): Remounting filesystem read-onlyext4 已经切成只读往上翻日志找触发它的第一条 errorEXT4-fs error (device sda1): ext4_...ext4 元数据异常离线e2fsckBuffer I/O error on dev sdb1, logical block 1234567块设备层读失败扇区级问题查 SMART准备换盘XFS (sdb1): Corruption detected. Unmount and run xfs_repairxfs 检测到损坏卸载后xfs_repairXFS (sdb1): Filesystem has been shut downxfs 已关停同上需清日志BTRFS error ... csum failed数据校验和不匹配检查内存和盘走 btrfs 修复流程ata3.00: status: { DRDY ERR }硬盘通信层出错常见于线缆或硬盘老化换线、换口再测盘看日志有个诀窍不要只盯着Remounting filesystem read-only这一行那只是结果。要往上看第一条 error它才是真正的起因。我见过太多次只看到 remount 就去跑fsck结果根因其实是内存条故障导致的数据位翻转硬盘本身完全健康。2.3 第三步空间、inode 与进程占用三连查虽然空间不足导致的报错是No space left on device而不是Read-only file system但在实际排查中同时确认这三项能帮你排除掉大量干扰因素尤其是 inode 耗尽这个问题特别容易被忽略——df -h显示还有几十 GB 可用但 inode 早用光了表现和磁盘满一模一样。# 容量和 inode 一起看-T 会显示文件系统类型 df -hT df -i # 找已删除但仍被进程占用的文件磁盘没释放空间的常见原因 lsof L1 2/dev/null | head -n 20 # 看谁占着这个挂载点卸载失败的时候必用 fuser -vm /data lsof D /data 2/dev/null | headfuser -vm这个命令我个人用得非常多。它会把所有访问指定挂载点的进程列出来包括进程号、用户、访问的权限类型。想卸载一块盘却提示target is busy用它基本三秒定位。而lsof L1找的是已被删除但句柄还没关的文件日志切割脚本写得不对、写日志的进程没 reload这种坑在自研服务里非常常见磁盘空间被一个看不见的文件占满重启进程才释放。2.4 第四步判断盘是不是快废了这一条是分水岭。如果日志里出现了I/O error、Buffer I/O error、扇区号那不管fsck能不能修好你都得先确认硬件状态。用smartctl读一下 SMART 信息五分钟的事能帮你避免修完三天又坏的循环。# 装 smartmontoolsCentOS / Ubuntu 都一样 yum install -y smartmontools # CentOS 7.9 apt install -y smartmontools # Ubuntu / Debian # 整体健康状态 smartctl -H /dev/sda # 关键属性 smartctl -A /dev/sda | egrep Reallocated|Pending|Uncorrect|CRC|Wear|Temperature # 最近的错误记录 smartctl -l error /dev/sda # NVMe 盘用这个 nvme smart-log /dev/nvme0几个必须记住的 SMART 属性我按重要程度排一下属性 ID名称我的判断标准197Current_Pending_Sector只要非 0说明有扇区读不出来立刻重视198Offline_Uncorrectable非 0 强烈建议直接换盘5Reallocated_Sector_Ct非 0 就要持续观察快速增长就是死刑187Reported_Uncorrect有任何数值基本可判盘有问题199UDMA_CRC_Error_Count持续增长说明 SATA 线缆或接口问题231 / 233SSD 剩余寿命低于 10% 就该列入更换计划提示smartctl -H返回 PASSED 不代表盘一定没问题。SMART 的阈值是厂商设的往往要到非常严重才会报 FAILED。真正有价值的是看属性值的变化趋势所以我建议把smartctl -A的输出定期存档前后对比才有意义。2.5 第五步回头检查挂载配置和人为操作如果日志干净、SMART 正常、容量和 inode 都没问题那就要往配置上想了。先看fstab里有没有ro再看有没有人手工 remount 过。# 排除注释行看有效配置 grep -vE ^\s*#|^\s*$ /etc/fstab # 看最近的登录和命令历史需要 root last | head -n 10还有一种很隐蔽的情况某些自动化运维脚本或者监控 agent 在检测到异常时会主动执行mount -o remount,ro把盘保护起来。这种善意的操作会让现象变得很诡异因为内核日志里什么错误都没有。遇到排查不通的情况可以检查一下 crontab 和 systemd timer 里有没有类似的脚本。3. 应急恢复先救业务再查病因3.1 remount,rw 什么时候管用什么时候白搭掌握排查手段之后到了现场往往没时间慢慢分析业务在报错第一诉求是先让它能写。这时候最直接的手段是重新挂载为可写# 把指定挂载点重新挂成读写 mount -o remount,rw /data # 根分区同理前提是内核允许 mount -o remount,rw /这条命令的成功率取决于只读是怎么来的。如果是人为挂成只读或者fstab里写了ro那它百分之百成功秒级恢复。但如果是内核因为检测到错误主动切的只读那大概率会失败或者表面上成功、几秒后又变回只读。原因在于 ext4 在超级块上打了一个错误标志位EXT4_ERROR_FS只要这个标志还在内核就不允许恢复可写必须先做一次完整性检查把它清掉。所以我的建议是先尝试 remount成功了就赶紧恢复业务但要马上安排计划内停机做fsck。因为内核既然报过错就说明有不一致的可能性带着隐患继续跑风险很高。如果 remount 失败别硬试第二次第三次直接准备停机走修复流程。3.2 根分区只读是最麻烦的情况根分区只读和普通数据盘只读完全是两个难度等级。数据盘只读你卸载、检查、重挂业务可能只是短暂中断。根分区只读你连fsck都不能在线跑而且很多服务会因为写不了 PID 文件、写不了日志而直接起不来。常见的处置路径有这么几条我按推荐顺序排第一条是进入 rescue 模式。systemd 系统上执行systemctl rescue它会切到单用户救援 target。但要注意如果你的根分区是因为文件系统错误被切只读的rescue 模式未必能帮你自动改成可写还是得看内核态度。第二条是在 GRUB 里给内核命令行加参数。fsck.modeforce让启动时强制执行文件系统检查fsck.repairyes让它自动修复这两个参数组合起来对根分区只读且系统还能启动的情况很有效。Debian 系还有一个老办法是touch /forcefsck重启后会触发一次全盘检查。第三条是用 Live 介质或救援模式启动从外部挂载这块盘做离线检查。这是最稳妥的方式因为文件系统处于完全未被挂载的状态修复工具能访问所有元数据。云主机的话把系统盘卸载挂到另一台机器上处理思路完全一样。注意根分区修复之前能备份的先备份。尤其是/etc目录很多人的服务器配置根本没有版本管理一旦修复过程中出岔子重装系统容易找回那堆手工改过的配置能让人崩溃。3.3 fsck 和 xfs_repair不同文件系统不能乱用这是新手最容易踩的坑之一xfs 文件系统绝对不能用 fsck。在 CentOS 7.9 这类默认使用 xfs 的系统上如果你习惯性地fsck /dev/sda1那只是在做无害的空转它不会真正检查 xfs。正确的工具是xfs_repair。# 1. 先卸载 umount /data # 如果提示 target is busy先找占用进程 fuser -vm /data lsof D /data | head # 2. ext4 / ext3 修复 e2fsck -f -y -C 0 /dev/sdb1 # -f 强制检查即使标记为 clean # -y 全部自动回答 yes # -C 0 显示进度 # 3. xfs 修复 xfs_repair -v /dev/sdb1 # 如果提示日志脏log is dirty且你确认可以丢弃最近未落盘的数据 xfs_repair -L /dev/sdb1不同文件系统对应的修复工具和注意事项我整理成一张表遇到的时候直接查文件系统修复工具是否必须卸载备注ext2/3/4e2fsck根分区需离线或在启动时最成熟的工具成功率最高xfsxfs_repair必须卸载不能用 fsck-L清日志会丢最近数据慎用btrfsbtrfs check --repair必须卸载官方文档明确提示此命令有风险vfatfsck.vfat必须卸载修不了就重建U 盘数据价值低exfatfsck.exfat必须卸载内核 5.4 原生支持 exfatntfsntfsfix必须卸载只能做最小修复彻底修还是得靠其他平台工具xfs_repair -L这个参数我要特别说一下。它会清空日志代价是丢失日志里尚未落盘的事务。什么时候必须用当xfs_repair自己报告日志损坏、无法重放的时候。什么时候不该用只是泛泛地为了修得更干净而加-L那是在白扔数据。我的原则是先不加-L跑一遍跑不动了再考虑。3.4 修完之后必须做的两件事第一件是挂载验证并盯日志。mount /data之后立刻dmesg -T | tail -n 30看有没有新的 error 冒出来。有些盘修完能挂上但一挂上就接着报错这说明损坏还在持续产生根因没解决。第二件是加监控观察期。至少观察一周重点看是否复发、SMART 属性有没有继续恶化。修完三天又坏的盘基本可以判定硬件有问题不要再浪费时间在文件系统上了。顺便说一句如果这块盘上跑的是数据库修复之后最好用数据库自带的校验工具再验证一遍数据文件文件系统层能挂载不代表数据文件本身是完整的。4. 磁盘挂载配置90% 的莫名只读来自 fstab 写错4.1 fstab 六个字段一个都不能含糊/etc/fstab每一行有六个字段用空格或 Tab 分隔。很多人只照着网上的教程抄过前四列后两列随手写 0 0其实每一列都有明确含义。列号名称示例说明1设备UUID8b1a8c0e-...强烈建议用 UUID 或 LABEL2挂载点/data目录必须已存在fstab 不会替你创建3文件系统类型ext4/xfs/vfat要和lsblk -f的输出一致4挂载选项defaults,noatime,nofail逗号分隔不带空格5dump 备份标志0现代系统基本恒为 06开机检查顺序2根分区写 1其他写 2不检查写 0第五列和第六列特别值得说。第六列如果写 2启动时 systemd-fsck 会检查这个文件系统如果这块盘很大比如 20TB 的机械盘检查可能长达几十分钟服务器启动就会卡在那里。所以对于纯数据盘、尤其是大容量盘很多人会写 0 跳过开机检查把检查放到业务低峰期手工做。这是个权衡不是绝对的取决于你对数据安全的要求。4.2 为什么不能用 /dev/sdX 而要用 UUID设备名/dev/sda、/dev/sdb是内核在探测设备时按顺序分配的。同一块硬盘插在主板不同的 SATA 口上设备名可能就变了加装一块新硬盘原来的sdb可能变成sdc某些主板和硬盘的初始化速度有差异重启几次设备名就漂移了。如果fstab里写的是设备名某次设备名一变轻则挂载失败重则把错误的盘挂到错误的挂载点上——比如把备份盘挂到数据库数据目录上直接覆盖掉真实数据这种事故的破坏力远超只读问题。# 查看所有块设备的文件系统类型、UUID、挂载点 lsblk -f # 单独查某一块分区的 UUID 和 LABEL blkid /dev/sdb1拿到 UUID 之后fstab里就这么写UUID你的UUID /data ext4 defaults 0 2。有极少数场景会用 LABEL比如批量部署时每块盘都做同样的标签但 LABEL 有重名风险相比之下 UUID 更保险。4.3 挂载选项逐条拆解按需取用defaults是绝大多数教程默认给的选项但它其实是个缩写等价于rw,suid,dev,exec,auto,nouser,async。也就是说defaults里已经包含了rw你不用再额外写一遍。常用选项和它们的实际作用选项作用适用场景defaults上面那七个选项的集合普通数据盘noatime不更新文件的访问时间几乎所有场景减少写放大nodiratime不更新目录的访问时间和 noatime 搭配nofail设备不存在时不影响开机外接盘、可移动设备必加x-systemd.device-timeout10等待设备超时时间改为 10 秒配合 nofail避免开机卡 90 秒ro只读挂载数据卷防误改、备份盘umask/uid/gid权限映射vfat、exfat、ntfs 必须用iocharsetutf8文件名编码外接盘中文名乱码时用对 SSD 我还想多说一句discard。这个选项让文件系统在删除文件时立即通知 SSD 主控回收闪存块但它的副作用是删除操作变慢而且部分老 SSD 上有性能抖动。我更推荐的做法是不加 discard改用 systemd 的 fstrim.timer 定期批量 TRIM每周跑一次就够了对性能影响小得多。Ubuntu 和 CentOS 7.9 上都可以直接systemctl enable --now fstrim.timer开起来。关于iocharset和中文乱码顺便把一个高频混淆点讲清楚。外接 U 盘挂载后文件名变成问号或者乱码这是挂载编码的问题vfat用utf8或iocharsetutf8、codepage936一般能解决。但如果你是在 Linux 上解压 Windows 打包的 zip 文件文件名出现乱码那和挂载一点关系都没有纯粹是 zip 工具默认用 CP437 解析文件名导致的解决办法是用unzip -O cp936 文件名.zip指定编码或者换成7z x 文件名.zip、bsdtar -xf 文件名.zip。这两类乱码经常被混为一谈排查方向完全不一样。一个完整的 Ubuntu 桌面挂载移动硬盘的例子# /etc/fstab UUID1234-ABCD /mnt/usb vfat utf8,umask0000,uid1000,gid1000,nofail,x-systemd.device-timeout10 0 0 UUID5678-EFGH /mnt/ntfs ntfs3 uid1000,gid1000,umask022,windows_names,noatime,nofail 0 0windows_names这个选项值得单独提一下它会拒绝创建 Windows 不接受的非法文件名比如带:或*的避免以后把盘插回 Windows 时出现莫名其妙的问题。4.4 外接盘开机挂载的时序坑外接 USB 硬盘开机自动挂载最典型的翻车场景是这样的fstab里老老实实写了一行没加nofail某天硬盘没插、或者接触不良、或者 USB 控制器初始化比较慢systemd 的local-fs.target就会一直等默认等待 90 秒后进入 emergency 模式变成只有一个 shell 的救援界面。普通桌面用户看到这个界面基本就懵了以为是系统坏了。解决办法就两个选项一起加nofail,x-systemd.device-timeout10。前者告诉 systemd 这块盘可以不存在后者把等待时间从 90 秒压到 10 秒。加了之后硬盘插着就正常挂载没插就是一个空目录开机顺畅。改完fstab之后不要直接重启验证先用这两条命令做静态检查能避免绝大多数翻车# 让 systemd 重新读取 fstab systemctl daemon-reload # 校验 fstab 语法会指出有问题的行需要 util-linux 2.30 findmnt --verify --fstab # 模拟挂载所有 fstab 条目已经挂载的会跳过 mount -amount -a有个特性要记住它不会自动创建挂载点目录。如果目录不存在它会报mount point does not exist然后失败。所以新加一条挂载配置第一件事是mkdir -p /data。另外mount -a是幂等的已经挂载的条目通常会被跳过不会重复挂。4.5 挂载点覆盖一个经典到不能再经典的坑这个坑和只读无关但破坏力极大而且很多人第一次遇到会以为是数据丢了。场景是你把一块新盘挂到/data而/data目录里原本有一些文件。挂载完成之后那些文件消失了。实际上它们还在原分区上只是被新的挂载点覆盖了umount /data之后就能重新看到。应对方法很简单所有挂载点目录创建时保持为空不要往里面放任何东西。如果业务代码必须往挂载点根目录写东西那也是写到挂载之后的文件系统里而不是挂载之前。我见过有人把 web 站点根目录/var/www挂载到新盘然后原来的首页文件被覆盖排查了半天以为是权限问题。4.6 挂载之后还是写不进去先分清三种不能写排除掉只读挂载之后写不进去还有另外两种常见原因它们的报错不一样别混在一起查。第一种是权限问题报错是Permission denied需要检查目录属主、属组、权限位以及挂载选项里的 uid/gid/umask 映射——对 vfat 这类没有原生权限概念的文件系统内核是按挂载选项统一映射权限的你在盘上chmod根本没效果。第二种是 SELinuxCentOS 7.9 默认开启新挂载的盘继承的上下文不对服务进程就是访问不了报错同样是Permission denied但ls -Z一看上下文就知道问题在哪用restorecon -Rv /data或者semanage fcontext修正即可。判别的顺序我固定成这样先看findmnt是不是ro再看ls -ld的权限位最后看ls -Z的上下文。三步走下来基本不会漏。5. 高频报错速查表与实战清单5.1 报错原文对照表下面这张表是我这些年攒下来的横跨 CentOS 7.9、Ubuntu 和各类嵌入式环境。遇到报错直接搜关键词比翻文档快得多。报错或现象最可能的根因处置方法Read-only file system内核检测到错误自动切只读findmntdmesg定位离线fsckmount: wrong fs type, bad option, bad superblock文件系统类型写错、驱动没装lsblk -f核对类型装 ntfs-3g / exfat 驱动mount: unknown filesystem type ntfs内核不认、缺少驱动装ntfs-3g或用-t ntfs3mount point does not exist挂载点目录没建mkdir -p后重试target is busy有进程正在占用fuser -vm找进程或umount -l延迟卸载Structure needs cleaningxfs 元数据损坏卸载后xfs_repairFilesystem has errors, check forcedext4 标记为需要检查e2fsck -f -yUNEXPECTED INCONSISTENCY; RUN fsck MANUALLY开机自检失败进 emergency手动fsck后重启开机进 emergency modefstab 有错或设备不存在加nofail检查 UUID外接盘中文文件名乱码挂载编码不对加utf8或iocharsetutf8No space left on device但df -h还有空间inode 耗尽df -i确认清理小文件磁盘空间不释放删除的文件被进程占用lsof L1找出进程并重启SMART overall-health: FAILED硬盘硬件故障立即备份数据换盘SSD 突然只读且不可恢复主控写保护锁触发只读拷出数据盘报废5.2 我在现场固定执行的排查清单写到这里把流程固化成一份可以照着敲的清单。我通常会在脑子里跑一遍新手的话建议对着敲敲两次就记住了。findmnt /目标挂载点确认 OPTIONS 里是不是ro区分是挂载问题还是内核问题。dmesg -T | tail -n 200往上看第一条 error别只看 remount 那一行。journalctl -k --since 2 hours ago确认日志在重启前的记录如果需要。df -hT和df -i排除容量和 inode 问题。smartctl -H和smartctl -A判断是不是硬件故障这一步决定后续策略。试mount -o remount,rw成功则临时恢复业务同时安排停机检查。remount 失败则走离线修复卸载、e2fsck或xfs_repair、重新挂载、观察日志。修复后grep -vE ^#|^$ /etc/fstab检查配置里有没有ro或错误的 UUID。findmnt --verify --fstabmount -a确认配置正确。加监控观察一周。6. 预防让只读问题尽量别发生6.1 一个可以直接用的巡检脚本与其等出事了再排查不如每天跑一次巡检把只读状态、容量水位、inode 水位和 SMART 健康都记下来。下面这个脚本我用了很久依赖util-linux、smartmontoolsCentOS 7.9 和 Ubuntu 上都能直接跑。#!/bin/bash # 文件/usr/local/bin/fs_check.sh # 用途巡检文件系统只读状态、容量水位、inode 水位与磁盘健康 LOG/var/log/fs_check.log TS$(date %F %T) # 1. 检查已挂载的本地文件系统 findmnt -rn -o TARGET,SOURCE,FSTYPE,OPTIONS | while read -r target source fstype options; do case $fstype in ext2|ext3|ext4|xfs|btrfs) ;; *) continue ;; esac # 只读检测 if echo ,$options, | grep -q ,ro,; then echo $TS [RO ] $target ($source) 处于只读挂载 $LOG fi # 容量与 inode 水位 used$(df -P $target 2/dev/null | awk NR2{gsub(%,,$5); print $5}) iused$(df -Pi $target 2/dev/null | awk NR2{gsub(%,,$5); print $5}) [ -n $used ] [ $used -gt 90 ] echo $TS [USE ] $target 容量使用率 ${used}% $LOG [ -n $iused ] [ $iused -gt 85 ] echo $TS [INODE] $target inode 使用率 ${iused}% $LOG done # 2. 磁盘 SMART 健康检查 lsblk -dn -o NAME,TYPE | awk $2disk{print $1} | while read -r disk; do health$(smartctl -H /dev/$disk 2/dev/null | grep -Ei overall-health|SMART Health Status) echo $health | grep -qi passed \ || echo $TS [SMART] /dev/$disk 健康异常${health:-无法读取} $LOG done挂到 crontab 里每天跑一次同时配上 logrotate 防止日志把盘占满# crontab -l 30 7 * * * /usr/local/bin/fs_check.sh # /etc/logrotate.d/fs_check /var/log/fs_check.log { weekly rotate 8 compress missingok notifempty create 0644 root root }脚本有两个设计上的取舍我想说明一下。第一它只检查ext、xfs、btrfs这几类本地文件系统因为网络挂载和虚拟文件系统的 OPTIONS 里出现ro是正常现象纳进来会产生大量误报。第二容量阈值定在 90%、inode 定在 85%看似提前量不大但这两个数字是我在实际环境里调过几轮的结果——定得太低比如 70%会产生大量无意义告警运维看多了就会自动忽略反而失去了告警的价值。6.2 告警阈值怎么定才不会被忽略巡检脚本产出的是日志日志没人看等于没写。真正起作用的是告警而告警的核心不是技术是阈值设计。我的经验是分两档只读状态和 SMART 异常走最高优先级立刻通知因为这两个基本没有误报出现了就是真事容量和 inode 走低优先级每天汇总一次超过阈值才提醒避免半夜被无关告警吵醒。只读告警的实现可以直接在脚本外面套一层判断[RO ]出现就把日志用邮件或 webhook 推出去。我见过有人做的更精细用inotify盯着关键目录不能写就告警思路也不错缺点是容易漏掉那些不常写入的目录。6.3 备份策略才是最终保险再好的巡检也挡不住盘突然暴毙。我个人的习惯是分三层重要数据用 rsync 定期同步到另一台机器注意是另一台机器不是同一台机器的另一块盘因为同一台机器的电源和控制器是共享的一起出问题的概率不低系统盘用整盘镜像工具做周期性备份开源方案里再生龙这类工具做离线整盘镜像是很成熟的路子把它做进 U 盘启动盘定期跑一次出问题直接还原关键业务卷用 LVM 快照或者文件系统快照做升级、改配置这类高风险操作前先打一个出问题回滚只要几分钟。有一点特别提醒备份盘千万不要用和源盘同型号、同批次、同一天出厂的硬盘。硬盘的故障率曲线和使用时间高度相关同批次盘经常在同一时间窗口集体出问题这种一起坏的情况在小型机房里并不罕见。6.4 一个我不推荐的野路子网上偶尔能看到有人讨论用内核模块动态加载file_operations来拦截 read 和 write实现所谓的数据保护或者审计。我明确不建议在正经环境里这么干。原因很实在文件系统的读写路径不止一条普通 read/write 系统调用只是其中之一还有 mmap 内存映射、直接 IOO_DIRECT、以及各种内核内部的回写路径。你在某个入口挂上钩子其他入口照样能绕过去结果就是内核认为数据写下去了磁盘上的实际内容却不一样元数据一致性被破坏最后触发只读保护的几率会明显上升——你想防的没防住反倒制造了新故障。真要做文件层的审计用 fanotify、inotify 这类官方提供的机制或者内核自带的审计子系统稳定性有保障也不会和文件系统打架。文件系统这块按设计用法用永远是最省心的选择。我个人在实测中比较深的体会是只读文件系统这类问题真正花时间的地方从来不是敲命令而是判断这盘还能不能救。日志、SMART、修复工具这三样东西凑齐判断基本就有底了。至于那些配置层面的坑nofail加 UUID 这两条记住了能挡掉日常八成的挂载故障。