简介:面向Linux服务器运维与存储管理人员的实战型资料,聚焦同一存储设备需共享挂载至两台服务器,却因一台服务器故障导致另一台无法挂载或提示“存储正忙”的常见问题。文档以dmsetup命令为主线,从设备文件与Device-Mapper映射机制入手,先梳理共享存储冲突的产生原理,再给出在故障服务器上执行dmsetup remove_all清理映射后重新挂载的解决步骤,并延伸到快照、克隆、镜像等高级用法,使读者既能快速应急排障,也能系统掌握dmsetup在存储管理中的典型应用场景。全文按问题分析、解决方案、结论组织,重点突出,排错路径可复现,便于运维人员快速定位关键命令。包体为1个docx文档,仅11KB,内容精炼,适合快速查阅。已有1646人学习/下载,适合需要处理共享存储冲突、学习dmsetup命令的Linux运维和存储工程师参考。
1. 双机共享存储的“夺命”现场:一台宕机另一台报存储正忙
做存储运维的人大概率都碰过这种场面:一套双控存储,通过光纤或者 iSCSI 同时挂给了两台 Linux 服务器,本来跑得好好的,结果其中一台因为断电、内核 panic 或者重启就“猝死”了。剩下的这台服务器想接管存储,挂载时却直接弹“storage is busy”或者“设备或资源忙”。第一反应是拔线重插,不行;重启 multipathd,不行;最后被老前辈指点,在备机上敲了一行dmsetup remove_all,世界才安静下来。
这行命令解决的不是“抢盘”本身,而是把主机侧 Device-Mapper 层残留的映射关系,也就是另一台服务器控制权消失后留下的“僵尸锁”清干净。很多刚接触多路径存储的同事,甚至不少干了几年系统运维的人,都以为dmsetup remove_all是万能的“卸载命令”,其实它只是清空 Device-Mapper 的设备映射表,用错场景轻则重启失效,重则把系统盘的 LVM 映射也一并干掉。这篇笔记不绕弯子,直接拆开这台“存储正忙”背后的机制,把我处理这类问题时的完整排查路径和踩过的坑写出来,适合负责 Linux 服务器存储挂载、双机共享存储、多路径环境的运维和 DBA 同事参考。
2. 先看懂 Device-Mapper 与多路径:为什么“存储正忙”是必然结果
2.1 Device-Mapper:内核里的“磁盘翻译层”
Linux 里访问磁盘,最终都要经过块设备层。而 Device-Mapper 是内核提供的一个通用块设备映射框架,它的核心作用是把一个物理块设备重新映射成一个或多个逻辑设备。像 LVM 的逻辑卷、软 RAID(mdadm 的某些模式)、DM 快照、dm-crypt 加密盘,底层全都是 Device-Mapper 在起作用。
我们用dmsetup ls能看到当前系统上所有 Device-Mapper 的逻辑设备,它们被统一归纳在/dev/mapper/目录下面。比如 LVM 的逻辑卷常显示为/dev/mapper/vgdata-lvdata,多路径盘显示为/dev/mapper/mpatha或者/dev/mapper/3600c0ff000...。这里最容易混淆的是:很多人把/dev/mapper/目录里的设备理解成“物理磁盘”,实际上它只是一个映射关系。
Device-Mapper 设备有三个关键属性:设备名(name)、映射表(table)、唯一标识(uuid)。dmsetup table可以看到某台逻辑设备底层对应的真实物理设备。比如一个多路径设备mpatha的 table 里通常有 4 个条目,对应四个存储控制器端口路径,这也就解释了为什么/dev/mapper/目录下的设备能“屏蔽”底层物理路径的差异。
2.2 multipath 把四路路径合并成一块“逻辑盘”
企业级存储一般都有双控制器,每个控制器再出两个前端端口,这样一台服务器到存储就有 4 条物理路径。如果不用多路径软件,系统会看到 4 个独立的/dev/sdX设备,指向同一个 LUN,后果是裸设备直接读写会产生元数据错乱,因为操作系统根本不知道这 4 个盘其实是同一块数据。
multipathd的作用就是根据每个 SCSI 设备的 WWID,也就是全球唯一标识符,把这 4 条路径合并成一个/dev/mapper/mpathX。这个动作的关键在/etc/multipath.conf里的配置,比如:
cat /etc/multipath.conf输出中的wwid绑定和alias命名规则决定了 multipath 怎么识别和命名设备。我一般会在里面显式指定需要合并的设备列表,防止它误把两块不同 LUN 的盘当成同一块盘。
这里有个很多新手会犯的错误:他们以为multipath -ll里看到 mpath 设备就是物理盘,直接在/etc/fstab里写/dev/mapper/mpatha,也没问题。但一旦存储侧调整过 LUN 映射,比如更换了控制器,旧 WWID 遗留在系统里,multipathd就会重新生成一套新映射,/dev/mapper/mpatha可能指向完全不同的 LUN,这就是后续“存储正忙”或者说挂载异常的隐患源头之一。
2.3 存储正忙的真实链路:SCSI 预留与残留映射
回到最原始的问题:为什么一台服务器崩了,另一台挂不上?
大多数双机共享存储场景,要么跑的是集群文件系统(如 GFS2、OCFS2),要么是数据库裸设备(如 Oracle ASM),要么被第三方集群软件接管。这些场景下,存储侧会启用 SCSI-3 Persistent Reservation,也就是持久预留锁。节点 A 通过 PR 注册一个 reservation key 并占有 LUN,节点 B 作为后备节点,虽然路径也能看到 LUN,但没有合法的 key,并发写入会被存储拒掉。
当节点 A 异常宕机,比如断电,它的 PR key 不会主动释放,是 lease 超时之后由存储控制器自动清除的,超时时间通常是 30 到 60 秒。但如果节点 A 只是被强制重启,操作系统没来得及走正常卸载流程,那么主机侧遗留的 Device-Mapper 映射里还“粘着”这个旧 key。节点 B 尝试挂载时,SCSI 层交互就出现冲突,表现就是mount卡住或者直接报device busy。
还有一种更常见的非集群场景:两台服务器不加任何集群锁,直接把同一个 LUN 用 ext4/xfs 挂到各自的/data目录,这种配置本身就是高危的。一台挂了,另一台对存储发出的指令会因为缓存不一致、文件系统日志错乱而被拒绝,dmesg里通常能看到I/O error和sdX: reservation conflict之类的信息。所以dmsetup remove_all能解决的是“主机侧的映射残留”,根源上的“锁”和“数据一致性”问题是避免不了的,这个边界务必要清楚。
3. 实操:dmsetup remove_all 与完整排障流程
3.1 第一步:别急着 remove,先看清现场
接到故障,我习惯先收集 4 个输出,分别是 multipath 状态、dm 映射列表、LVM 卷状态、SCSI 设备状态:
multipath -ll dmsetup ls pvs lvs cat /proc/scsi/scsi为什么先做这一步?因为dmsetup remove_all是无差别清理,所有 Device-Mapper 设备都会被尝试移除。如果存在一个 LVM 卷组正在被系统盘根文件系统使用,盲目执行会有不可逆后果,比如/dev/mapper/centos-root里的 root 逻辑卷是被系统挂载着的,remove_all 对它是无效的但同样会报错,其他未挂载的映射则被清理掉。这个“先看后动”的习惯能帮你判断哪些映射是有价值的,哪些是残留的僵尸映射。
关键看两点:multipath -ll里active/passive状态,以及dmsetup ls里设备名。如果一台服务器宕机后,这台服务器上的 mpath 设备变成了undef状态,或者路径数从 4 变成 0,这种映射就是失效的,是清理对象。
3.2 第二步:按依赖顺序卸载与停用
正常的清理顺序必须遵循“从顶往下”的原则,也就是先卸载文件系统,再停止 LVM 卷组,再刷新 multipath 状态,最后才是dmsetup remove_all:
umount /data vgchange -an vgdata multipath -F dmsetup remove_allumount是释放文件系统层的占用;vgchange -an是停用卷组,告诉 LVM 不再管理这些物理卷,对应的 dm-linear 映射会被释放;multipath -F是刷新 multipath 设备表,让 multipathd 放弃当前路径的管理权。
当这三步做完,dmsetup 再执行 remove_all 时,就能把剩余残留映射一次性清掉。如果之前的步骤有遗漏,比如卷组没有停用,remove_all 通常会报 target is busy。
参数说明:multipath -F里的F是大写,表示 flush all multipath devices,不是-f(flush a specific device)。dmsetup remove_all后系统里/dev/mapper下应该只剩系统盘自身的映射。
3.3 第三步:重新识别存储并挂载
清理只是半程,后半程是把盘重新认回来。很多时候这台服务器是作为“接管方”,存储侧本身的 LUN 还在,需要重新扫描 SCSI 总线让内核重新发现设备:
echo "- - -" > /sys/class/scsi_host/host0/scan echo "- - -" > /sys/class/scsi_host/host1/scan这里的- - -是三个通配符,分别表示 channel、target、lun,意思是对该 HBA 的所有通道、所有目标、所有 LUN 做全量扫描。扫描完成后,dmesg和/dev/disk/by-id能看到新的 sd 设备出现。之后再启动 multipath 重新合并路径并挂载验证:
systemctl restart multipathd multipath -ll mount /dev/mapper/mpatha /data常见做法是重启 multipathd 后再执行multipath -F和multipath -v2重新生成设备,最后确认/data下的数据能看到之前的内容,再正常对外提供业务。这里有个细节:扫描之前要看 HBA 号的列表,不同机器 HBA 数量不同,用下面的命令确认:
ls /sys/class/scsi_host/3.4 强制清理的场景与风险边界
如果在执行dmsetup remove_all时系统提示Device or resource busy,而且你已经确认对应的文件系统和卷组都已经停用,说明有残留进程占用了块设备。这时候可以加--force:
dmsetup remove_all --force这个选项会强制删除映射,不检查设备是否在使用的状态。但是强烈不建议在业务运行中的生产环境直接这样搞,因为它跳过的是内核的引用计数检查,强制删除后进程对这块盘的读写会直接卡死。只有在确认这台机器已经彻底不需要该存储,比如存储侧已经释放、业务已切走、当前服务器只是“残留”状态时才用。
一个我常用的确认手段是:
fuser -vm /dev/mapper/mpatha这个命令会列出哪些进程正在使用该设备。如果没有进程输出,说明只是映射残留,force 是安全的。
4. 避坑清单:remove_all 没删掉、误删盘、重启失效
4.1 remove_all 执行了,但提示 Device or resource busy
现象:在故障机上执行dmsetup remove_all,命令一直在刷Device or resource busy,看起来没效果。
原因:dmsetup remove_all只能清理没有 in-use 的映射。这个 in-use 不只是文件系统挂载,还可能是正在被某进程直接打开的/dev/mapper/xxx设备,比如 Oracle ASM 的裸设备就是直接绑定/dev/mapper/3600...的,此时没有经过文件系统层,umount根本管不到。
解决:先用lsof或者fuser找到打开该设备的进程。如果是数据库实例,先停数据库服务,再执行dmsetup remove_all。如果是集群软件控制的设备,比如 Pacemaker 的资源代理,需要先把资源 disable 掉。有些时候/dev/mapper设备被 udev 或 systemd 引用,需要先清理引用关系,直接用dmsetup remove /dev/mapper/xxx针对单个设备操作。
4.2 remove 之后 multipathd 又把 mpath 拉回来了
现象:dmsetup remove_all执行完,dmsetup ls里已经空了,但过了几秒multipath -ll又看到 mpath 设备出现,而且路径状态正常,重新进入 pending 或 active 状态。
原因:multipathd是一个常驻守护进程,它会周期性地重新检查 SCSI 设备并自动创建多路径设备。你执行dmsetup remove_all删掉映射后,multipathd 检测到底层 sd 设备仍然存在,就把映射重新建立了。这在故障处理中其实不是坏事,但如果你需要把这块盘“晾”在一边等待存储侧动作,这个行为就会造成干扰。
解决:先停掉 multipathd 再 remove:
systemctl stop multipathd dmsetup remove_all在/etc/multipath.conf里设置blacklist把暂时不需要的 LUN 加进去,防止后续再被自动接管。处理完问题后,把黑名单里的条目移除,启动 multipathd 才能正常识别这块盘。
4.3 本想删存储盘映射,结果把系统盘的 LVM 也删了
现象:remove_all 执行完,重启之后系统直接进入 rescue 模式,root 逻辑卷找不到。
原因:系统盘如果用 LVM 配置,/dev/mapper/centos-root本身就是 Device-Mapper 映射,一个remove_all会把它也尝试删掉。如果当时系统没有挂载根文件系统的冲突,或者你在 rescue 模式下手动执行了这条命令,逻辑卷的映射就被彻底删除了,这时 LVM 元数据在磁盘上虽然还在,但内核里没有了映射关系。
解决:永远不要在系统盘还作为 LVM 卷组活跃时执行dmsetup remove_all。处理共享存储问题时,先通过vgdisplay确认哪些卷组属于共享存储,哪些属于本机系统盘。只对故障存储对应的卷组执行vgchange -an,然后删除该卷组对应的 dm 设备。真误删了系统盘映射也不要慌,重启进入系统后执行vgscan和vgchange -ay重新激活卷组,通常能恢复,前提是你没有同时执行过vgremove。这一点非常关键,不要在紧张的时候狂敲 remove_all。
4.4 存储侧重启后,服务器怎么都认不到盘
现象:存储控制器升级或重启完成,LUN 正常,但服务器执行multipath -ll看不到路径,dmesg里也没有识别到新设备。
原因:很多情况是服务器 SCSI 设备层还保留着故障前状态。存储侧重启会断开链路,服务器上的 scsi_device 变成 offline 或 deleted 状态,需要先删除旧的 scsi 设备对象,再重新扫描。直接执行 scan 往往没用,因为内核认为该设备还在。
解决:先删掉对应 HBA 上所有失效设备对象,再重新扫描:
echo 1 > /sys/class/scsi_device/2:0:0:1/delete echo "- - -" > /sys/class/scsi_host/host2/scan这里的2:0:0:1对应 HBA 号:通道:目标:LUN。要确认哪些设备处于 offlined 状态,看dmesg | grep -i "offline"或者直接cat /sys/class/scsi_device/*/state。删除时可以先用multipath -l拿到路径信息,再从路径的sysfs链接反查 scsi_device 编号。
4.5 多路径 wwid 冲突导致两块 LUN 被合并成一块
现象:挂载后发现文件系统数据“错乱”,两块不同用途的 LUN 显示成同一个 mpath 设备,存储上的数据不敢用了。
原因:multipath.conf的wwid配置写错,或者底层磁盘无 WWID 时 multipath 错误使用了设备的序列号做合并依据。通常发生在存储厂商自带的序列号不唯一,或者某些虚拟化平台对 WWID 的传递不完整。
解决:在multipath.conf里显式书写正确绑定:
multipaths { multipath { wwid 3600c0ff0000000000000000000000000 alias datalun } }配置完后执行multipath -r重建设备映射,确认multipath -ll里 datalun 对应的是正确的物理路径集合。不同 LUN 一定要用不同 alias,不要用默认的 mpathN 命名,这样即使出现异常也能一眼看出来。
5. 从命令到习惯:处理共享存储故障的复验动作
dmsetup remove_all本身并不神秘,几十个字符的事情。真正容易翻车的,是操作前后少做了几次校验,导致你以为恢复了,几天后才发现问题。现在我处理这类故障,固定强制走一遍“三板斧”验证流程,缺一步就不算完。
第一板斧是验证映射表。恢复挂载后,把dmsetup ls输出存成一个文件,再和故障发生前的输出对比,确认没有多出莫名其妙的新映射。特别是那些uuid和故障时不一样的设备,一定要查清楚来源。第二板斧是验证读写链路,不能只看挂载成功就收工。对关键目录做过一次真实写读:
dd if=/dev/zero of=/data/testfile bs=1M count=1024 conv=fdatasync dd if=/data/testfile of=/dev/null bs=1M count=1024conv=fdatasync会让数据绕过 page cache 直接落到存储,这一步能抓到 multipath 路径配置错误导致的写失效问题。第三板斧是重启环境验证。生产环境不敢重启,至少也要在主备机之间做一次切换演练,确认下次一台宕机时,另一台能在 60 秒内完成挂载接管。这一步暴露过很多“隐藏配置”,比如/etc/fstab里挂载参数写死,或者 udev 规则里残留旧 wwid 映射,这些在平时的运行中完全看不出来。
这个故障处理中最深刻的一次教训,是我最开始处理“存储正忙”时只知道闷头执行dmsetup remove_all,结果在北向监控里看到系统盘 LVM 映射丢失的报警,才意识到自己差点把生产系统搞挂。从那以后,我每次执行 remove 类命令之前都会强制走一遍后面的动作:先multipath -ll和pvs、lvs三连摸底,确认系统盘卷组和共享存储卷组是干净隔离的再动手。这种故障处理,处理的是映射表和锁状态,赌的就是你对现状的把握足够准确。希望这篇笔记能帮你少踩我踩过的那些坑。
本文还有配套的精品资源,点击获取