欢迎光临
我们一直在努力

Linux 设备管理器:udev、mdev 与现代嵌入式根文件系统构建系统的设备管理方案

Linux 设备管理器:udev、mdev 与现代嵌入式根文件系统构建系统的设备管理方案

适用内核版本:Linux 2.6.13+(udev),Linux 2.6+(mdev via BusyBox) 覆盖范围:设备管理器(udev / mdev / eudev / procd-hotplug)及 Buildroot、Yocto、OpenWrt 等根文件系统构建系统的设备管理方案


目录

  • 概述
  • 历史演进:从 devfs 到 udev、mdev 与现代嵌入式方案
  • udev 详解
  • mdev 详解
  • 现代嵌入式根文件系统构建系统下的设备管理器
  • 核心机制对比
  • 配置方式对比
  • 版本演进与关键里程碑
  • 使用场景选择指南
  • 实际配置示例
  • 从 udev 迁移到 mdev 的实践
  • 附录:常见问题

  • 一、概述

    在 Linux 系统中,设备管理器负责动态创建/删除 /dev 下的设备节点,响应内核的热插拔事件,并执行相应的权限设置、符号链接创建、驱动加载等操作。

    设备管理器/机制定位体量依赖典型场景
    udev 桌面/服务器级标准设备管理器 ~1MB+ systemd(现代)或独立运行 PC、服务器、复杂嵌入式
    mdev BusyBox 内置轻量级设备管理器 ~10KB BusyBox 资源受限且使用 BusyBox 的嵌入式系统
    eudev udev 的 systemd 无关分支 ~1MB 无 systemd 依赖 不使用 systemd 的桌面/服务器
    procd + hotplug OpenWrt 自研热插拔事件分发机制 ~几十KB procd / ubus / devtmpfs OpenWrt 路由器/网关
    devfs 早期内核态设备文件系统 内核内 内核内置 2.4 内核时代(已废弃)

    核心口诀:udev 大而全,mdev 小而快;udev 用 netlink,mdev 用 hotplug。

    补充:在构建系统层面,Buildroot 可在 devtmpfs only / mdev / eudev / systemd-udev 之间切换;Yocto 默认使用 udev(eudev),可选 busybox-mdev 或 systemd;OpenWrt 默认使用 procd + hotplug 而非 mdev/udev。


    二、历史演进:从 devfs 到 udev、mdev 与现代嵌入式方案

    2.1 六个阶段

    在这里插入图片描述

    上图:Linux /dev 管理从静态节点、devfs、udev、devtmpfs、mdev 一路演进,到现代嵌入式构建系统时代分化为 Buildroot、Yocto、OpenWrt 三条典型路线。

    时间轴解读:

    阶段关键事件解决的问题
    静态节点 mknod 手动创建 /dev/xxx 早期 Linux 无动态设备管理能力
    devfs 2.4.x 内核态动态设备文件系统 首次支持动态创建设备节点,但命名僵化、Bug 多
    udev 2.6.13 引入用户态守护进程 将设备管理迁出内核,规则灵活,支持持久化命名
    devtmpfs 2.6.32 内核自动创建基本节点 解决启动早期 /dev 为空的问题
    mdev BusyBox 内置轻量方案 资源受限嵌入式场景的最小化选择
    构建系统分化 ~2010+ 后 Buildroot/Yocto/OpenWrt 各成体系 同一硬件在不同构建系统中可采用不同 /dev 管理策略

    2.2 为什么 devfs 被废弃?

    问题说明
    命名不灵活 设备名称由内核硬编码,无法自定义
    Bug 未修复 作者停止维护,存在 race condition 等问题
    内核内存占用 大量设备时消耗显著内存
    错误加载驱动 对不存在的设备节点也会尝试加载驱动,浪费资源
    内核态实现 设备管理逻辑应在用户空间,devfs 违背这一原则

    udev 的设计正是为了解决 devfs 的上述问题:将设备管理从内核态迁移到用户态,通过规则文件实现灵活配置。

    2.3 嵌入式时代的方案分化

    随着 devtmpfs 成熟,现代嵌入式系统不再只有“udev 或 mdev”二选一,而是根据构建系统和资源约束出现了多条路线:

    阶段代表方案核心特征
    静态节点时代 mknod + device table 构建时固定节点,无动态插拔能力
    内核自治时代 devfs / devtmpfs 内核自动创建/删除基本节点
    全功能用户态时代 udev / eudev / systemd-udevd netlink 异步事件、丰富规则、持久化命名
    极简用户态时代 mdev BusyBox 内置、uevent_helper 同步调用
    自研框架时代 OpenWrt procd + hotplug 不依赖 udev/mdev,基于 ubus 的事件分发

    这种分化使得:同样的嵌入式硬件,在 Buildroot 中可能选 mdev,在 Yocto 中默认用 udev,在 OpenWrt 中则走 procd + hotplug。


    三、udev 详解

    3.1 定位与架构

    udev 是一个用户空间守护进程(udevd),通过监听内核通过 netlink 发送的 uevent 事件来动态管理设备。

    在这里插入图片描述

    上图:udev 从内核检测设备变化开始,经 netlink 广播 uevent,由 udevd 监听、规则匹配引擎处理,最终执行创建设备节点、设置权限、加载固件等用户态动作。

    3.2 核心组件

    组件作用路径
    udevd 守护进程,事件处理主循环 /usr/lib/systemd/systemd-udevd 或 /sbin/udevd
    udevadm 管理工具:查看规则、触发事件、监控日志 /usr/bin/udevadm
    libudev 用户空间库,供应用程序查询设备信息 /usr/lib/libudev.so
    规则文件 定义匹配条件和执行动作 /etc/udev/rules.d/*.rules
    硬件数据库 设备属性数据库 /usr/lib/udev/hwdb.d/

    3.3 事件类型

    事件触发时机典型动作
    add 设备注册到内核 创建 /dev/xxx 节点、设置权限、加载固件
    remove 设备注销 删除节点、清理符号链接
    change 设备状态变化 更新属性、重新评估规则
    bind 驱动绑定设备 创建符号链接、触发服务
    unbind 驱动解绑 移除符号链接
    move 设备重命名 更新节点名

    3.4 持久化命名

    udev 的核心优势之一是持久化设备命名,解决设备名随插拔顺序变化的问题:

    命名方式路径示例用途
    by-id /dev/disk/by-id/usb-Brand_1234-0:0 基于设备唯一标识(序列号)
    by-path /dev/disk/by-path/pci-0000:00:14.0-usb-0:1 基于物理拓扑位置
    by-uuid /dev/disk/by-uuid/xxxx-xxxx 基于文件系统 UUID
    by-label /dev/disk/by-label/MyDisk 基于文件系统卷标

    四、mdev 详解

    4.1 定位与架构

    mdev 是 BusyBox 内置的轻量级设备管理器,专为资源受限的嵌入式系统设计。它不是独立项目,而是 BusyBox 的一个 applet。

    在这里插入图片描述

    上图:mdev 基于 uevent_helper 机制,内核产生事件时直接调用 /sbin/mdev,读取 /etc/mdev.conf 后同步执行创建/删除节点、设置权限或自定义命令等动作。

    4.2 两种工作模式

    模式命令用途
    热插拔模式 echo /sbin/mdev > /proc/sys/kernel/hotplug 内核产生 uevent 时自动调用 mdev
    扫描模式 mdev -s 系统启动时扫描 /sys/class 和 /sys/block,批量创建设备节点

    4.3 与 BusyBox 的关系

    mdev 不是独立软件包,而是 BusyBox 编译时可选的一个功能:

    # 配置 BusyBox 时启用 mdev
    make menuconfig
    # → Linux System Utilities → [*] mdev

    编译后,mdev 作为 busybox 的符号链接存在:

    ls -la /sbin/mdev
    # lrwxrwxrwx 1 root root 7 Jan 1 1970 /sbin/mdev -> busybox


    五、现代嵌入式根文件系统构建系统下的设备管理器

    在嵌入式 Linux 中,根文件系统通常由 Buildroot、Yocto Project、OpenWrt 等构建系统生成。它们对 /dev 管理的设计理念、默认实现和可配置空间各不相同,不能简单地认为“用了 BusyBox 就用 mdev”。本章详细分析这三个主流构建系统的设备管理方案,并给出选择建议。

    5.1 总体对比

    构建系统默认 /dev 方案可选项关键配置入口说明
    Buildroot 通常 Dynamic using devtmpfs only(很多板级 defconfig 会选 devtmpfs + mdev) Static device tabledevtmpfs onlydevtmpfs + mdevdevtmpfs + eudevsystemd-udev(若 init 选 systemd) System configuration → /dev management 官方推荐先用 devtmpfs only,按需升级到 mdev/eudev
    Yocto Project (Poky) SysVinit + udev(实际提供者为 eudev) udev / busybox-mdev / systemd / static pre-populated VIRTUAL-RUNTIME_dev_managerUSE_DEVFSIMAGE_DEVICE_TABLES 工业级构建系统,默认走完整 udev
    OpenWrt procd + hotplug(不是 mdev/udev) 可额外安装 eudev 等包,但默认不走 /etc/hotplug.d/<subsystem>/ 脚本 自研轻量事件分发,设备节点由 devtmpfs 提供

    5.2 Buildroot

    Buildroot 在 System configuration → /dev management 中提供 4 种主要 /dev 管理方式:

  • Static using device table:构建时固定生成节点,不支持动态插拔。
  • Dynamic using devtmpfs only:仅依赖内核 devtmpfs 自动创建/删除节点,用户空间不参与。
  • Dynamic using devtmpfs + mdev:在 devtmpfs 基础上叠加 BusyBox mdev,支持热插拔脚本、固件加载和自定义权限。
  • Dynamic using devtmpfs + eudev:使用独立的 eudev 守护进程,规则能力接近桌面 udev。
  • 若 Init system 选择 systemd,/dev 管理会自动由 systemd 自带的 systemd-udevd 接管。

    官方建议:先用 devtmpfs only,直到出现以下需求再升级:

    • 需要用户态感知设备插入/移除
    • 需要自动加载固件
    • 需要自定义设备节点权限/属组

    此时优先选择 devtmpfs + mdev;若规则复杂或需要持久化命名,再选 eudev。

    典型配置片段(.config):

    BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV=y

    5.3 Yocto Project

    Yocto Project 默认使用 devtmpfs + udev(在 Poky 参考发行版中实际提供者为 eudev)。它通过 VIRTUAL-RUNTIME_dev_manager 变量来选择设备管理器:

    # 默认
    VIRTUAL-RUNTIME_dev_manager = "udev"

    # 轻量方案,使用 BusyBox mdev
    # VIRTUAL-RUNTIME_dev_manager = "busybox-mdev"

    # systemd 方案
    # VIRTUAL-RUNTIME_dev_manager = "systemd"

    同时可通过 USE_DEVFS 控制是否使用动态 /dev:

    # 默认:动态 devtmpfs + 设备管理器
    USE_DEVFS = "1"

    # 静态预填充 /dev
    USE_DEVFS = "0"
    IMAGE_DEVICE_TABLES = "device_table-mymachine.txt"

    Yocto 的灵活性在于:同一套 recipes 可以通过 distro/machine 配置切换设备管理器,而无需修改上层应用包。

    5.4 OpenWrt

    OpenWrt 默认不使用 mdev 也不使用 udev,而是采用自研的 procd 进程管理器处理热插拔事件:

    内核 uevent

    procd(PID 1 的一部分)

    /sbin/hotplug-call <subsystem>

    /etc/hotplug.d/<subsystem>/<script>

    • 设备节点仍由内核 devtmpfs 自动创建。
    • 启动阶段的“冷插拔”(coldplug)由 procd 自带的 udevtrigger 触发。
    • 热插拔脚本按子系统组织,如 /etc/hotplug.d/block/、/etc/hotplug.d/net/、/etc/hotplug.d/usb/。

    只有在运行某些特殊软件(如 ModemManager、容器工具链)时,才会额外安装 eudev 等包来补充 udev 规则能力。

    5.5 选择建议

    场景推荐方案
    极简资源受限系统,仅需基本设备节点 Buildroot: devtmpfs only;Yocto: busybox-mdev;OpenWrt: 默认 procd
    需要热插拔脚本、固件加载、简单权限控制 Buildroot: devtmpfs + mdev;Yocto: busybox-mdev
    需要持久化命名、复杂规则、硬件数据库 Buildroot: devtmpfs + eudev;Yocto: udev/systemd
    与 systemd 深度集成 Yocto: VIRTUAL-RUNTIME_dev_manager = "systemd"

    六、核心机制对比

    6.1 实现机制差异

    维度udevmdev
    事件接收机制 netlink socket(内核 ↔ udevd 守护进程) uevent_helper(内核调用 /proc/sys/kernel/hotplug 指定的程序)
    进程模型 守护进程(udevd),长期运行 无守护进程,每次事件触发新进程
    事件处理 异步(非阻塞,事件队列) 同步(阻塞式,顺序执行)
    并发处理 支持并行处理多个事件 串行处理
    内存占用 ~1MB+(守护进程常驻) ~10KB(仅 busybox 片段)
    启动依赖 需要早期启动 udevd 仅需 busybox 和 /etc/mdev.conf

    6.2 功能对比

    功能udevmdev
    创建设备节点
    设置权限/属主
    符号链接 ✅(有限)
    持久化命名(by-id/by-path)
    固件自动加载 ⚠️(需手动配置)
    热插拔管理 ✅ 完整 ⚠️ 基础
    复杂规则匹配 ✅(丰富的键值匹配) ⚠️(简单正则)
    网络设备管理
    与 systemd 集成
    D-Bus 通信
    硬件数据库(hwdb)
    设备快照
    驱动模块自动加载 ⚠️(有限)

    6.3 性能对比

    指标udevmdev
    内存占用 高(守护进程常驻) 极低(无常驻进程)
    启动时间 较长(需启动 udevd + 扫描规则) 极短(mdev -s 瞬间完成)
    事件响应延迟 低(异步队列) 中等(同步 fork/exec)
    大量事件处理 高效(netlink + 并行) 低效(串行同步)
    CPU 占用 较低 极低

    6.4 嵌入式构建系统方案对比

    前面主要对比了 udev 与 mdev 两个具体实现。但在实际嵌入式项目中,很少单独选择 udev/mdev,而是根据所采用的根文件系统构建系统来决定 /dev 管理方案。

    维度BuildrootYocto ProjectOpenWrt
    定位 轻量根文件系统生成器 工业级 Linux 发行版构建系统 路由器/网关固件发行版
    默认 /dev 方案 devtmpfs only / devtmpfs + mdev(视 defconfig) devtmpfs + udev(实际为 eudev) procd + hotplug
    事件机制 依选择而定:netlink(eudev)或 uevent_helper(mdev) netlink(udev/eudev 或 systemd-udevd) uevent_helper 分发给 hotplug 脚本
    常驻进程 无(mdev)或 eudev/systemd-udevd udevd / systemd-udevd procd(PID 1)
    配置入口 System configuration → /dev management VIRTUAL-RUNTIME_dev_manager /etc/hotplug.d/<subsystem>/
    规则/脚本能力 mdev.conf 简单正则 / eudev rules 完整 udev rules hotplug shell 脚本
    典型场景 极简嵌入式、单板产品 复杂嵌入式、工业产品 路由器、AP、网关
    包管理 无(静态镜像) rpm/deb/ipk 可选 opkg

    关键结论:

    • Buildroot 是“轻量方案超市”,从 devtmpfs only 到 mdev 再到 eudev 都可配置,按资源约束选择即可。
    • Yocto Project 默认提供完整的 udev(eudev)能力,适合需要持久化命名、复杂规则和硬件数据库的工业级系统。
    • OpenWrt 不依赖 udev/mdev,而是用 procd + hotplug 完成事件分发,设备节点由 devtmpfs 提供,适合路由器这类有自研生态的场景。

    七、配置方式对比

    7.1 udev 规则文件

    路径:/etc/udev/rules.d/*.rules(自定义)+ /lib/udev/rules.d/*.rules(系统默认)

    # /etc/udev/rules.d/99-my.rules
    # 语法:匹配条件, 匹配条件, … , 动作, 动作, …

    # 示例1:USB 设备匹配
    SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", \\
    SYMLINK+="my_device", MODE="0660", GROUP="plugdev", \\
    RUN+="/usr/local/bin/setup_device.sh"

    # 示例2:串口设备权限
    KERNEL=="ttyUSB[0-9]*", OWNER="root", GROUP="dialout", MODE="0660"

    # 示例3:块设备自动挂载
    SUBSYSTEM=="block", ENV{ID_TYPE}=="disk", ENV{DEVTYPE}=="partition", \\
    RUN+="/usr/bin/systemd-mount –no-block –automount=yes /dev/%k /mnt/%k"

    # 示例4:systemd 服务触发
    SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", \\
    TAG+="systemd", ENV{SYSTEMD_WANTS}="gps-setup.service"

    udev 规则关键字:

    关键字说明
    SUBSYSTEM 子系统匹配(usb, block, tty 等)
    KERNEL 内核设备名匹配
    ATTR{…} sysfs 属性匹配
    ENV{…} 环境变量匹配/设置
    SYMLINK+="…" 创建符号链接
    MODE="…" 设置权限
    OWNER="…" 设置属主
    GROUP="…" 设置属组
    RUN+="…" 执行外部命令
    TAG+="…" 添加标签(如 systemd)

    7.2 mdev 配置文件

    路径:/etc/mdev.conf

    # /etc/mdev.conf
    # 格式:设备正则 [用户:组] [权限] [@|$*命令]
    # @ = 创建设备前执行
    # $ = 创建设备后执行
    # * = 创建设备后执行(传递环境变量)

    # 示例1:SD 卡分区自动挂载
    mmcblk[0-9]p[0-9]* 0:0 660 $ /etc/mdev/sdhotplug.sh

    # 示例2:USB 串口权限
    ttyUSB[0-9]* root:uucp 660

    # 示例3:视频设备
    video[0-9]* root:video 660

    # 示例4:执行自定义脚本
    sd[a-z][0-9]* 0:0 660 * /etc/mdev/automount.sh

    mdev 环境变量(脚本中可用):

    变量说明
    $MDEV 设备名(如 sda1)
    $ACTION 动作(add/remove)
    $FIRMWARE 固件名(如需加载固件)
    $DEVPATH sysfs 中的设备路径

    7.3 配置复杂度对比

    特性udevmdev
    规则文件语法 复杂(键值对,多条件匹配) 简单(正则 + 权限 + 命令)
    规则文件数量 多文件(按优先级排序) 单文件
    调试工具 udevadm monitor、udevadm test 无专用工具,靠日志
    规则重载 udevadm control –reload-rules 修改即生效(无守护进程)

    7.4 嵌入式构建系统中的配置入口

    与直接在运行系统中编辑规则文件不同,Buildroot/Yocto/OpenWrt 的设备管理方案大部分在构建阶段决定,配置入口也各不相同。

    构建系统配置入口典型配置示例
    Buildroot make menuconfig → System configuration → /dev management BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV=y
    Yocto Project local.conf / distro / machine 配置文件 VIRTUAL-RUNTIME_dev_manager = "udev" / "busybox-mdev" / "systemd"
    OpenWrt /etc/hotplug.d/<subsystem>/ 脚本 + procd /etc/hotplug.d/block/10-mount

    Buildroot 通过 Kconfig 菜单一次性选定 /dev 管理方式,生成镜像后基本不再变更;需要调整时重新编译即可。

    Yocto Project 通过 VIRTUAL-RUNTIME_dev_manager 等变量在 recipe 层抽象设备管理器, distro 或 machine 配置切换方便,同一套上层 recipes 不需要改动。

    OpenWrt 没有统一的“规则文件”,热插拔逻辑分散在 /etc/hotplug.d/ 下的 shell 脚本中,灵活性高但规则能力取决于脚本自身,调试也主要靠日志和手动触发。


    八、版本演进与关键里程碑

    8.1 时间线

    在这里插入图片描述

    上图:从静态节点、devfs、udev、devtmpfs、mdev,到 systemd-udevd、eudev,再到当前构建系统分化的时间线。

    8.2 关键版本对照表

    机制/项目首次引入成熟/强制版本当前状态
    静态设备节点 Linux 0.01 仅特殊场景使用
    devfs 2.3.46 (2001) 2.4 2.6.13 移除,已废弃
    udev 2.6.13 (2005) 2.6.15 主流桌面/服务器标准
    udev 持久化命名 2.6.15 (2006) 2.6.30 沿用至今
    devtmpfs 2.6.32 (2009) 3.0+ 现代系统标配
    mdev (BusyBox) ~2006 ~2009 嵌入式标准
    systemd-udevd ~2012 (systemd 183+) 3.x+ systemd 发行版标配
    eudev ~2012 4.x+ 非 systemd 发行版选择

    九、使用场景选择指南

    9.1 选择 mdev 的场景

    场景原因
    ✅ 内存 < 64MB 的嵌入式系统 mdev 仅占用 ~10KB,无守护进程常驻
    ✅ 使用 BusyBox 的 initramfs/initrd mdev 已内置于 BusyBox,无需额外依赖
    ✅ 要求极简启动(< 2 秒) mdev -s 瞬间完成,无需启动守护进程
    ✅ 设备管理需求简单 仅需创建节点、设置权限,无复杂规则
    ✅ 无热插拔复杂需求 偶尔插拔 USB/SD 卡,mdev 足够处理
    ✅ 无桌面环境 无 KDE/GNOME/Xorg 等依赖 udev 的组件
    ✅ 容器/轻量级虚拟化 资源敏感,mdev overhead 极低

    典型使用 mdev 的发行版/项目:

    • Alpine Linux(默认使用 mdev,可选 eudev)
    • Buildroot 生成的嵌入式系统(常选 Dynamic using devtmpfs + mdev)
    • Yocto 的 busybox-mdev 方案(非 Poky 默认,需显式配置)
    • 各类定制嵌入式 Linux

    注意:OpenWrt 默认并不使用 mdev,而是使用自研的 procd + hotplug 体系,详见第五章。

    9.2 选择 udev 的场景

    场景原因
    ✅ 桌面/服务器系统 需要完整的设备管理、持久化命名、硬件数据库
    ✅ 复杂的热插拔处理 USB 设备频繁插拔,需要稳定设备名
    ✅ 多用户环境 需要动态权限管理、属组分配
    ✅ 与 systemd 深度集成 systemd 依赖 udev 进行设备触发和服务管理
    ✅ 需要网络设备管理 udev 支持网络接口重命名、MAC 绑定
    ✅ 需要高级功能 固件自动加载、D-Bus 通信、设备快照
    ✅ 存储设备多 需要 by-id/by-path/by-uuid 持久化命名

    典型使用 udev 的发行版/项目:

    • Ubuntu/Debian/Fedora/Arch(systemd-udevd)
    • RHEL/CentOS/Rocky Linux(systemd-udevd)
    • Gentoo(可选 udev 或 eudev)
    • Yocto Project / Poky(默认使用 eudev,也可切换为 systemd-udev)
    • 使用 systemd 的嵌入式发行版

    9.3 选择 eudev 的场景

    场景原因
    ✅ 不使用 systemd 但需要完整 udev 功能 eudev 是 udev 的 systemd 无关分支
    ✅ 非 systemd 桌面/服务器系统 Gentoo、Alpine(可选)等发行版
    ✅ 嵌入式系统拒绝 systemd 依赖 Buildroot 可选 devtmpfs + eudev,Yocto 也可配置 eudev

    9.4 选择 OpenWrt procd + hotplug 的场景

    场景原因
    ✅ 路由器 / AP / 网关设备 OpenWrt 原生为此类设备设计,procd 同时管理进程与热插拔
    ✅ 已基于 OpenWrt 生态开发 需要与 netifd、ubus、procd 等组件协同
    ✅ 资源受限且需要网络事件处理 不需要额外运行 udev/mdev 守护进程
    ✅ 偏好 shell 脚本处理设备事件 /etc/hotplug.d/ 下直接写脚本,无需学习 udev rules
    ✅ 设备节点由 devtmpfs 足够提供 不需要 udev/mdev 额外创建或管理节点

    典型使用 procd + hotplug 的项目:

    • OpenWrt 官方及衍生固件
    • 各类路由器、网关、AP 定制发行版

    十、实际配置示例

    10.1 场景:USB 摄像头插入处理

    mdev 方式:

    # /etc/mdev.conf
    video[0-9]* root:video 660 @/etc/mdev/camera_setup

    # /etc/mdev/camera_setup
    #!/bin/sh
    if [ "$ACTION" = "add" ]; then
    v4l2-ctl –set-fmt-video=width=640,height=480
    /usr/bin/start_streaming
    fi

    udev 方式:

    # /etc/udev/rules.d/99-camera.rules
    SUBSYSTEM=="video4linux", ATTR{index}=="0", \\
    TAG+="systemd", ENV{SYSTEMD_WANTS}="camera-stream.service"

    # systemd 服务自动管理(/etc/systemd/system/camera-stream.service)

    10.2 场景:SD 卡自动挂载

    mdev 方式:

    # /etc/mdev.conf
    mmcblk[0-9]p[0-9]* 0:0 660 $ /etc/mdev/sdhotplug.sh

    # /etc/mdev/sdhotplug.sh
    #!/bin/sh
    case $ACTION in
    add) mount /dev/$MDEV /mnt/sd ;;
    remove) umount /mnt/sd ;;
    esac

    udev 方式:

    # /etc/udev/rules.d/99-sd.rules
    SUBSYSTEM=="block", ENV{ID_TYPE}=="disk", ENV{DEVTYPE}=="partition", \\
    RUN{program}+="/usr/bin/systemd-mount –no-block –automount=yes /dev/%k /mnt/%k"

    10.3 场景:串口设备权限

    mdev 方式:

    # /etc/mdev.conf
    ttyACM[0-9]* root:dialout 660
    ttyUSB[0-9]* root:dialout 660

    udev 方式:

    # /etc/udev/rules.d/50-serial.rules
    SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", OWNER="root", GROUP="dialout", MODE="0660"
    SUBSYSTEM=="tty", KERNEL=="ttyUSB[0-9]*", OWNER="root", GROUP="dialout", MODE="0660"

    10.4 场景:OpenWrt 下 USB 存储自动挂载

    OpenWrt 不依赖 udev/mdev,而是通过 /etc/hotplug.d/block/ 下的 shell 脚本处理块设备热插拔。

    插入时自动挂载:

    # /etc/hotplug.d/block/10-mount
    #!/bin/sh

    [ "$ACTION" = "add" ] || exit 0
    [ "$DEVTYPE" = "partition" ] || exit 0

    mkdir -p /mnt/$DEVNAME
    mount /dev/$DEVNAME /mnt/$DEVNAME

    移除时自动卸载:

    # /etc/hotplug.d/block/20-umount
    #!/bin/sh

    [ "$ACTION" = "remove" ] || exit 0

    umount -l /mnt/$DEVNAME
    rmdir /mnt/$DEVNAME 2>/dev/null

    说明:$ACTION、$DEVNAME、$DEVTYPE 等环境变量由 procd 的 /sbin/hotplug-call 在调用脚本前注入。

    10.5 场景:Yocto 下为自定义设备添加 udev 规则

    Yocto Project 默认使用 udev(实际提供者为 eudev)。自定义设备规则通常通过单独 recipe 打包到镜像中,而不是手动修改目标系统。

    1. 确保设备管理器为 udev:

    # build/conf/local.conf
    VIRTUAL-RUNTIME_dev_manager = "udev"

    2. 创建 udev rules recipe:

    # meta-mylayer/recipes-core/my-udev-rules/my-udev-rules.bb
    SUMMARY = "Custom udev rules for my device"
    LICENSE = "MIT"

    SRC_URI = "file://99-my-device.rules"

    S = "${WORKDIR}"

    do_install() {
    install -d ${D}${sysconfdir}/udev/rules.d
    install -m 0644 ${WORKDIR}/99-my-device.rules ${D}${sysconfdir}/udev/rules.d/
    }

    FILES:${PN} += "${sysconfdir}/udev/rules.d/99-my-device.rules"

    3. 编写规则文件:

    # meta-mylayer/recipes-core/my-udev-rules/files/99-my-device.rules
    # 为指定 VID/PID 的 USB 设备创建固定符号链接并设置权限
    SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", \\
    SYMLINK+="my_device%n", MODE="0660", GROUP="plugdev"

    4. 将规则包加入镜像:

    # image recipe 或 local.conf
    IMAGE_INSTALL:append = " my-udev-rules"

    说明:这样构建出的镜像启动后会自动加载 /etc/udev/rules.d/99-my-device.rules,无需在目标板上手动维护规则文件。

    10.6 场景:Buildroot 下切换 /dev 管理方式

    Buildroot 在构建阶段通过 Kconfig 菜单决定 /dev 管理方式,无需在目标系统中手动安装或切换。

    菜单路径:

    make menuconfig
    → System configuration
    → /dev management
    → Dynamic using devtmpfs + mdev

    等价 .config 片段(使用 mdev):

    BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV=y

    若需要完整 udev 能力,改为 eudev:

    BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y

    重新执行 make 后,生成的根文件系统镜像即使用选定的设备管理器。目标板上无需再修改 /etc/mdev.conf 或 /etc/udev/rules.d/ 之外的构建配置。


    十一、从 udev 迁移到 mdev 的实践

    11.1 迁移检查清单

    # 1. 检查哪些包依赖 udev
    equery depends udev # Gentoo
    apt-cache rdepends udev # Debian/Ubuntu
    rpm -q –whatrequires udev # RHEL

    # 2. 检查是否使用 LVM(mdev 对 LVM 支持有限)
    lvscan

    # 3. 检查是否使用桌面环境(KDE/GNOME 依赖 udev)
    # 如果有,不建议迁移到 mdev

    11.2 迁移步骤(以 Gentoo 为例)

    # 1. 确保 BusyBox 编译了 mdev
    make menuconfig
    # → Linux System Utilities → [*] mdev

    # 2. 安装 busybox(静态链接 + mdev 支持)
    echo 'sys-apps/busybox static mdev -pam' >> /etc/portage/package.use
    emerge -av busybox

    # 3. 配置 mdev
    cp /opt/mdev/mdev.conf /etc/mdev.conf

    # 4. 设置 uevent_helper
    echo "/sbin/mdev" > /proc/sys/kernel/hotplug

    # 5. 系统启动时扫描创建设备
    mdev -s

    # 6. 添加 mdev 到启动级别
    rc-update add mdev sysinit

    # 7. 移除 udev
    rc-update del udev sysinit
    rc-update del udev-mount sysinit
    emerge –unmerge -a sys-fs/udev virtual/udev

    # 8. 屏蔽 udev(防止被重新安装)
    echo "sys-fs/udev" >> /etc/portage/package.mask/udev

    11.3 规则迁移对照

    mdev 规则udev 等效规则
    sda[0-9]* root:disk 660 KERNEL=="sda[0-9]*", OWNER="root", GROUP="disk", MODE="0660"
    ttyACM[0-9]* 0:0 660 @/usr/local/bin/gps_setup.sh SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", RUN+="/usr/local/bin/gps_setup.sh"
    mmcblk[0-9]p[0-9]* 0:0 660 $ /etc/mdev/sdhotplug.sh SUBSYSTEM=="block", KERNEL=="mmcblk[0-9]p[0-9]*", RUN+="/etc/mdev/sdhotplug.sh"

    11.4 常见问题

    问题原因解决
    /dev/shm 仅 root 可写 无 udev-mount 脚本 启动脚本添加 chmod 1777 /dev/shm
    lsusb 不工作 依赖 udev 的 usbids 数据库 安装 usbutils 或使用 cat /sys/kernel/debug/usb/devices
    网络接口未重命名 mdev 无网络设备管理 使用 nameif + /etc/mactab 基于 MAC 重命名
    设备节点权限不对 mdev.conf 规则未配置 检查 /etc/mdev.conf 正则匹配和权限设置
    Xorg 输入设备异常 Xorg 依赖 udev 检测输入设备 手动配置 /etc/X11/xorg.conf.d/ 的 InputDevice 段

    十二、附录:常见问题

    Q1:mdev 能完全替代 udev 吗?

    不能。mdev 是 udev 的功能子集,适合简单场景。以下功能 mdev 无法提供:

    • 持久化设备命名(by-id/by-path/by-uuid)
    • 硬件数据库(hwdb)查询
    • 与 systemd 的服务触发集成
    • 复杂的规则匹配逻辑
    • 网络设备管理

    Q2:devtmpfs 和 udev/mdev 是什么关系?

    互补关系:

    • devtmpfs(内核态):设备注册时自动创建基本节点(root:root, 0600),确保启动早期 /dev 不为空
    • udev/mdev(用户态):后续调整权限、属组、符号链接,执行自定义动作

    现代 Linux 系统中,devtmpfs 是 /dev 的基础,udev/mdev 在其之上做增强管理。

    Q3:为什么 Alpine Linux 默认使用 mdev?

    Alpine Linux 的设计哲学是极小化、安全、简单。mdev 完美契合:

    • 无守护进程,攻击面小
    • 内存占用极低
    • 无需额外依赖(已内置于 busybox)
    • 容器和嵌入式场景足够

    Alpine 也提供 eudev 作为可选包,供需要完整设备管理的用户安装。

    Q4:如何查看当前系统使用哪种设备管理器?

    # 方法1:检查进程
    ps aux | grep -E "udev|mdev"

    # 方法2:检查 uevent_helper
    cat /proc/sys/kernel/hotplug
    # 输出 /sbin/mdev → 使用 mdev
    # 输出为空 → 使用 udev(netlink 机制)

    # 方法3:检查服务
    rc-status | grep -E "udev|mdev" # OpenRC
    systemctl status systemd-udevd # systemd

    # 方法4:检查配置文件
    ls -la /etc/mdev.conf # 存在 → 可能使用 mdev
    ls -la /etc/udev/ # 存在 → 使用 udev
    ls -la /etc/hotplug.d/ # 存在且 procd 运行 → OpenWrt 方案

    # 方法5:OpenWrt 专用
    ubus call service list # 查看 procd 服务
    ls /etc/hotplug.d/block/ # 查看 block 子系统热插拔脚本

    Q5:容器(Docker)中需要设备管理器吗?

    通常不需要。容器共享宿主机的 /dev,设备节点由宿主机管理。但如果容器需要独立 /dev(如 –privileged 或特殊 init 系统),可以使用 devtmpfs 或极简 mdev。


    参考资源

  • BusyBox mdev 官方文档:docs/mdev.txt(BusyBox 源码内)
  • udev 官方文档:man udev、man udevadm、man udev.conf
  • 《Linux Device Drivers, 3rd Edition》 — Jonathan Corbet 等
  • Gentoo Wiki – Mdev:https://wiki.gentoo.org/wiki/Mdev
  • Alpine Linux Wiki – Mdev:https://wiki.alpinelinux.org/wiki/Mdev
  • Yocto Project – Device Manager:https://docs.yoctoproject.org/dev/dev-manual/device-manager.html
  • Yocto Project – Initialization Manager:https://docs.yoctoproject.org/dev/dev-manual/init-manager.html
  • Buildroot User Manual – /dev management:https://buildroot.org/downloads/manual/manual.html
  • OpenWrt – procd:https://openwrt.org/docs/techref/procd

  • 说明:本文覆盖的 Linux 设备管理器包含从 devfs 到 udev、mdev,再到 Buildroot/Yocto/OpenWrt 等嵌入式构建系统方案的完整演进,适用于 Linux 2.6.13+ 至当前 6.x 主线内核。对于资源受限的嵌入式系统,mdev 是轻量首选;对于工业级复杂嵌入式系统,Yocto 默认的 udev/eudev 更合适;对于路由器/网关,OpenWrt 的 procd + hotplug 是原生方案;对于桌面/服务器,udev(或 eudev)是标准选择。

    赞(0)
    未经允许不得转载:171主机测评 » Linux 设备管理器:udev、mdev 与现代嵌入式根文件系统构建系统的设备管理方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址