First understand the event flow and ownership (who is responsible for mounting), then act.block-mount already owns the mount right; custom hotplug scripts only perform supplementary actions, never mount a second time.
Determine Task Type
- Configure automount(fstab UCI + block command) — go to Workflow A.
- Write hotplug supplementary scripts(supplementary actions such as LED/scan/notify) — go to Workflow B, first read hotplug-flow。
- Choose kmod(USB controller/filesystem) — read kmod-storage。
- Troubleshoot "plugged in a disk, no response"— trace segment by segment along the event flow → read hotplug-flow。
Prerequisites / Preflight
SSH to the device and verify each item at runtime:
- block command exists:
command -v block. fstools is in DEFAULT_PACKAGES (include/target.mk L21-34); any official image has/sbin/block。 - Whether block-mount is installed:
opkg list-installed | grep block-mountorapk info -e block-mount(in the 25.12 source tree opkg/apk coexist, depending on build configurationUSE_APK, config/Config-build.in L71). nas device type includes block-mount by default (target.mk L44-48), router type by defaultdoes not include it(L52-61)。 - USB link visibility:
ls /sys/class/block/、lsusb、dmesg | tail -20。 - Kernel version:
uname -r— kmod package versions must match it exactly; cross-version modules refuse to load.
Offline Baseline
- OpenWrt upstream-refs:25.12.5(read-through 2026-09-02, not auto-updated). File paths and line numbers refer to that snapshot.
- fstools package installation artifacts (package/system/fstools/Makefile L112-117):
/etc/hotplug.d/block/10-mount← files/mount.hotplug/etc/hotplug.d/block/00-media-change← files/media-change.hotplug/etc/uci-defaults/10-fstab← files/fstab.default/etc/init.d/fstab← files/fstab.init(START=11)
- Verified evidence: procd hotplug.json, base-files sbin/hotplug-call, kernel modules fs.mk/usb.mk.
Contracts (event flow and ownership; do not fabricate when uncertain)
- Hotplug event flow: kernel uevent → procd matches by hotplug.json rules →
exec /sbin/hotplug-call %SUBSYSTEM%(procd hotplug.json L47, L84-85) → hotplug-call sources/etc/hotplug.d/$1/*forlsone by one in - Mount ownership: block-mount's
10-mountruns/sbin/block hotplugupon receiving add/remove (mount.hotplug is one line in full); what gets mounted is determined by fstab UCI. - First-boot contract:
/etc/uci-defaults/10-fstabruns/etc/config/fstabonly whenblock detect > /etc/config/fstabdoes not exist (fstab.default is one line in full). - Boot contract:
/etc/init.d/fstabSTART=11:boot() → /sbin/block mount,stop() → /sbin/block umount(fstab.init)。 - kmod contract: storage and filesystem modules are auto-loaded via AUTOLOAD/AutoProbe (kmod-usb-storage
AutoProbe usb-storage,usb.mk L1093-1100;fs-btrfsAutoLoad,30, fs.mk L67-77). See references/kmod-storage.md for the package matrix. - Filesystem capabilities in one sentence: kmod-fs-ntfs3 / kmod-fs-exfat make NTFS/exFAT "mountable and writable"; but data protection such as bad-block isolation and self-healing is a capability of native filesystems like ext4 (and btrfs), so prefer ext4 for long-term data disks.
Capability Boundaries + Hand-off
Not covered: baking packages/files into firmware at build time; init.d service scaffolding; teaching upper-layer services such as RAID/LVM and Samba/NFS.
| User Intent | Assigned To |
|---|---|
| Preset block-mount/kmod/custom fstab/50- scripts into the image at build time | openwrt-image-build |
| procd init.d services, rc.common scaffolding | openwrt-procd-init |
Workflow A: Automatically mount when a USB drive is plugged in
-
Install packages(runtime installation; build-time presetting hand-off
openwrt-image-build):opkg update opkg install block-mount kmod-usb-storage kmod-fs-ext4 # NTFS 盘加 kmod-fs-ntfs3;exFAT 加 kmod-fs-exfat;btrfs 加 kmod-fs-btrfs -
Generate an fstab draft:
block detect > /etc/config/fstab(Same-origin logic as first-boot uci-defaults 10-fstab, fstab.default). -
Edit the target entry:
uci set fstab.@mount[-1].target='/mnt/sda1' uci set fstab.@mount[-1].enabled='1' uci commit fstabChoose either the uuid or device attribute; for field semantics see references/fstab-uci.md.
-
Mount immediately and verify:
block mount && df -h;block infoCheck device recognition and filesystem type. -
Reboot to verify the boot chain: after reboot
df -his still present (S11block mounttakes effect);logread | grep -i mount。
Workflow B: attach a hotplug script (supplementary only)
Rules of collaboration:Do not write your own mount logic. 10-mount is already responsible for mounting; if your script also mounts, it will compete with block hotplug (double mounts, stepping on each other's umount). Correct pattern:
-
Sequence number > 10(runs after 10-mount):
/etc/hotplug.d/block/50-<name>。 -
Do only what block-mount does not do: health scans, LED indication, notifications, logger checkpoints.
-
Script template:
#!/bin/sh # /etc/hotplug.d/block/50-my-disk — 附加动作,绝不 mount(10-mount 已负责) [ "$ACTION" = "add" ] || exit 0 case "$DEVNAME" in sd[a-z]) : ;; *) exit 0 ;; esac logger -t my-disk "new disk $DEVNAME" ( [ -x /usr/bin/my-disk-hook ] && /usr/bin/my-disk-hook "/dev/$DEVNAME" >/dev/null 2>&1 & ) exit 0This pattern comes from a real example in a tested repository
50-tinynas-disk(openwrt-imagebuilder/common/tinynas-files/etc/hotplug.d/block/): the file header comment is the rule ("do not mount! block-mount 10-mount is already responsible for mounting"), and it only queues a quick background scan of sdX forrotational=1, calling the tool only if it exists and logging with logger if it does not. -
Debugging: in the script use
env > /tmp/hotplug.envto capture event variables;logreadto see hotplug-call output. For step-by-step troubleshooting of the event flow see references/hotplug-flow.md.
Validation Gates
Layer by evidence; when there is no device, mark all conclusions as Pending HIL:
- Event arrival: plug in the device,
logread -fshows hotplug activity;ls /sys/class/block/a new disk appears. - fstab generation:
uci show fstabeach mount has target, uuid/device, and enabled=1. - Mount success:
df -hthe target appears;touch <target>/.rw && rm <target>/.rwwrite test passes. - Survives reboot: after reboot df is still present — proving S11
block mounttakes effect, rather than relying only on this manual mount. - Failure symptoms:
dmesgunknown filesystem appears /block mountsilently not mounting → usually a missing fs kmod; go back to Workflow A step 1 to check the package matrix.
Pitfalls
- Do notwrite your own hotplug mount script to compete with 10-mount — the single source of truth for mounting is fstab UCI; double mounts/umount races create a risk of data corruption.
- Do notuse a sequence number ≤ 10 —
00-media-change、10-mountis already taken by fstools; running earlier than 10 means it runs beforeblock hotplug. - Do notrun long synchronous work in a hotplug script — hotplug-call sources scripts synchronously in lexical order, which blocks subsequent scripts and procd event handling; background it.
- Do notassume
/etc/config/fstabalways exists — it is conditionally generated by first-boot uci-defaults 10-fstab; containers/custom images may not have it, so firstblock detect。 - Do notmix uuid and device in the same entry — choose one; for semantics see references/fstab-uci.md.
- Do notinstall mismatched kmods arbitrarily — the version must equal
uname -r; cross-version insmod is rejected outright. - Do notUsing an NTFS/exFAT disk as a long-term data disk — it can be mounted and written to, but bad block isolation and self-healing are native ext4 capabilities.
Official Sources
- https://openwrt.org/docs/guide-user/storage/wextexternal(official external storage guide)
- https://openwrt.org/docs/guide-user/base-system/hotplug(official hotplug guide)
- https://git.openwrt.org/?p=project/fstools.git(block/fstools upstream source code)
- https://downloads.openwrt.org/releases/25.12.5/(package index; verify the kmod version against the target platform)
Privacy
- No collection or external transmission of user data;
block detectthe output contains only device facts such as disk UUID/model. - Troubleshooting output (dmesg/logread) may contain internal network topology and hostnames: keep analysis local, and do not paste large chunks of logs verbatim in replies.
- Disk serial numbers/UUIDs are device identifiers; it is recommended that users redact them before external transmission.