简介:本资源是一份面向Linux系统运维工程师与中级存储管理员的实战排错指南,聚焦多服务器共享同一块存储时出现的挂载冲突问题——如一台服务器挂载后,另一台提示‘设备正忙’或无法挂载。内容深入剖析底层设备文件映射机制与并发访问风险,并以dmsetup命令为核心,详解remove_all等关键操作的适用场景、执行逻辑及规避数据损坏的注意事项,同时延伸介绍快照、镜像等Device-Mapper高级管理能力。资源为单文件Word文档(.docx),共1个文件,体积仅11KB,内容精炼,含命令实操截图、参数说明与典型错误应对策略,便于快速查阅与现场排障。目前已有1646人学习下载,适合需在生产环境中稳定管理iSCSI、FC或本地共享存储的运维人员参考使用。
1. 同一个存储挂到两台服务器就“卡死”:不是权限问题,是 Device-Mapper 的映射残留在作祟
你刚把一块 iSCSI LUN 或 FC 存储卷同时挂到两台 Linux 服务器上,A 机挂载成功、读写正常,B 机却死活 mount 不上,报错mount: /mnt/data: special device /dev/mapper/vg0-lv_data does not exist或更常见的device-mapper: reload ioctl failed: Device or resource busy;或者 A 机突然宕机/重启后,B 机再 mount 就提示Resource busy,lsblk看设备还在,lvs却显示 inactive,dmsetup info里一堆 stale(陈旧)的映射条目——这不是 NFS 锁冲突,也不是 multipath 路径没配好,而是 Device-Mapper 层面的映射状态没清理干净。这个问题在生产环境高频出现:数据库主备切换、KVM 虚拟机热迁移、Ceph RBD 映射回收失败、甚至只是运维误操作vgchange -an后没清 mapper 设备,都会触发。它不挑发行版(RHEL/CentOS 7/8、Ubuntu 20.04+/22.04、openEuler 22.03 都一样),也不依赖具体存储协议(iSCSI/FC/NVMe-oF 全中招),核心症结在于:Linux 的 device-mapper 框架不会自动感知远端服务器是否已释放设备,它只认本地内核态的映射表是否被显式销毁。所以dmsetup remove_all不是“万能重启键”,而是必须精准使用的“手术刀”——用错了会直接导致逻辑卷丢失、LVM 元数据损坏,甚至触发kernel panic。本文带你从dmsetup的底层行为出发,拆解真实复现场景、验证每一步命令的副作用,并给出带防护机制的自动化清理脚本。
2. Device-Mapper 是什么:不是文件系统,而是内核级块设备“翻译器”
2.1 为什么挂载失败?先看 Device-Mapper 在内核里干了什么
Device-Mapper(DM)是 Linux 内核提供的一个块设备虚拟化框架,它不直接管理磁盘,而是在物理块设备(如/dev/sdb)和上层逻辑设备(如/dev/mapper/vg0-lv0)之间插入一层“映射引擎”。这个引擎通过一张映射表(mapping table)定义如何把逻辑扇区号(logical sector)转换成物理扇区号(physical sector)。举个典型例子:当你执行lvcreate -L 10G -n lv_data vg0,LVM 实际调用的是dmsetup create vg0-lv_data --table "0 20971520 linear 8:16 2048",其中8:16是/dev/sdb的主次设备号,2048是起始偏移扇区。这个映射关系被加载进内核后,/dev/mapper/vg0-lv_data才真正可被mkfs和mount使用。关键点来了:这个映射表一旦加载,就独立于任何用户空间进程存在;即使创建它的lvchange进程退出,映射仍驻留内核,直到被显式remove。所以当 A 机异常宕机,它来不及执行dmsetup remove vg0-lv_data,内核里就留下一个“僵尸映射”——B 机尝试vgscan && vgchange -ay时,LVM 发现/dev/sdb上已有 DM 映射(哪怕 inactive),就会拒绝重建,报Device or resource busy。
提示:
dmsetup ls显示的是当前内核中所有 active/inactive 的映射名,而lvs显示的是 LVM metadata 中记录的 LV 状态。两者不一致是问题根源。
2.2dmsetup remove_all到底做了什么?别把它当rm -rf
dmsetup remove_all命令看似粗暴,实则有严格执行顺序:
- 先遍历
/sys/block/dm-*下所有 device-mapper 设备,检查其holders目录是否为空(即是否有进程正在使用该设备); - 对每个无 holder 的设备,调用
ioctl(DM_DEVICE_REMOVE),通知内核卸载映射表; - 最后清空
/dev/mapper/下对应符号链接(但注意:它不会删除/dev/dm-*字符设备节点,那是内核动态分配的)。
这意味着:如果某个 LV 正被dd、fsck或数据库进程打开,remove_all会跳过它并报错Device or resource busy,而不是强制卸载。这也是为什么很多人执行后问题依旧——因为真正卡住的映射根本没被删掉。验证方法很简单:执行dmsetup remove_all 2>&1 | grep -E "(busy|failed)",如果有输出,说明有活跃 holder,必须先杀进程或 umount。
2.3 为什么vgchange -an不等于dmsetup remove_all?
vgchange -an vg0只做两件事:
- 将 VG 中所有 LV 的 LVM metadata 标记为 inactive;
- 调用
dmsetup suspend+dmsetup remove删除对应 mapper 设备。
但它不处理其他非 LVM 创建的 DM 设备,比如:
multipath创建的/dev/mapper/mpatha(主路径设备);cryptsetup创建的/dev/mapper/luks-xxx(加密卷);- 手动
dmsetup create的自定义映射(如快照 origin); - 甚至某些驱动(如
nvme多路径)注册的临时映射。
这些设备在vgchange -an后依然存活,lsblk里还能看到dm-0,dm-1,dmsetup ls也列出来。而remove_all是全局清理,一把梭哈——所以它危险,但也必要。
3. 实战复现与分步修复:从报错到恢复的完整链路
3.1 复现环境搭建(10 分钟可完成)
我们用两台 CentOS 7.9 虚拟机(A/B),共享同一块 iSCSI target(用targetcli在第三台机搭建,或直接用losetup模拟):
# 在 A 机上:创建 PV/VG/LV 并挂载 sudo losetup -fP /tmp/disk.img # 假设 disk.img 是 2G 文件 sudo pvcreate /dev/loop0 sudo vgcreate vg0 /dev/loop0 sudo lvcreate -L 1G -n lv_data vg0 sudo mkfs.xfs /dev/vg0/lv_data sudo mkdir /mnt/shared && sudo mount /dev/vg0/lv_data /mnt/shared # 在 B 机上:尝试挂载同一块 loop0(模拟共享存储) sudo losetup -fP /tmp/disk.img # 注意:实际生产中这是同一块 SAN LUN sudo pvscan --cache # 强制刷新 PV 缓存 sudo vgscan --cache sudo vgchange -ay vg0 # 此处会失败,报 Device busy此时dmsetup ls在 A 机输出:
vg0-lv_data (253:0)在 B 机输出:
vg0-lv_data (253:0) # 但状态是 INACTIVE,且 `ls -l /dev/mapper/vg0-lv_data` 报 No such file3.2 精准诊断:三步定位“忙”的根源
不要一上来就remove_all,先确认到底谁在占着:
# 步骤 1:查哪个 dm 设备被占用 sudo dmsetup info -c | awk '$7 > 0 {print $1}' # 输出所有 open_count > 0 的 mapper 名 # 示例输出:vg0-lv_data # 步骤 2:查谁在用它(比 lsof 更准) sudo dmsetup deps vg0-lv_data # 显示依赖的底层设备(如 8:0) sudo lsof /dev/sda # 查 sda 是否被进程打开(注意:这里要换成本地实际设备号) # 步骤 3:查内核映射表是否残留 sudo cat /sys/block/dm-0/dm/name # 输出 vg0-lv_data sudo cat /sys/block/dm-0/dm/status # 如果是 "SUSPENDED" 或 "LOADING",说明卡住了3.3 安全清理:带校验的remove_all替代方案
直接dmsetup remove_all风险太高,我习惯用以下脚本替代:
#!/bin/bash # safe-dm-clean.sh set -e # Step 1: 检查是否有活跃 holder BUSY_MAPS=$(sudo dmsetup info -c | awk '$7 > 0 {print $1}') if [ -n "$BUSY_MAPS" ]; then echo "ERROR: Following devices have open holders, cannot remove:" echo "$BUSY_MAPS" echo "Run 'sudo lsof /dev/mapper/<name>' to find processes" exit 1 fi # Step 2: 仅清理 inactive 且无 holder 的映射 INACTIVE_MAPS=$(sudo dmsetup ls --target=linear --noheadings | awk '{print $1}') for map in $INACTIVE_MAPS; do if sudo dmsetup status "$map" 2>/dev/null | grep -q "inactive"; then echo "Removing inactive mapper: $map" sudo dmsetup remove "$map" 2>/dev/null || true fi done # Step 3: 强制清理残留(仅当 Step 2 无效时启用) # sudo dmsetup remove_all --force # 注释掉,手动解注 echo "Cleanup done. Run 'sudo vgscan && sudo vgchange -ay' now."参数说明:
--target=linear只匹配 LVM 创建的线性映射,避开 multipath/crypt 等类型;sudo dmsetup remove "$map"比remove_all更可控,失败也不会中断后续。
3.4 恢复挂载:LVM 元数据同步是关键
清理完 mapper 后,B 机不能直接vgchange -ay,因为 LVM cache 可能过期:
# 必须刷新 metadata 缓存(否则 vgscan 仍认为 VG locked) sudo vgscan --cache --ignorelockingfailure sudo pvscan --cache # 再激活 VG sudo vgchange -ay vg0 # 验证 LV 状态 sudo lvs -o+attr vg0 # 查看 Attr 列,应为 '-wi-a-----'(a 表示 active) sudo mount /dev/vg0/lv_data /mnt/shared注意:
--ignorelockingfailure参数允许在集群锁不可用时强制扫描,适用于单机调试。生产环境务必配合clvmd或dlm。
4. 避坑:五个血泪经验总结的“踩坑现场”
4.1 现象:执行dmsetup remove_all后vgscan报Failed to find physical extent
原因:remove_all清除了所有 mapper,包括 PV 所在的/dev/mapper/pv_name(如果 PV 是加密或 multipath 设备),导致pvscan无法读取 PV header。
解决:先sudo multipath -r或sudo cryptsetup luksOpen恢复底层设备,再vgscan。
4.2 现象:dmsetup remove报device-mapper: remove ioctl failed: Device or resource busy,但lsof查不到进程
原因:内核模块(如xfs、ext4)持有 superblock 锁,或udev规则正在处理设备事件。
解决:sudo udevadm settle等待 udev 完成,再sudo sync && sudo echo 3 > /proc/sys/vm/drop_caches清页缓存,最后重试。
4.3 现象:B 机vgchange -ay成功,但mount报wrong fs type, bad option, bad superblock
原因:A 机未正常umount就宕机,XFS 日志未提交,B 机直接挂载会因日志不一致拒绝。
解决:sudo xfs_repair -L /dev/vg0/lv_data(-L强制清日志,慎用!先备份元数据)。
4.4 现象:dmsetup ls显示vg0-lv_data (253:0),但ls /dev/mapper/vg0-lv_data报 No such file
原因:mapper 设备存在,但/dev/mapper/下符号链接被误删(常见于udev规则失效)。
解决:sudo ln -s /dev/dm-0 /dev/mapper/vg0-lv_data手动重建链接,或sudo udevadm trigger --subsystem-match=block。
4.5 现象:清理后vgdisplay vg0显示Alloc PE / Total PE为 0,VG 似乎“消失”了
原因:remove_all误删了 PV 的 device-mapper 映射(如/dev/mapper/3600...),导致 LVM 无法访问 PV 物理扇区。
解决:sudo pvscan --cache --ignorelockingfailure强制重读 PV,再sudo vgcfgrestore vg0(需提前备份vgcfgbackup)。
5. 生产级防护:给dmsetup加上“后悔药”和自动巡检
5.1 给每次dmsetup remove加审计日志
在/etc/udev/rules.d/99-dm-audit.rules中添加:
# 记录所有 dmsetup 操作 KERNEL=="dm-*", SUBSYSTEM=="block", ACTION=="add|remove", \ RUN+="/bin/sh -c 'logger -t dm-audit \"DM event: %k %p %E{ACTION}\"'"然后sudo udevadm control --reload-rules。这样journalctl -t dm-audit就能查到每次 mapper 创建/删除时间,排查问题时比翻dmsetup history(不存在)靠谱得多。
5.2 自动化巡检脚本:每天检查 stale mapper
#!/bin/bash # /usr/local/bin/check-dm-stale.sh STALE_COUNT=$(sudo dmsetup info -c | awk '$7 == 0 && $5 ~ /I/ {count++} END {print count+0}') if [ "$STALE_COUNT" -gt 0 ]; then echo "ALERT: $STALE_COUNT stale DM devices found!" | mail -s "DM Stale Alert" admin@company.com # 附详细列表 sudo dmsetup info -c | awk '$7 == 0 && $5 ~ /I/ {print $1, $5, $7}' | mail -s "Stale DM Details" admin@company.com fi加入 crontab:0 2 * * * /usr/local/bin/check-dm-stale.sh
5.3 关键参数表:dmsetup常用子命令与安全等级
| 命令 | 安全等级 | 适用场景 | 风险提示 |
|---|---|---|---|
dmsetup info -c | ★★★★★ | 诊断只读,无副作用 | 输出字段含义:$1=name,$5=status(I=inactive,A=active),$7=open_count |
dmsetup deps <name> | ★★★★☆ | 查依赖设备,定位底层 block | 不要用于正在 IO 的设备,可能阻塞 |
dmsetup suspend <name> | ★★★☆☆ | 冻结 IO,为快照做准备 | 挂起后必须resume,否则设备永久不可用 |
dmsetup remove <name> | ★★☆☆☆ | 精准删除单个 mapper | 若有 holder 会失败,需先deps+lsof |
dmsetup remove_all --force | ★☆☆☆☆ | 紧急恢复,最后手段 | 可能导致 LVM metadata 损坏,仅限单机调试 |
5.4 一个真实案例:某金融客户 NAS 挂载失败的根因还原
客户用 NFSv4 挂载 NetApp 存储,两台应用服务器 A/B 同时挂载/nas/appdata。A 机内核 panic 后重启,B 机挂载报Resource busy。我们按流程:
dmsetup info -c发现netapp-nas (253:2)open_count=0 但 status=I;dmsetup deps netapp-nas输出0 20971520 linear 8:32 2048,对应/dev/sdc;lsof /dev/sdc为空,但cat /sys/block/sdc/device/model显示NetApp LUN,确认是共享存储;- 执行
sudo dmsetup remove netapp-nas成功; sudo mount -t nfs4 10.10.1.10:/vol/appdata /nas/appdata—— 恢复。
根因是 NetApp 的 ALUA(Asymmetric Logical Unit Assignment)模式下,A 机 panic 时未发送 SCSI RELEASE 命令,B 机控制器侧仍认为 LUN 被占用。dmsetup remove清除了本地内核残留,让 NFS client 重新协商连接。
从那以后我每次处理共享存储故障,第一件事就是dmsetup info -c | grep -E "(I|0)$"扫描 inactive 且 open_count=0 的设备,而不是盲目umount或vgchange。这招在 RHEL 8.5+ 的 Stratis 存储、openEuler 的 DMS(Distributed Metadata Service)场景下同样有效——底层都是 device-mapper。希望帮到你。
本文还有配套的精品资源,点击获取