udev规则错误导致设备不触发挂载,因匹配条件不当(如缺attr{removable}=="1");systemd-mount报“no media found”是因未格式化或无卷标;需用唯一id挂载并加锁防冲突,且必须显式设置uid/gid和umask权限。

udev 规则写错导致设备插入后不触发挂载
udev 是 Linux 下处理热插拔事件的核心机制,规则写错就等于告诉系统“别管这个设备”。最常见的是匹配条件太宽或太窄:SUBSYSTEM=="block" 必须有,但光有它不够;漏掉 ATTR{removable}=="1" 或 ENV{ID_BUS}=="usb",U 盘可能被当成内置盘忽略。
实操建议:
- 先用
udevadm monitor --subsystem-match=block插拔设备,确认事件是否发出;再用udevadm info -n /dev/sdb(替换成你的设备节点)查出真实属性值,照抄进规则,别凭经验写 - 规则文件必须放在
/etc/udev/rules.d/99-usb-mount.rules这类带数字前缀的路径,且权限为0644,否则 udevd 不加载 - 写完运行
sudo udevadm control --reload-rules && sudo udevadm trigger --subsystem-match=block,但注意:trigger 不会重放已拔出的设备,得真插一次 - 调试时在规则里加
RUN+="/bin/sh -c 'logger udev-test: %p'",然后journalctl -t kernel -g udev-test看有没有日志,比盲猜快得多
systemd-mount 挂载失败报 “No media found”
这个错误不是磁盘坏了,而是 systemd-mount 默认跳过未格式化或无文件系统的块设备。它比 mount 更严格,不会尝试挂载空分区或 FAT32 但未打标(no label)的 U 盘。
实操建议:
- 先确认分区有文件系统:
sudo blkid /dev/sdb1,如果输出为空,说明没格式化或签名损坏,用sudo mkfs.vfat -F32 /dev/sdb1重建(注意备份) - 如果已有文件系统但没卷标,
sudo fatlabel /dev/sdb1 MYUSB或sudo e2label /dev/sdb1 MYUSB加个 label,systemd-mount 就能识别 - 挂载命令别直接用
systemd-mount /dev/sdb1,改用systemd-mount --no-block --automount=yes /dev/sdb1,避免阻塞和权限问题 - 挂载点默认在
/run/media/$USER/xxx,但该目录由udisks2管理;如果系统没装 udisks2,得自己建目录并确保$USER有写权限,否则 mount 会静默失败
自动挂载后普通用户无法读写文件
根源是挂载选项没设对。Linux 默认用 uid=0,gid=0 挂载,即使你用 systemd-mount,若没显式指定 -o uid=1000,gid=1000,所有文件属主都是 root,普通用户只能看不能删。
实操建议:
- 在 udev 规则里调用
systemd-mount时,必须带上完整选项:RUN+="/usr/bin/systemd-mount --no-block --automount=yes -o uid=%G,gid=%G,umask=000,fmask=113,dmask=002 /dev/%k"(%G是当前登录用户的 gid,%k是内核名如 sdb1) - 别信 “defaults” 选项 —— 它在不同文件系统下行为不同,FAT32 下
umask控制权限,ext4 下得靠uid/gid,混用必出问题 - 如果用
/etc/fstab配合 autofs,注意user选项只允许挂载者卸载,不解决读写权限;真正起作用的是uid=1000,gid=1000和fmask/dmask - 挂载后立刻检查:
ls -ld /run/media/$USER/*,确认目录属主是自己;再touch /run/media/$USER/xxx/testfile实测写入,别只看 ls 权限位
多个 USB 设备同时插拔引发挂载冲突
udev 事件是异步的,两个 U 盘几乎同时插入时,规则可能并发执行,导致 systemd-mount 尝试挂载同一个临时路径,或 blkid 查到的设备名(如 /dev/sdb)在执行中途被重分配。
实操建议:
- 永远用设备的唯一标识符,而不是
/dev/sdX。在 udev 规则中优先使用SYMLINK+="usb-%E{ID_SERIAL_SHORT}",然后挂载/dev/disk/by-id/usb-xxx路径 - 在 RUN 命令中加简单锁:
RUN+="/bin/sh -c 'mkdir /run/usb-mount-lock-%E{ID_SERIAL_SHORT} 2>/dev/null || exit 1; systemd-mount ... ; rmdir /run/usb-mount-lock-%E{ID_SERIAL_SHORT}'",利用 mkdir 原子性防并发 - 避免在规则里做耗时操作(比如调用
blkid多次),全用 udev 自带的ENV{ID_FS_TYPE}、ENV{ID_FS_LABEL}变量,它们已在上一阶段解析好 - 如果设备反复出现 “device busy” 错误,大概率是前一次挂载没 clean up —— 检查
systemctl --user list-units | grep mount,手动 stop 对应的dev-disk-by\x2did-xxx.device单元再试
热插拔看着是插上线就完事,实际卡点全在 udev 的时机、systemd-mount 的策略、以及文件系统层对“可挂载”的定义差异。少一个 ENV{ID_BUS}=="usb",或者多一个没删的锁目录,都够你对着 journalctl 发十分钟呆。










