简介:这份 docx 文档聚焦 Linux 多服务器环境中的共享存储挂载故障,面向运维工程师、系统管理员以及正在学习存储管理的读者,围绕同一存储设备挂到两台服务器后出现一台无法挂载或提示“存储正忙”的典型问题展开。内容从设备文件、设备映射与挂载机制入手分析冲突成因,并给出借助 dmsetup 清理映射后重新挂载的排错思路,同时延伸到快照、克隆与镜像等 Device-Mapper 管理用法,帮助读者建立从现象定位到命令验证的完整排查路径。压缩包共 1 个 docx 文件,约 11KB,篇幅精炼,适合作为日常运维排障时的速查笔记,也可用于补充共享存储冲突、dmsetup 命令实践与存储管理知识框架,便于按问题现象快速检索对应思路。已有 1650 人学习或下载,适合需要快速了解共享存储冲突处理与 dmsetup 基本用法的读者参考。
1. 共享存储“存储正忙”:一个反直觉的真相
两台服务器挂同一块存储,一台宕机后,另一台执行mount却报device is busy,甚至设备节点还在、容量也在,就是挂不上。很多人的第一反应是文件系统坏了,于是fsck一路跑下去;或者怀疑链路、HBA、多路径。但真正卡住的,往往是内核里那层看不见的“映射表”——设备已经不可达,Device-Mapper 的映射项却还挂着,I/O 全部阻塞在队列里。这就是存储运维里典型的玄学现场。搞懂它,比记住任何一条命令都值:你能判断该清映射、该重启服务,还是该先摘链路,而不是靠dmsetup remove_all碰运气。
2. Device-Mapper 的分层:/dev/sda和挂载点之间到底隔了什么
2.1 从块设备到文件系统,中间是一个可插拔的映射层
很多人把/dev/sda理解成“磁盘本身”,其实在多数生产环境里,它只是最底层的物理或虚拟块设备,上面还叠着 Device-Mapper(下文简称 DM)这层。DM 是 Linux 内核的一个块设备映射框架,LVM、多路径(multipath)、dm-crypt、dm-snapshot 全都建在它上面。它做的事很纯粹:接收上层(文件系统)发来的 bio,按映射表把逻辑地址翻译成底层设备地址,再转发下去。
所以一条 I/O 的真实路径是:应用 → 文件系统 → DM 逻辑设备(如/dev/dm-0)→ 映射表 target(linear / multipath / snapshot)→ 底层块设备 → 存储。文件系统眼里的“一块盘”,其实是 DM 临时拼出来的逻辑视图。问题就出在这里:文件系统只认 DM 设备,而 DM 映射的生命周期和底层存储的可用性并不同步。底层断了,映射还在,就成了一个“指向空气”的设备节点。
这里有个容易被忽略的细节:/dev/dm-N是内核动态分配的编号,每次加载映射都可能变,真正稳定的标识是/dev/mapper/<name>这个符号链接。排查时如果盯着/dev/dm-0看,重启一次顺序就全乱了,血泪经验。
2.2 映射表项的生命周期:谁创建、谁持有、谁释放
一条 DM 映射从生到死有几个明确阶段,理解它才能理解为什么“删不掉”:
| 阶段 | 触发动作 | 内核状态 |
|---|---|---|
| 创建 | dmsetup create/lvcreate/ multipath 自动 | 映射表写入,/dev/dm-N出现 |
| 激活 | dmsetup resume | 开始接受 I/O,队列可下发 |
| 挂起 | dmsetup suspend | 队列冻结,新 I/O 排队等待 |
| 移除 | dmsetup remove | 引用计数归零后释放 |
| 强制移除 | dmsetup remove -f | 标记 deferred,等引用释放 |
关键在“引用计数”。只要还有文件系统挂载、还有进程持有该设备的文件描述符、还有未完成的 I/O 在队列里,remove就会被拒绝,报Device or resource busy。这跟删除一个正被打开的文件是同一个道理:内核不允许你抽掉别人脚下的地板。而remove_all做的事,就是遍历所有映射逐个尝试移除——它不是“万能钥匙”,只是把“逐个 remove”批量化了。
3. 两台服务器抢同一块存储:为什么一台挂了另一台就“正忙”
3.1 非集群文件系统的独占假设被打破了
ext4、xfs 这类本地文件系统有一个隐含前提:这块块设备只有我一个使用者在写。它们会在挂载时往设备上写日志区(journal)、维护超级块、缓存元数据。两台服务器同时挂载同一个非集群文件系统,等于两个人同时改同一份账本,元数据迟早对不上,轻则报错,重则整块存储的结构被写坏。
注意:这不是“Linux 的限制”,而是文件系统自己的并发模型决定的。要真正多机共享,得换集群文件系统(如 OCFS2、GFS2)或走 NFS/SMB 这类网络文件系统,由服务端做串行化。把 ext4 挂两台机器上,本质上是在用一个不支持并发的协议做并发,翻车是时间问题。
3.2 一台宕机后,残留的映射和未完成的 I/O 才是元凶
真正的现场往往是这样:服务器 A 正常挂载使用,服务器 B 也通过多路径看到了同一块 LUN。A 突然宕机(断电、内核 panic、链路断),A 上的 DM 映射没来得及清理,未完成的 I/O 还压在队列里;同时 B 侧的多路径发现某条链路失败,尝试切换路径或重新认设备,于是报“存储正忙”。
从 B 的视角看,它并没有主动占用什么,但底层存储可能还保留着 A 的 reservation(SCSI-3 PR,持久化预留),或者阵列侧认为这条路径仍被 A 持有。这时候光在 B 上dmsetup remove_all是不够的——你得先确认 A 确实不会再回来了,再去阵列侧清掉预留,否则 B 强行接管只会引发更严重的脑裂(split-brain)风险。
提示:判断“A 是否真的死了”,不能只看 ping。要看存储阵列的会话表、FC/iSCSI 登录状态、以及 PR 预留持有者。网络不通不等于主机宕机,链路抖动也会造成同样的表象。
3.3dmsetup remove_all到底做了什么
把这条命令拆开看,它等价于对/dev/mapper下每个映射执行一次dmsetup remove,遇到 busy 就跳过并报错。源码层面,它走的是 DM 的 ioctl 接口DM_DEV_REMOVE,内核在dm_destroy()路径里检查md->open_count和md->holders,非零就返回-EBUSY。所以它从来不是“强删”,只是一个批量尝试。
# 查看当前所有 DM 映射及其依赖关系 dmsetup ls --tree # 树状展示,能看出谁依赖谁 dmsetup info -c # 列出所有映射的状态、打开数 dmsetup table <name> # 查看某个映射的 target 表,确认底层设备 # 逐个安全移除(推荐顺序:先上层后底层) dmsetup remove <name> # 正常移除,busy 会失败 dmsetup remove -f <name> # 强制标记删除,等引用释放后生效 # 批量移除(谨慎,遇到 busy 会跳过并报错) dmsetup remove_alldmsetup info -c输出里的Open计数是判断能否移除的第一手依据:只要不是 0,remove必然失败,remove -f也只是挂起等待。--tree则能告诉你移除顺序,先摘 snapshot 再摘 origin,顺序反了同样会 busy。代码后面的这层逻辑,比命令本身重要得多。
4. 从表象到根因:一套可复现的排查路径
4.1 先定位“忙”在哪一层
排查要自下而上,别一上来就动映射。第一步看块设备层:lsblk能看到设备树和挂载点;multipath -ll能确认多路径聚合状态和每条 path 的failed/active;dmsetup ls --tree确认 DM 层结构。三者对照,就能判断“正忙”是卡在多路径、DM 映射,还是文件系统挂载残留。
第二步看持有者:fuser -vm /mountpoint找占用进程,lsof找打开的文件描述符,/proc/mounts确认是否有残留挂载项(有时mount报错但条目已写入)。第三步看内核日志:dmesg -T | grep -i -E "dm-|multipath|scsi|reservation",I/O error、path down、PR conflict 都会留痕,这是最不会骗人的黑匣子。
4.2 清理残留映射的正确顺序
确认没有活跃 I/O 之后,顺序是:卸载文件系统 → 停多路径服务(或multipath -f <mpath>刷掉路径)→dmsetup remove逐层删映射 → 必要时dmsetup remove_all兜底。如果卸载时报 busy,先fuser -km杀掉占用进程(生产环境慎用),再umount -l惰性卸载,等引用释放。
# 典型清理脚本,每步都要确认返回码 umount /data 2>/dev/null || umount -l /data # 卸载,失败则惰性卸载 multipath -f mpatha 2>/dev/null # 刷掉指定多路径设备 dmsetup ls --tree # 确认剩余映射 dmsetup remove_all 2>&1 | tee /tmp/dm_remove.log # 批量移除并留日志 dmsetup ls # 验证是否清空顺序颠倒的代价很实在:先删底层映射,上层 snapshot 的引用会悬空,内核可能直接 panic 或进入不可中断睡眠(D 状态),那时候只能重启。脚本里tee留日志不是形式主义,批量移除跳过了哪些、报了什么错,事后全靠它复盘。
4.3 阵列侧的预留:命令层解决不了的那一半
如果 DM 层已经干净,B 还是挂不上,问题多半在阵列侧。SCSI-3 PR 预留是存储用来防止多主机同时写的机制,A 宕机后预留可能仍被持有。需要在阵列管理界面或通过sg_persist工具查看并清除:
# 查看设备上的 PR 预留持有者(需要 sg3_utils) sg_persist --in --read-keys /dev/sdb sg_persist --in --read-reservation /dev/sdb # 确认 A 不会再回来后,清除预留(危险操作,务必确认前提) sg_persist --out --register-ignore --param-slist=0 --device=/dev/sdb这一步是命令解决不了的那一半:它依赖你对“A 是否真的下线”的业务判断。我一般会这么理解——DM 清理是技术动作,PR 清理是决策动作,两者混在一起做,就是事故的起点。
5. 避坑与排查:五条现场踩出来的教训
5.1 现象:dmsetup remove一直报 busy,remove -f也没用
原因:还有进程持有设备 fd,或文件系统处于惰性卸载未完成状态,引用计数不归零。remove -f只是标记 deferred,并不会绕过引用。解决:fuser -vm找出进程,确认业务允许后终止;cat /proc/mounts检查残留挂载;必要时dmsetup suspend冻结队列观察是否还有 I/O 下发,再决定下一步。
5.2 现象:清完映射重启,设备名从/dev/dm-0变成/dev/dm-3,fstab 挂载失败
原因:/dev/dm-N是动态编号,重启或映射重建后顺序变化。解决:fstab 和业务配置一律用/dev/mapper/<name>或 UUID/LABEL,绝不用/dev/dm-N。这条是纯血泪经验,改配置的成本远低于一次生产事故。
5.3 现象:双机同时挂载 ext4,一台写入后另一台读到脏数据
原因:本地文件系统不支持多主机并发写,元数据缓存各自为政,journal 互相覆盖。解决:立刻停止双挂,对其中一台做只读挂载或彻底卸载,用fsck检查结构;长期方案是换集群文件系统或网络文件系统。不要试图用mount -o ro加定期刷新来“凑合共享”,那是拿数据完整性赌博。
5.4 现象:multipath -ll显示路径全 failed,DM 映射挂着但 I/O 全超时
原因:链路层已断,multipath 的 path checker 还没判定失败,I/O 在队列里排队超时,表现为“假活”。解决:multipath -ll关注path checker状态和failback策略,临时multipath -f刷掉设备防止继续堆积,同时排查 FC/iSCSI 链路;不要在这个状态下跑remove_all,否则会把本可恢复的路径信息一起清掉。
5.5 现象:A 宕机后 B 接管,运行一段时间出现文件系统损坏
原因:A 的残留 I/O 或缓存未刷盘,存储侧 PR 预留未清,B 接管后两边的写序列交错,脑裂导致元数据写坏。解决:接管前必须确认 A 完全下线、PR 预留已清、阵列侧会话已断;接管后第一时间做文件系统一致性检查。顺序是“确认死亡 → 清预留 → 摘旧映射 → 新机挂载”,少一步都可能埋雷。
6. 设计取舍:为什么 Linux 不给你一把“万能钥匙”
dmsetup remove_all被很多人当成救命稻草,但它恰恰体现了 Linux 存储栈的一个核心设计哲学:默认你清楚自己在做什么,内核只保证机制正确,不替你做业务决策。DM 的引用计数、deferred removal、PR 预留,全都是“防误删、防脑裂”的护栏。它们让你在正常路径上多点几下,换来的是异常路径上不至于一删就崩。如果内核允许无条件强删映射,双机场景下脑裂只会来得更快更隐蔽。
这个取舍有代价:故障现场的操作复杂度上去了,排障要靠lsblk、multipath -ll、dmsetup ls --tree、dmesg四件套交叉验证,而不是一条命令。但换个角度想,存储这层的错误成本太高——一次误删映射可能意味着整块 LUN 的数据不可达,几小时的恢复窗口。用操作复杂度换安全边界,这个交易是划算的。
验证方法也很朴素:在测试环境里故意制造“一台宕机”的场景,观察 B 侧的 DM 状态、PR 预留、multipath 路径判定分别怎么变,把每一步的dmesg输出记下来。跑通一次,比读十篇文档都管用。进阶方向可以看 DM 的 target 实现(drivers/md/dm-linear.c、dm-mpath.c),理解 bio 是怎么被重映射的,再回头看remove的-EBUSY就一目了然。
从那以后我每次处理双机存储故障,都强制走一遍“先看树、再看持有者、最后动映射”的流程,哪怕现场再急也不跳步。希望帮到你。
本文还有配套的精品资源,点击获取