Armbian 自动挂载 USB 移动硬盘

最近在折腾配置 N1 上的 Armbian,想实现插入 USB 移动硬盘自动挂载的功能。经过一番摸索,终于找到了一套稳定可靠的方案,特此记录下来,供大家参考。

AI 生成的 Armbian USB 移动硬盘自动挂载完全指南。

基于 udev + systemd 的稳定热插拔方案,同时覆盖 NTFS 与 exFAT 两种文件系统。
适用 Armbian current / edge(内核 ≥ 5.15)。

前置问题:驱动该用哪个?

在开始配置之前,先把驱动问题说清楚,因为 NTFS 和 exFAT 的情况截然不同。

NTFS:ntfs3 vs ntfs-3g

Linux 5.15 起内核自带 ntfs3 驱动(Paragon 贡献),Armbian 已安装的 ntfs-3g 是早年 FUSE 方案。

维度 ntfs3(内核驱动) ntfs-3g(FUSE 驱动)
运行层 内核空间 用户空间(FUSE)
读写性能 快约 20-25% 较慢(上下文切换开销)
稳定性 成熟(5.15 后持续完善) 久经考验(2007 年起)
Type= 参数 ntfs3 ntfs-3g
是否需要额外安装 否(内核自带) 是(已安装)

结论:挂载改用 ntfs3,但保留 ntfs-3g 安装。
ntfs-3g 包含 ntfsfix 工具,在硬盘出现 dirty 标记时必须用它修复。工具留着,驱动换掉。

1
2
3
4
# 确认 ntfs3 模块存在(应输出 ✅)
[ -d "/lib/modules/$(uname -r)/kernel/fs/ntfs3" ] \
  && echo "✅ ntfs3 available" \
  || echo "❌ 内核不含 ntfs3,请改用 ntfs-3g"

exFAT:内核 exfat vs exfatprogs

同理,Linux 5.4 起内核已内置 exFAT 驱动。exfatprogs(或旧版 exfat-utils)是用户空间工具包,提供 mkfs.exfatfsck.exfat 等命令,挂载本身不需要它,但建议保留。

1
2
3
4
5
# 确认内核 exfat 模块
modinfo exfat | grep filename

# 安装工具包(如果还没装)
apt install exfatprogs

挂载 exFAT 直接用 Type=exfat,无需 FUSE 层。

方案架构

整个方案由两个部件组成:

1
2
3
4
5
6
7
8
9
10
USB 插入/拔出

    ├─ udev rule 捕获块设备事件(by UUID)
    │       ↓
    ├─ 触发 systemctl start/stop
    │       ↓
    └─ systemd .mount unit 执行挂载/卸载

            ├─ nofail          → 开机无盘不阻塞
            └─ DefaultDependencies=no → 不产生循环依赖

Step 1:确认硬盘 UUID

始终用 UUID,不用 /dev/sdX 设备名随插入顺序变化,UUID 是硬盘的永久标识。

1
2
3
4
5
6
7
8
9
# 插入硬盘后执行
lsblk -f

# 或用 blkid 获取完整信息
blkid | grep -E "ntfs|exfat"

# 示例输出:
# /dev/sda1: UUID="A1B2C3D4E5F67890" TYPE="ntfs" ...
# /dev/sda1: UUID="1A2B-3C4D" TYPE="exfat" ...

注意:NTFS 的 UUID 通常是 16 位十六进制(如 A1B2C3D4E5F67890),
exFAT 的 UUID 通常是 8 位带短横线(如 1A2B-3C4D),两者格式不同,注意区分。

Step 2:创建挂载点

1
mkdir -p /mnt/usbdisk

挂载点命名与 unit 文件名必须对应
/mnt/usbdisk → unit 文件名为 mnt-usbdisk.mount(斜杠换短横线)。
如果你改成 /mnt/my_disk,unit 文件名就要改成 mnt-my_disk.mount

Step 3:编写 systemd .mount unit

根据你的文件系统类型,选择对应的配置。

NTFS 版本

1
2
3
4
5
6
7
8
9
10
11
12
# /etc/systemd/system/mnt-usbdisk.mount

[Unit]
Description=USB NTFS External Disk

[Mount]
What=/dev/disk/by-uuid/A1B2C3D4E5F67890
Where=/mnt/usbdisk
Type=ntfs3

[Install]
WantedBy=multi-user.target

exFAT 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# /etc/systemd/system/mnt-usbdisk.mount

[Unit]
Description=USB exFAT External Disk

[Mount]
What=/dev/disk/by-uuid/1A2B-3C4D
Where=/mnt/usbdisk
Type=exfat
Options=defaults,noatime,nofail,fmask=0000,dmask=0000,x-systemd.device-timeout=5
TimeoutSec=30s

[Install]
WantedBy=multi-user.target

Step 4:编写 udev 热插拔规则

systemd mount unit 只处理开机挂载。要实现插入自动挂载、拔出自动卸载、重插后再次挂载,需要 udev 规则来监听块设备事件。

1
2
3
4
5
6
7
# /etc/udev/rules.d/99-usb-mount.rules

# 插入时挂载(替换 UUID 为你的实际值)
SUBSYSTEM=="block", ACTION=="add", ENV{ID_FS_UUID}=="YOUR-UUID-HERE", TAG+="systemd", ENV{SYSTEMD_WANTS}="mnt-usbdisk.mount"

# 拔出时卸载(防止下次插入时出现 dirty 标记)
SUBSYSTEM=="block", ACTION=="remove", ENV{ID_FS_UUID}=="YOUR-UUID-HERE", RUN+="/usr/bin/systemctl stop mnt-usbdisk.mount"

两处 UUID 都要替换,且必须与 mount unit 中的完全一致(大小写敏感)。

udev 通过 ENV{ID_FS_UUID} 匹配,即使同时插多块 USB 盘也不会混淆。

Step 5:启用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 重新加载 systemd 配置
systemctl daemon-reload

# 重新加载 udev 规则(无需重启)
udevadm control --reload-rules
udevadm trigger

# 手动测试挂载
systemctl start mnt-usbdisk.mount
systemctl status mnt-usbdisk.mount

# 确认挂载成功
df -h /mnt/usbdisk

# 设置开机自动挂载(硬盘存在时生效)
systemctl enable mnt-usbdisk.mount

Step 6:三种场景验证

场景一:开机不插盘

1
2
3
reboot
# 开机后检查,状态应为 inactive (dead),而非 failed
systemctl status mnt-usbdisk.mount

场景二:开机后插盘

1
2
3
4
5
# 插入硬盘,等 2 秒后验证
ls /mnt/usbdisk

# 实时查看 udev 触发日志
journalctl -f | grep -E "usb|usbdisk|ntfs|exfat"

场景三:掉盘模拟(拔出后重插)

1
2
3
4
5
6
7
# 开启实时日志监控
journalctl -f

# 拔出硬盘 → 等 3 秒 → 重新插入
# 日志中应先出现 stop 再出现 start
# 之后 /mnt/usbdisk 应再次可访问
ls /mnt/usbdisk

常见问题排查

问题一:挂载失败,日志显示 “dirty”

Windows 未安全弹出,或 Linux 上次拔盘前未卸载,NTFS 会被标记为 dirty,内核 ntfs3 默认拒绝挂载。exFAT 无此问题。

1
2
3
4
5
# 用 ntfs-3g 工具包修复(这就是保留它的意义)
ntfsfix /dev/sdX1

# 修复后重新挂载
systemctl start mnt-usbdisk.mount

问题二:udev 规则不触发

1
2
3
4
5
# 检查 udev 是否识别到 UUID
udevadm info --name=/dev/sda1 | grep ID_FS_UUID

# 手动测试规则匹配
udevadm test $(udevadm info -q path -n /dev/sda1) 2>&1 | grep -E "uuid|RUN"

问题三:确认当前实际使用的驱动

1
2
3
4
5
# 查看挂载点使用的文件系统类型
mount | grep usbdisk

# 或
findmnt /mnt/usbdisk

参考

https://www.freedesktop.org/software/systemd/man/systemd.mount.html