一:Udev概述
-
udev 是一个用户空间的设备管理器,用于为事件设置处理程序。作为守护进程, udev 接收的事件主要由 linux 内核生成,这些事件是外部设备产生的物理事件。总之, udev 探测外设和热插拔,将设备控制权传递给内核,例如加载内核模块或设备固件。
-
udev 是一个用户空间系统,可以让操作系统管理员为事件注册用户空间处理器。为了实现外设侦测和热插拔,udev 守护进程接收 Linux 内核发出的外设相关事件; 加载内核模块、设备固件; 调整设备权限,让普通用户和用户组能够访问设备。
-
作为 devfsd 和 hotplug 的替代品, udev 还负责管理 /dev 中的设备节点,即添加、链接和重命名节点,取代了 hotplug 和 hwdetect。
-
udev 并行处理事件,具有潜在的性能优势,但是无法保证每次加载模块的顺序,例如如果有两个硬盘, /dev/sda 在下次启动后可能变成 /dev/sdb。
二:Udev结构
-
udev守护进程
udev是由systemd-udevd守护进程管理。
root@ubuntu:/usr/lib/systemd/system# systemctl status systemd-udevd.service
● systemd-udevd.service - udev Kernel Device Manager
Loaded: loaded (/lib/systemd/system/systemd-udevd.service; static; vendor preset: enabled)
Active: active (running) since Wed 2023-02-15 15:20:47 CST; 1h 34min ago
TriggeredBy: ● systemd-udevd-control.socket
● systemd-udevd-kernel.socket
Docs: man:systemd-udevd.service(8)
man:udev(7)
Main PID: 292 (systemd-udevd)
Status: "Processing with 32 children at max"
Tasks: 1
Memory: 48.6M
CGroup: /system.slice/systemd-udevd.service
└─292 /lib/systemd/systemd-udevd
Feb 15 15:20:48 ubuntu.rockchip systemd-udevd[315]: ethtool: autonegotiation is unset or enabled, the speed and duplex are not writable.
Feb 15 15:20:53 ubuntu.rockchip mtp-probe[1264]: checking bus 6, device 2: "/sys/devices/platform/usbhost3_0/fcd00000.usb/xhci-hcd.10.auto/usb6/6-1"
Feb 15 15:20:53 ubuntu.rockchip mtp-probe[1264]: bus: 6, device: 2 was not an MTP device
Feb 15 15:20:53 ubuntu.rockchip systemd-udevd[302]: Using default interface naming scheme 'v245'.
Feb 15 15:20:53 ubuntu.rockchip systemd-udevd[302]: ethtool: autonegotiation is unset or enabled, the speed and duplex are not writable.
-
rules规则文件
-
udev配置文件:
/etc/udev/udev.conf 可能包含#开头的注释,然后有几行选项:
udev_root="/dev/"
#udev_log="err"
udev_rules="/etc/udev/rules.d/"
-
udev规则文件必须以.rules结尾,如果 /usr/lib 和 /etc 这两个目录中有同名文件,则 /etc 中的文件优先:
/etc/udev/rules.d/
/lib/udev/rules.d/
三:Udev命令udevadm
udevadm是udev管理工具,udevadm 配合一个命令和命令指定选项。它控制了udev运行的行为,处理内核事件,控制事件队列,并且提供简单的调试机制。
udevadm [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]
Send control commands or test the device manager.
Commands:
info Query sysfs or the udev database
trigger Request events from the kernel
settle Wait for pending udev events
control Control the udev daemon
monitor Listen to kernel and udev events
test Test an event run
test-builtin Test a built-in command
See the udevadm(8) man page for details.
- 查询设备信息:udevadm info [OPTIONS] [DEVPATH|FILE]
Query sysfs or the udev database.
-h --help Print this message
-V --version Print version of the program
-q --query=TYPE Query device information:
name Name of device node
symlink Pointing to node
path sysfs device path
property The device properties
all All values
-p --path=SYSPATH sysfs device path used for query or attribute walk
-n --name=NAME Node or symlink name used for query or attribute walk
-r --root Prepend dev directory to path names
-a --attribute-walk Print all key matches walking along the chain
of parent devices
-d --device-id-of-file=FILE Print major:minor of device containing this file
-x --export Export key/value pairs
-P --export-prefix Export the key name with a prefix
-e --export-db Export the content of the udev database
-c --cleanup-db Clean up the udev database
-w --wait-for-initialization[=SECONDS]
Wait for device to be initialized
-
查看nvme0n1所有信息
root@ubuntu:~# udevadm info --query=all --name=nvme0n1
P: /devices/platform/fe150000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/nvme/nvme0/nvme0n1
N: nvme0n1
L: 0
S: disk/by-path/platform-fe150000.pcie-pci-0000:01:00.0-nvme-1
S: disk/by-id/nvme-eui.00000000000000000026b7381a662ba5
S: disk/by-uuid/ebd6cc2b-3324-40c8-9c1c-2b3e9a50ef49
S: disk/by-id/nvme-KINGSTON_OM8PGP4128P-A0_50026B7381A662BA
E: DEVPATH=/devices/platform/fe150000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/nvme/nvme0/nvme0n1
E: DEVNAME=/dev/nvme0n1
E: DEVTYPE=disk
E: MAJOR=259
E: MINOR=0
E: SUBSYSTEM=block
E: USEC_INITIALIZED=13761244
E: ID_SERIAL_SHORT=50026B7381A662BA
E: ID_WWN=eui.00000000000000000026b7381a662ba5
E: ID_MODEL=KINGSTON OM8PGP4128P-A0
E: ID_REVISION=ELFKBO.2
E: ID_SERIAL=KINGSTON OM8PGP4128P-A0_50026B7381A662BA
E: ID_PATH=platform-fe150000.pcie-pci-0000:01:00.0-nvme-1
E: ID_PATH_TAG=platform-fe150000_pcie-pci-0000_01_00_0-nvme-1
E: ID_FS_UUID=ebd6cc2b-3324-40c8-9c1c-2b3e9a50ef49
E: ID_FS_UUID_ENC=ebd6cc2b-3324-40c8-9c1c-2b3e9a50ef49
E: ID_FS_VERSION=1.0
E: ID_FS_TYPE=ext4
E: ID_FS_USAGE=filesystem
E: DEVLINKS=/dev/disk/by-path/platform-fe150000.pcie-pci-0000:01:00.0-nvme-1 /dev/disk/by-id/nvme-eui.00000000000000000026b7381a662ba5 /dev/disk/by-uuid/ebd6cc2b-3324-40c8-9c1c-2b3e9a50ef49 /dev/disk/by-id/nvme-KINGSTON_OM8PGP4128P-A0_50026B7381A662BA
E: TAGS=:systemd:
-
查看nvme0n1的path
root@ubuntu:~# udevadm info --query=path --name=nvme0n1
/devices/platform/fe150000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/nvme/nvme0/nvme0n1
-
接收内核发送来的设备事件:udevadm trigger [OPTIONS] DEVPATH
主要用于重放coldplug事件信息(内核在启动时已经检测到了系统的硬件设备,并把硬件设备信息通过sysfs内核虚拟文件系统导出。udev扫描sysfs文件系统,根据硬件设备信息生成热插拔(hotplug)事件,udev再读取这些事件,生成对应的硬件设备文件。由于没有实际的硬件插拔动作,所以这一过程被称为coldplug。)
Request events from the kernel.
-h --help Show this help
-V --version Show package version
-v --verbose Print the list of devices while running
-n --dry-run Do not actually trigger the events
-t --type= Type of events to trigger
devices sysfs devices (default)
subsystems sysfs subsystems and drivers
-c --action=ACTION|help Event action value, default is "change"
-s --subsystem-match=SUBSYSTEM Trigger devices from a matching subsystem
-S --subsystem-nomatch=SUBSYSTEM Exclude devices from a matching subsystem
-a --attr-match=FILE[=VALUE] Trigger devices with a matching attribute
-A --attr-nomatch=FILE[=VALUE] Exclude devices with a matching attribute
-p --property-match=KEY=VALUE Trigger devices with a matching property
-g --tag-match=KEY=VALUE Trigger devices with a matching property
-y --sysname-match=NAME Trigger devices with this /sys path
--name-match=NAME Trigger devices with this /dev name
-b --parent-match=NAME Trigger devices with that parent device
-w --settle Wait for the triggered events to complete
--wait-daemon[=SECONDS] Wait for udevd daemon to be initialized
before triggering uevents
使用方法可参考systemd-udev-trigger.service:
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=udev Coldplug all Devices
Documentation=man:udev(7) man:systemd-udevd.service(8)
DefaultDependencies=no
Wants=systemd-udevd.service
After=systemd-udevd-kernel.socket systemd-udevd-control.socket
Before=sysinit.target
ConditionPathIsReadWrite=/sys
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=udevadm trigger --type=subsystems --action=add
ExecStart=udevadm trigger --type=devices --action=add
-
监听设备事件:udevadm monitor [OPTIONS]
监听内核事件和udev发送的events事件。打印事件发出的设备。可以通过比较内核或者udev事件的时间戳来分析事件时序。
Listen to kernel and udev events.
-h --help Show this help
-V --version Show package version
-p --property Print the event properties
-k --kernel Print kernel uevents
-u --udev Print udev events
-s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem
-t --tag-match=TAG Filter events by tag
root@ubuntu:~# udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processin
KERNEL - the kernel uevent
KERNEL[857.722336] change /devices/platform/usbdrd3_0/fc000000.usb/udc/fc000000.usb (udc)
KERNEL[857.722400] change /devices/virtual/android_usb/android0 (android_usb)
KERNEL[857.722440] change /devices/virtual/android_usb/android0 (android_usb)
UDEV [857.726333] change /devices/platform/usbdrd3_0/fc000000.usb/udc/fc000000.usb (udc)
KERNEL[857.732797] change /devices/platform/usbdrd3_0/fc000000.usb/udc/fc000000.usb (udc)
UDEV [857.733277] change /devices/virtual/android_usb/android0 (android_usb)
UDEV [857.734935] change /devices/platform/usbdrd3_0/fc000000.usb/udc/fc000000.usb (udc)
-
测试:udevadm test [OPTIONS] DEVPATH
Test an event run.
-h --help Show this help
-V --version Show package version
-a --action=ACTION|help Set action string
-N --resolve-names=early|late|never When to resolve names
root@ubuntu:/usr/lib/udev/rules.d# udevadm test --action="add" /devices/platform/fe150000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/nvme/nvme0/nvme0n1
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.
Load module index
Parsed configuration file /usr/lib/systemd/network/99-default.link
Parsed configuration file /usr/lib/systemd/network/73-usb-net-by-mac.link
Created link configuration context.
Reading rules file: /usr/lib/udev/rules.d/1-net-rename.rules
Reading rules file: /usr/lib/udev/rules.d/2-adbd-device.rules
Reading rules file: /usr/lib/udev/rules.d/3-mount-ssd.rules
... ...
Reading rules file: /usr/lib/udev/rules.d/97-hid2hci.rules
Reading rules file: /usr/lib/udev/rules.d/99-systemd.rules
Invalid inotify descriptor.
DEVPATH=/devices/platform/fe150000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/nvme/nvme0/nvme0n1
DEVNAME=/dev/nvme0n1
DEVTYPE=disk
MAJOR=259
MINOR=0
ACTION=add
SUBSYSTEM=block
DEVLINKS=/dev/disk/by-uuid/ebd6cc2b-3324-40c8-9c1c-2b3e9a50ef49 /dev/disk/by-id/nvme-KINGSTON_OM8PGP4128P-A0_50026B7381A662BA /dev/disk/by-id/nvme-eui.00000000000000000026b7381a662ba5 /dev/disk/by-path/platform-fe150000.pcie-pci-0000:01:00.0-nvme-1
ID_SERIAL_SHORT=50026B7381A662BA
ID_WWN=eui.00000000000000000026b7381a662ba5
ID_MODEL=KINGSTON OM8PGP4128P-A0
ID_REVISION=ELFKBO.2
ID_SERIAL=KINGSTON OM8PGP4128P-A0_50026B7381A662BA
ID_PATH=platform-fe150000.pcie-pci-0000:01:00.0-nvme-1
ID_PATH_TAG=platform-fe150000_pcie-pci-0000_01_00_0-nvme-1
ID_FS_UUID=ebd6cc2b-3324-40c8-9c1c-2b3e9a50ef49
ID_FS_UUID_ENC=ebd6cc2b-3324-40c8-9c1c-2b3e9a50ef49
ID_FS_VERSION=1.0
ID_FS_TYPE=ext4
ID_FS_USAGE=filesystem
TAGS=:systemd:
USEC_INITIALIZED=3460267
run: '/etc/api/mountNvmeSSD.sh'
run: '/usr/bin/unshare -m /usr/bin/snap auto-import --mount=/dev/nvme0n1'
Unload module index
Unloaded link configuration context.
- 加载新添加的udev规则:
- 使用
udevadm control --reload-rules
和udevadm trigger
- 重启系统以使更改生效。
四:Udev规则
udev规则文件以行为单位,以“#”开头的行代表注释行,其余的每一行代表一个规则。规则有一系列的键值对组成,键值对之间用逗号分隔。每个规则分成一个或多个匹配和赋值部分。匹配部分用匹配专用的关键字来表示,赋值部分用赋值专用的关键字来表示。匹配键确定规则是否被应用,而赋值键表示分配某值给该键。
-
udev规则匹配键
-
ACTION: 事件 (uevent) 的行为,例如:add( 添加设备 )、remove( 删除设备 )。
-
KERNEL: 内核设备名称,例如:sda, cdrom。
-
DEVPATH: 设备的 devpath 路径。
-
SUBSYSTEM: 设备的子系统名称,例如:sda 的子系统为 block。
-
BUS: 设备在 devpath 里的总线名称,例如:usb。
-
DRIVER: 设备在 devpath 里的设备驱动名称,例如:ide-cdrom。
-
ID: 设备在 devpath 里的识别号。
-
SYSFS{filename}: 设备的 devpath 路径下,设备的属性文件“filename”里的内容。
例如:SYSFS{model}==“ST936701SS”表示:如果设备的型号为 ST936701SS,则该设备匹配该匹配键。
-
ENV{key}: 环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键。
-
PROGRAM: 调用外部命令。
-
RESULT: 外部命令 PROGRAM 的返回结果。
-
udev规则操作符
-
“==”: 比较键、值,若等于,则该条件满足;
-
“!=”: 比较键、值,若不等于,则该条件满足;
-
“=”: 对一个键赋值;
-
“+=”: 为一个表示多个条目的键赋值。
-
“:=”: 对一个键赋值,并拒绝之后所有对该键的改动。目的是防止后面的规则文件对该键赋值。
-
udev规则赋值键
-
NAME:在 /dev下产生的设备文件名。只有第一次对某个设备的 NAME 的赋值行为生效。之后匹配的规则再对该设备的 NAME 赋值行为将被忽略。如果没有任何规则对设备的 NAME 赋值,udev 将使用内核设备名称来产生设备文件。一般系统下设备节点name不能被udev改变,只能增加symlinks。
-
SYMLINK:为/dev/下的设备文件产生符号链接。由于udev只能为某个设备产生一个设备文件,所以为了不覆盖系统默认的udev规则所产生的文件,推荐使用符号链接。
-
OWNER, GROUP, MODE: 为设备设定权限。
-
ATTR{key}:值应该写入事件设备的sysfs属性文件中。
-
ENV{key}:设置设备属性值,以“.”开头的属性不会存储到database,也不会导出到events或外部工具。
-
RUN{type}:增加可执行程序到event设备,当所有规则匹配时。type可取program(默认)或builtin。程序名与参数用空格分隔,可用单引号指定包含空格的参数。
udev仅仅可运行短时间的任务,长时间的任务会阻塞udev后续event,且event处理完后程序会被强制退出(kill)或超时(默认180s)强制退出。
-
udev的值和可调用的替换操作符
-
$kernel, %k: 设备的内核设备名称,例如:sda、cdrom。
-
$number, %n: 设备的内核号码,例如:sda3 的内核号码是 3。
-
$devpath, %p: 设备的 devpath路径。
-
$id, %b: 设备在 devpath里的 ID 号。
-
$sysfs{file}, %s{file}: 设备的 sysfs里 file 的内容。其实就是设备的属性值。$env{key}, %E{key}: 一个环境变量的值。
-
$major, %M: 设备的 major 号。
-
$minor %m: 设备的 minor 号。
-
$result, %c: PROGRAM 返回的结果。
-
$parent, %P: 父设备的设备文件名。
-
$root, %r: udev_root的值,默认是 /dev/。
-
$tempnode, %N: 临时设备名。
-
$name: 当前设备名。
-
%%: 符号 % 本身。
-
$$: 符号 $ 本身。
五:示例
1、修改网卡网络号
-
使用udevadm命令查询以太网独有信息
udevadm info -a -p /sys/class/net/eth1
root@ubuntu:~# udevadm info -a -p /sys/class/net/eth1
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/platform/fe170000.pcie/pci0002:20/0002:20:00.0/0002:21:00.0/net/eth1':
KERNEL=="eth1"
SUBSYSTEM=="net"
DRIVER==""
ATTR{proto_down}=="0"
ATTR{dev_id}=="0x0"
ATTR{mtu}=="1500"
ATTR{name_assign_type}=="4"
ATTR{iflink}=="4"
ATTR{type}=="1"
ATTR{testing}=="0"
ATTR{carrier_changes}=="1"
ATTR{addr_assign_type}=="0"
ATTR{napi_defer_hard_irqs}=="0"
ATTR{operstate}=="down"
ATTR{carrier}=="0"
ATTR{flags}=="0x1003"
ATTR{tx_queue_len}=="1000"
ATTR{carrier_down_count}=="1"
ATTR{dev_port}=="0"
ATTR{ifindex}=="4"
ATTR{gro_flush_timeout}=="0"
ATTR{netdev_group}=="0"
ATTR{address}=="ec:d6:8a:a8:9f:83"
ATTR{speed}=="-1"
ATTR{link_mode}=="0"
ATTR{dormant}=="0"
ATTR{addr_len}=="6"
ATTR{carrier_up_count}=="0"
ATTR{broadcast}=="ff:ff:ff:ff:ff:ff"
ATTR{ifalias}==""
ATTR{duplex}=="unknown"
-
创建rules规则文件
#/usr/lib/udev/rules.d/1-net-rename.rules
SUBSYSTEM=="net", KERNEL=="eth*", KERNELS=="0002:21:00.0", ATTR{address}=="ec:d6:8a:a8:9f:83", NAME="eth1"

2、监控USB网卡掉线
- 使用udevadm monitor找出标志
udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent
KERNEL[54.963617] remove /devices/platform/fe3c0000.usb/usb1/1-1/1-1.3/1-1.3:1.0/net/eth1/queues/rx-0 (queues)
KERNEL[54.963851] remove /devices/platform/fe3c0000.usb/usb1/1-1/1-1.3/1-1.3:1.0/net/eth1/queues/tx-0 (queues)
KERNEL[54.964353] remove /devices/platform/fe3c0000.usb/usb1/1-1/1-1.3/1-1.3:1.0/net/eth1 (net)
UDEV [54.972204] remove /devices/platform/fe3c0000.usb/usb1/1-1/1-1.3/1-1.3:1.0/net/eth1/queues/rx-0 (queues)
UDEV [54.977661] remove /devices/platform/fe3c0000.usb/usb1/1-1/1-1.3/1-1.3:1.0/net/eth1/queues/tx-0 (queues)
KERNEL[54.980536] remove /devices/platform/fe3c0000.usb/usb1/1-1/1-1.3/1-1.3:1.0 (usb)
KERNEL[54.981987] remove /devices/platform/fe3c0000.usb/usb1/1-1/1-1.3 (usb)
- 创建rules规则文件
SUBSYSTEM=="net", ACTION=="remove", KERNEL=="eth1", RUN+="/app.sh"
3、监控UVC热插拔
ACTION=="add"
:这表示规则只在设备被添加时应用。KERNEL=="media*[0-9]"
:这表示规则匹配所有以 media开头并后跟一个数字的设备(例如media0
,media1
,media2
等)。RUN+="/uvcMonitor.sh add %k"
:当规则匹配时,udev
将运行指定的脚本,并将匹配的设备节点(例如/dev/media0
)作为参数传递给脚本(通过%k
占位符)。
SUBSYSTEM=="media", ACTION=="add", KERNEL=="media*[0-9]", RUN+="/uvcMonitor.sh add %k"
SUBSYSTEM=="media", ACTION=="remove", KERNEL=="media*[0-9]", RUN+="/uvcMonitor.sh remove %k"
六:问题处理
1、udev规则调用的挂载不生效
修改:/usr/lib/systemd/system/systemd-udevd.service
PrivateMounts=no
MountFlags=shared