跳转到内容跳转到页面导航:上一页 [访问键 p]/下一页 [访问键 n]
适用于 openSUSE Leap 15.6

16 使用 udev 进行动态内核设备管理 编辑源

内核几乎可以在正在运行的系统中添加或移除任何设备。设备状态的变化(设备是否插入或移除)需要传播到用户空间。设备在插入和识别时需要进行配置。特定设备的用户需要了解该设备识别状态的任何变化。udev 提供了所需的 инфраструктуру 来动态维护 /dev 目录中的设备节点文件和符号链接。udev 规则提供了一种将外部工具插入到内核设备事件处理中的方式。这允许您通过添加某些脚本作为内核设备处理的一部分来执行,或者请求并导入附加数据以在设备处理期间进行评估,从而自定义 udev 设备处理。

16.1 文件 /dev 目录 编辑源

/dev 目录中的设备节点提供对相应内核设备的访问。使用 udev/dev 目录反映了内核的当前状态。每个内核设备都有一个对应的设备文件。如果设备从系统中断开,则会移除设备节点。

/dev 目录的内容保存在临时文件系统上,所有文件在每次系统启动时都会呈现。手动创建或修改的文件,根据设计,在重新启动后不会保留。无论相应内核设备的状态如何,都应始终存在于 /dev 目录中的静态文件和目录可以使用 systemd-tmpfiles 创建。配置文件位于 /usr/lib/tmpfiles.d//etc/tmpfiles.d/ 中;有关更多信息,请参阅 systemd-tmpfiles(8) 手册页。

16.2 内核 ueventsudev 编辑源

所需的设备信息由 sysfs 文件系统导出。对于内核已检测并初始化的每个设备,都会创建一个以设备名称命名的目录。它包含具有设备特定属性的属性文件。

每次添加或移除设备时,内核都会发送一个 uevent 通知 udev 发生更改。udev 守护程序在启动时读取并解析 /usr/lib/udev/rules.d/*.rules/etc/udev/rules.d/*.rules 文件中的所有规则,并将其保存在内存中。如果规则文件被更改、添加或移除,守护程序可以使用命令 udevadm control --reload 重新加载其内存表示。有关 udev 规则及其语法的更多详细信息,请参阅 第 16.6 节,“使用 udev 规则影响内核设备事件处理”

每个收到的事件都与提供的规则集进行匹配。这些规则可以添加或更改事件环境变量键,请求创建设备节点的特定名称,添加指向该节点的符号链接,或者添加在创建设备节点后运行的程序。驱动程序核心 uevents 是从内核 netlink 套接字接收的。

16.3 驱动程序、内核模块和设备 编辑源

内核总线驱动程序探测设备。对于每个检测到的设备,内核都会创建一个内部设备结构,同时驱动程序核心向 udev 守护程序发送一个 uevent。总线设备通过一个特殊格式的 ID 来标识自己,该 ID 指示它是哪种设备。这些 ID 由供应商 ID、产品 ID 和其他子系统特定值组成。每个总线都有自己的 ID 方案,称为 MODALIAS。内核获取设备信息,从中组成一个 MODALIAS ID 字符串,并随事件发送该字符串。对于 USB 鼠标,它看起来像这样

MODALIAS=usb:v046DpC03Ed2000dc00dsc00dp00ic03isc01ip02

每个设备驱动程序都带有一个它能处理的已知设备别名列表。该列表包含在内核模块文件本身中。程序 depmod 读取 ID 列表并为所有当前可用的模块在内核的 /lib/modules 目录中创建 modules.alias 文件。通过此基础设施,模块加载就像为每个带有 MODALIAS 键的事件调用 modprobe 一样简单。如果调用 modprobe $MODALIAS,它会将为设备组成的设备别名与模块提供的别名进行匹配。如果找到匹配项,则加载该模块。所有这些都由 udev 自动触发。

16.4 引导和初始设备设置 编辑源

udev 守护程序运行之前在引导过程中发生的所有设备事件都会丢失,因为处理这些事件的基础设施位于根文件系统上,并且当时不可用。为了弥补这种损失,内核提供了一个 uevent 文件,位于 sysfs 文件系统中每个设备的设备目录中。通过向该文件写入 add,内核会重新发送与引导期间丢失的事件相同的事件。对 /sys 中所有 uevent 文件进行简单循环会再次触发所有事件,以创建设备节点并执行设备设置。

例如,引导过程中存在的 USB 鼠标可能不会被早期引导逻辑初始化,因为当时驱动程序不可用。设备发现事件丢失,未能找到设备的内核模块。为了解决这个问题,udev 在根文件系统可用后从内核请求所有设备事件,因此 USB 鼠标设备的事件再次运行。现在它在挂载的根文件系统上找到了内核模块,USB 鼠标可以被初始化。

从用户空间看,设备热插拔序列和运行时设备发现之间没有可见的区别。在这两种情况下,都使用相同的规则进行匹配,并运行相同的配置程序。

16.5 监控运行中的 udev 守护程序 编辑源

程序 udevadm monitor 可用于可视化驱动程序核心事件和 udev 事件处理的时间。

UEVENT[1185238505.276660] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1 (usb)
UDEV  [1185238505.279198] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1 (usb)
UEVENT[1185238505.279527] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0 (usb)
UDEV  [1185238505.285573] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0 (usb)
UEVENT[1185238505.298878] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10 (input)
UDEV  [1185238505.305026] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10 (input)
UEVENT[1185238505.305442] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/mouse2 (input)
UEVENT[1185238505.306440] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/event4 (input)
UDEV  [1185238505.325384] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/event4 (input)
UDEV  [1185238505.342257] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/mouse2 (input)

UEVENT 行显示内核通过 netlink 发送的事件。UDEV 行显示完成的 udev 事件处理程序。时间以微秒打印。UEVENTUDEV 之间的时间是 udev 处理此事件所用的时间,或者 udev 守护程序延迟了其执行以将此事件与相关且已运行的事件同步。例如,硬盘分区事件总是等待主磁盘设备事件完成,因为分区事件可能依赖于主磁盘事件从硬件查询到的数据。

udevadm monitor --env 显示完整的事件环境

ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10
SUBSYSTEM=input
SEQNUM=1181
NAME="Logitech USB-PS/2 Optical Mouse"
PHYS="usb-0000:00:1d.2-1/input0"
UNIQ=""
EV=7
KEY=70000 0 0 0 0
REL=103
MODALIAS=input:b0003v046DpC03Ee0110-e0,1,2,k110,111,112,r0,1,8,amlsfw

udev 还会将消息发送到 syslog。控制哪些消息发送到 syslog 的默认 syslog 优先级在 udev 配置文件 /etc/udev/udev.conf 中指定。可以使用 udevadm control --log_priority=LEVEL/NUMBER 更改正在运行的守护程序的日志优先级。

16.6 使用 udev 规则影响内核设备事件处理 编辑源

一个 udev 规则可以匹配内核添加到事件本身的任何属性或内核导出到 sysfs 的任何信息。该规则还可以从外部程序请求附加信息。事件与 /usr/lib/udev/rules.d/ (默认规则) 和 /etc/udev/rules.d (系统特定配置) 目录中提供的所有规则进行匹配。

规则文件中的每一行至少包含一个键值对。有两种类型的键,匹配键和赋值键。如果所有匹配键都匹配其值,则应用该规则并为赋值键分配指定的值。匹配规则可以指定设备节点的名称,添加指向节点的符号链接,或运行指定程序作为事件处理的一部分。如果未找到匹配规则,则使用默认设备节点名称创建设备节点。有关规则语法以及用于匹配或导入数据的可用键的详细信息,请参阅 udev 手册页。以下示例规则提供了 udev 规则语法的基本介绍。示例规则均取自 udev 默认规则集 /usr/lib/udev/rules.d/50-udev-default.rules

示例 16.1: 示例 udev 规则
# console
KERNEL=="console", MODE="0600", OPTIONS="last_rule"

# serial devices
KERNEL=="ttyUSB*", ATTRS{product}=="[Pp]alm*Handheld*", SYMLINK+="pilot"

# printer
SUBSYSTEM=="usb", KERNEL=="lp*", NAME="usb/%k", SYMLINK+="usb%k", GROUP="lp"

# kernel firmware loader
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware.sh"

console 规则由三个键组成:一个匹配键 (KERNEL) 和两个赋值键 (MODEOPTIONS)。KERNEL 匹配规则在设备列表中搜索类型为 console 的任何项。只有精确匹配才有效并触发此规则的执行。MODE 键为设备节点分配特殊权限,在本例中,只读写权限授予此设备的拥有者。OPTIONS 键使此规则成为应用于此类型任何设备的最后一条规则。任何以后匹配此特定设备类型的规则都不会产生任何效果。

serial devices 规则不再在 50-udev-default.rules 中可用,但仍然值得考虑。它由两个匹配键 (KERNELATTRS) 和一个赋值键 (SYMLINK) 组成。KERNEL 键搜索所有 ttyUSB 类型的设备。使用 * 通配符,此键匹配多个此类设备。第二个匹配键 ATTRS 检查 sysfs 中任何 ttyUSB 设备的 product 属性文件是否包含某个字符串。赋值键 (SYMLINK) 触发在 /dev/pilot 下为此设备添加符号链接。此键中使用的操作符 (+=) 告诉 udev 额外执行此操作,即使先前或后来的规则添加了其他符号链接。由于此规则包含两个匹配键,因此仅当两个条件都满足时才应用。

printer 规则处理 USB 打印机,包含两个匹配键,这两个键都必须应用才能应用整个规则 (SUBSYSTEMKERNEL)。三个赋值键处理此设备类型的命名 (NAME)、符号设备链接的创建 (SYMLINK) 和此设备类型的组员资格 (GROUP)。在 KERNEL 键中使用 * 通配符使其匹配多个 lp 打印机设备。在 NAMESYMLINK 键中都使用了替换来通过内部设备名称扩展这些字符串。例如,第一个 lp USB 打印机的符号链接将是 /dev/usblp0

kernel firmware loader 规则使得 udev 在运行时通过外部辅助脚本加载额外的固件。SUBSYSTEM 匹配键搜索 firmware 子系统。ACTION 键检查是否已添加属于 firmware 子系统的任何设备。RUN+= 键触发 firmware.sh 脚本的执行,以定位要加载的固件。

所有规则都具有共同的一般特性

  • 每个规则由一个或多个用逗号分隔的键值对组成。

  • 键的操作由操作符确定。udev 规则支持多个操作符。

  • 每个给定值都必须用引号括起来。

  • 规则文件的每一行代表一个规则。如果规则超过一行,请使用 \ 将不同的行连接起来,就像在 shell 语法中那样。

  • udev 规则支持 shell 风格的模式,该模式匹配 *?[] 模式。

  • udev 规则支持替换。

16.6.1 udev 规则中使用操作符 编辑源

创建键时,您可以根据要创建的键的类型选择多个操作符。匹配键通常用于查找与搜索值匹配或明确不匹配的值。匹配键包含以下任何操作符

==

比较是否相等。如果键包含搜索模式,则所有匹配此模式的结果都有效。

!=

比较是否不相等。如果键包含搜索模式,则所有匹配此模式的结果都有效。

以下任何操作符都可以与赋值键一起使用

=

将值赋给键。如果键之前由值列表组成,则键将重置并且只分配单个值。

+=

将值添加到包含条目列表的键。

:=

分配最终值。不允许以后通过后来的规则进行任何更改。

16.6.2 udev 规则中使用替换 编辑源

udev 规则支持使用占位符和替换。使用它们的方式与在任何其他脚本中类似。以下替换可与 udev 规则一起使用

%r, $root

设备目录,默认是 /dev

%p, $devpath

DEVPATH 的值。

%k, $kernel

KERNEL 的值或内部设备名称。

%n, $number

设备号。

%N, $tempnode

设备文件的临时名称。

%M, $major

设备的主设备号。

%m, $minor

设备的次设备号。

%s{ATTRIBUTE}, $attr{ATTRIBUTE}

sysfs 属性(由 ATTRIBUTE 指定)的值。

%E{VARIABLE}, $env{VARIABLE}

环境变量(由 VARIABLE 指定)的值。

%c, $result

PROGRAM 的输出。

%%

% 字符。

$$

$ 字符。

16.6.3 使用 udev 匹配键 编辑源

匹配键描述了在应用 udev 规则之前必须满足的条件。以下匹配键可用

ACTION

事件操作的名称,例如,添加或移除设备时的 addremove

DEVPATH

事件设备的设备路径,例如,DEVPATH=/bus/pci/drivers/ipw3945 用于搜索与 ipw3945 驱动程序相关的所有事件。

KERNEL

事件设备的内部 (内核) 名称。

SUBSYSTEM

事件设备的子系统,例如,SUBSYSTEM=usb 表示所有与 USB 设备相关的事件。

ATTR{FILENAME}

事件设备的 sysfs 属性。例如,要匹配 vendor 属性文件中包含的字符串,您可以使用 ATTR{vendor}=="On[sS]tream"

KERNELS

udev 向上搜索设备路径以查找匹配的设备名称。

SUBSYSTEMS

udev 向上搜索设备路径以查找匹配的设备子系统名称。

DRIVERS

udev 向上搜索设备路径以查找匹配的设备驱动程序名称。

ATTRS{FILENAME}

udev 向上搜索设备路径以查找具有匹配 sysfs 属性值的设备。

ENV{KEY}

环境变量的值,例如,ENV{ID_BUS}="ieee1394 用于搜索与 FireWire 总线 ID 相关的所有事件。

PROGRAM

udev 执行外部程序。要成功,程序必须返回退出代码零。程序的输出,打印到 STDOUT,可用于 RESULT 键。

RESULT

匹配上一个 PROGRAM 调用的输出字符串。将此键包含在与 PROGRAM 键相同的规则中,或在后续规则中。

16.6.4 使用 udev 赋值键 编辑源

与上面描述的匹配键不同,赋值键不描述必须满足的条件。它们将值、名称和操作分配给 udev 维护的设备节点。

NAME

要创建的设备节点的名称。在规则设置节点名称后,所有其他带有此节点 NAME 键的规则都将被忽略。

SYMLINK

与要创建的节点相关的符号链接的名称。多个匹配规则可以添加要与设备节点一起创建的符号链接。您还可以在一个规则中为单个节点指定多个符号链接,使用空格字符分隔符号链接名称。

OWNER, GROUP, MODE

新设备节点的权限。这里指定的值会覆盖已编译的任何内容。

ATTR{KEY}

指定要写入事件设备的 sysfs 属性的值。如果使用 == 运算符,此键也用于匹配 sysfs 属性的值。

ENV{KEY}

告诉 udev 将变量导出到环境变量中。如果使用 == 运算符,此键也用于匹配环境变量。

RUN

告诉 udev 将程序添加到为此设备执行的程序列表中。请记住将此限制为简短任务,以避免阻塞此设备的其他事件。

LABEL

添加一个标签,供 GOTO 跳转。

GOTO

告诉 udev 跳过几条规则,并继续执行带有 GOTO 键引用的标签的规则。

IMPORT{TYPE}

将变量加载到事件环境中,例如外部程序的输出。udev 导入多种类型的变量。如果未指定类型,udev 会尝试根据文件权限的可执行位自行确定类型。

  • program 告诉 udev 执行外部程序并导入其输出。

  • file 告诉 udev 导入一个文本文件。

  • parent 告诉 udev 导入来自父设备的存储键。

WAIT_FOR_SYSFS

告诉 udev 等待为某个设备创建指定的 sysfs 文件。例如,WAIT_FOR_SYSFS="ioerr_cnt" 通知 udev 等待直到 ioerr_cnt 文件被创建。

OPTIONS

OPTION 键可以有多个值

  • last_rule 告诉 udev 忽略所有后续规则。

  • ignore_device 告诉 udev 忽略此事件。

  • ignore_remove 告诉 udev 忽略此设备的所有后续移除事件。

  • all_partitions 告诉 udev 为块设备上所有可用的分区创建设备节点。

16.7 持久设备命名 编辑源

动态设备目录和 udev 规则基础设施使得为所有磁盘设备提供稳定名称成为可能——无论其识别顺序或用于设备的连接如何。内核创建的每个适当的块设备都会被具有关于特定总线、驱动器类型或文件系统的特殊知识的工具检查。除了动态内核提供的设备节点名称,udev 还维护指向设备的持久符号链接类

/dev/disk
|-- by-id
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B -> ../../sda
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part1 -> ../../sda1
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part6 -> ../../sda6
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part7 -> ../../sda7
|   |-- usb-Generic_STORAGE_DEVICE_02773 -> ../../sdd
|   `-- usb-Generic_STORAGE_DEVICE_02773-part1 -> ../../sdd1
|-- by-label
|   |-- Photos -> ../../sdd1
|   |-- SUSE10 -> ../../sda7
|   `-- devel -> ../../sda6
|-- by-path
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0 -> ../../sda
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0-part1 -> ../../sda1
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0-part6 -> ../../sda6
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0-part7 -> ../../sda7
|   |-- pci-0000:00:1f.2-scsi-1:0:0:0 -> ../../sr0
|   |-- usb-02773:0:0:2 -> ../../sdd
|   |-- usb-02773:0:0:2-part1 -> ../../sdd1
`-- by-uuid
    |-- 159a47a4-e6e6-40be-a757-a629991479ae -> ../../sda7
    |-- 3e999973-00c9-4917-9442-b7633bd95b9e -> ../../sda6
    `-- 4210-8F8C -> ../../sdd1

16.8 udev 使用的文件 编辑源

/sys/*

由 Linux 内核提供的虚拟文件系统,导出所有当前已知设备。udev 使用此信息在 /dev 中创建设备节点

/dev/*

动态创建的设备节点和使用 systemd-tmpfiles 创建的静态内容;有关更多信息,请参阅 systemd-tmpfiles(8) 手册页。

以下文件和目录包含 udev 基础设施的关键元素

/etc/udev/udev.conf

udev 配置文件。

/etc/udev/rules.d/*

系统特定的 udev 事件匹配规则。您可以在此处添加自定义规则以修改或覆盖 /usr/lib/udev/rules.d/* 中的默认规则。

文件按字母数字顺序解析。优先级较高的文件中的规则会修改或覆盖优先级较低的规则。数字越小,优先级越高。

/usr/lib/udev/rules.d/*

默认 udev 事件匹配规则。此目录中的文件归软件包所有,并会被更新覆盖。请勿在此处添加、移除或编辑文件,请改用 /etc/udev/rules.d

/usr/lib/udev/*

udev 规则调用的辅助程序。

/usr/lib/tmpfiles.d//etc/tmpfiles.d/

负责静态 /dev 内容。

16.9 更多信息 编辑源

有关 udev 基础设施的更多信息,请参阅以下手册页

udev

有关 udev、键、规则和其他重要配置问题的一般信息。

udevadm

udevadm 可用于控制 udev 的运行时行为,请求内核事件,管理事件队列并提供简单的调试机制。

udevd

有关 udev 事件管理守护程序的信息。

打印此页面