mdev vs udev: What Fits a Small Embedded Rootfs

On a small embedded rootfs, device nodes and hotplug usually fork into BusyBox mdev (hotplug helper + mdev -s to seed /dev) versus full udev / systemd-udevd (daemon that consumes kernel uevents and matches .rules).

BusyBox docs/mdev.txt describes two primary uses: initial population and dynamic updates. Both need sysfs mounted at /sys; dynamic updates also need kernel hotplug. udev(7)-family docs describe udevd receiving add/remove/change uevents and matching configured rules against device attributes to create nodes, symlinks, and extra device info.

This post stays on three axes only: when mdev fits · when udev is needed · rule-migration caveats. No invented board timings, prices, or affiliates.

Grounded in BusyBox mdev.txt (and BusyBox examples/mdev.conf), udev(7), and systemd-udevd.

When does mdev fit?

One-line answer: Prefer mdev when the root is small, BusyBox is already present, and you only need node creation, ownership/mode, simple rename/helpers. If the contract is “ship distro .rules unchanged,” mdev is the wrong tool.

Typical BusyBox init sketch:

mount -t proc proc /proc
mount -t sysfs sysfs /sys
echo /sbin/mdev > /proc/sys/kernel/hotplug   # or: sysctl kernel.hotplug=/sbin/mdev
mdev -s
# optional: tmpfs on /dev, mkdir /dev/pts, mount -t devpts …
ConditionLean mdevWhy (docs)
BusyBox image, initramfs, recovery rootStrongSeed + hotplug without a separate udev daemon
Default root:root 660 plus a few permission tweaksStrong/etc/mdev.conf is optional; unmatched → 0:0 660
Match by device-name regex, maj/min, or $ENV=OKFirst field: regex / @maj,min / $envvar=
Rename, symlink, suppress nodeOK=path, >path (move + symlink), ! (no node)
Short shell command on add/removeLimited@ / $ / * via system(); needs /bin/sh; stdio → /dev/null
Firmware load pathSupportedLoad requested names from /lib/firmware/
Deep ATTRS{} parent walks / ID_* persistent namesWeakDifferent matching model than udev rules

mdev.conf parsing stops at the first matching line unless the line starts with -. To override the default, add a total-match line such as .* uid:gid mode (documented pattern).

Do not: generalize from invented “mdev was N ms faster on our board” numbers. Choose by rootfs budget × matching depth.

When is udev required?

One-line answer: You need udev/systemd-udevd when the contract is attribute-based matching, persistent names, distro .rules, or udevadm workflows. A small rootfs does not cancel that contract.

udev collects rules from /usr/lib/udev/rules.d, /run/udev/rules.d, /etc/udev/rules.d, and processes them in lexical order (same basename: higher-priority path wins). Match keys include KERNEL, SUBSYSTEM, ATTR{…}, parent walks via ATTRS{…} / KERNELS / SUBSYSTEMS, ENV{…}, PROGRAM / RESULT. Assignments include NAME, SYMLINK, OWNER/GROUP/MODE, RUN, and more.

ConditionLean udevWhy
Stable symlinks by USB/serial/disk ID or pathStrongEveryday ATTRS{idVendor} + SYMLINK+= patterns
Must consume vendor/distro .rules as shippedStrongNot compatible with mdev.conf syntax
udevadm test / monitor / control --reload-rulesStrongDebug/reload contract lives on the udev side
systemd image with device units / Wants integrationStrongsystemd-udevd + property/tag model
Short foreground PROGRAM/RUN helpersOK (careful)Docs: not for long-running programs
Only create nodes and tweak modesOverkillmdev often enough

Bottom line: udev’s value is not only “make a node,” but reading the attribute graph and pinning stable names, modes, and follow-ups in rules. If that rule set is product contract, ship udev even on a tight flash budget.

Rule migration caveats?

One-line answer: No 1:1 mechanical translation. mdev.conf and udev .rules differ in match model, evaluation order, and helper environment. Re-state the intent (owner/mode, name, when to run a helper).

AxisBusyBox mdevudev / systemd-udevd
Configoptional /etc/mdev.confmany *.rules dirs, lexical order
Stop conditionfirst match (continue if leading -)multiple rules apply (=, +=, :=)
Keysname regex, @maj,min, $ENV=KERNEL / SUBSYSTEM / ATTR / ATTRS / ENV / PROGRAM…
Renames=path / >pathNAME, SYMLINK+=
Helpers@/$/* → system() shellRUN{program}; short foreground; prefer absolute paths
Event path/proc/sys/kernel/hotplug → mdevdaemon receives netlink uevents
Orderingoptional /dev/mdev.seq SEQNUM serializedaemon queue + rule engine (different model)

Migration checklist (doc-aligned sketch):

1. State intent in one line: owner/mode? stable name? helper on add?
2. If the udev rule needs ATTRS/parents/ID_* → do not invent a “similar” mdev regex
3. If staying on mdev: redesign regex + first-match / leading-
4. Helpers: mdev needs /bin/sh and stdio=/dev/null; udev RUN forbids long jobs
5. Do not enable both hotplug helper and udevd on the same events
6. Smoke real add/remove on the target (no host-only verification)

Warning: Pasting a .rules file into mdev.conf does not work. Likewise, do not treat a one-line mdev @modprobe "$MODALIAS" as equivalent to udev’s richer module-load and property rules.

FAQ

Does mdev -s alone cover hotplug?

No. mdev -s seeds nodes for devices already present (via /sys). Later add/remove needs mdev registered as the hotplug helper (echo /sbin/mdev > /proc/sys/kernel/hotplug, etc.—documented sketch).

Does firmware loading work with mdev?

BusyBox docs say place firmware under /lib/firmware/; the kernel requests a filename and mdev loads it. Exact names are hardcoded in the kernel/driver—check those docs.

If we run systemd, are devices “automatic” without udev?

Device management is usually systemd-udevd plus rules. “We use systemd” is not the same design decision as “our udev rule contract.”

Can both be registered as hotplug helpers?

Not recommended. Kernel hotplug helper and udevd handling the same events can fight over nodes and modes. Pick one device manager per image.

What should you remember?

Small root + simple nodes/modes → mdev. Attributes, persistent names, distro rules, udevadm → udev. Rule syntax does not port. Migrate intent and smoke-test on the target. No invented board footprints or affiliates.

Where are the official sources?