linux_udev机制实现-0

liaocj 2022-09-20 16:04:03
Categories: > > > Tags:

udev 简介

在早期的 linux 中,对于设备管理的策略是比较简单的,各个硬件设备对应 /dev 目录下的一些静态属性文件,这时候的硬件环境并不复杂,外围硬件通常比较少,更没有热插拔的需求.

不过,随着这几十年硬件的爆发式增长以及移动设备的兴起,设备管理开始变得复杂起来,一方面是外围设备的增多,设备的复杂度逐渐提高,另一方面,系统需要满足越来越多的”动态需求”,也就是一些即插即用的设备,比如:USB 网卡,硬盘等.

为了应对外部环境的变化,linux 首先推出了 devfs,首次出现在 2.3 内核中,它主要特点是支持设备的热插拔,但是 devfs 不支持持久化的命名、后期维护不积极,同时考虑到设备管理的工作没必要完全放在内核中等因素,在不久之后的 2.6 版本内核中就被新的设备管理策略 udev 所替代,一直沿用至今.

值得一提的是,udev 是一个用户空间程序,通过 netlink 机制与内核进行交互,监听内核的设备更改并相应地修正应用空间的设备接口.

udev 分为两个部分,一个是守护进程 udevd,另一部分是客户端程序,主要是 udevadm,提供用户层面的操作接口.在早期 udev 作为独立的服务运行在 Linux 系统中,后来被并入 systemd 管理系统中,这种迁移并不对 udev 的功能造成任何影响.

udev 能做什么?

设备管理是一个抽象的概念,设备本身也囊括了非常多的东西,linux 中的设备分为三种:字符设备,块设备和网络设备,对于 Linux 来说,设备在硬件上通过各种总线连接到系统中,然后在软件层面导出操作设备的接口,几乎所有设备都是这种方式运行在 linux 中(网络设备稍微特殊一些,它不会在通用的/dev,/sys目录下直接导出操作接口).

不同设备的区别在于:硬件上,有些设备可能是通过 USB 总线连接到机器,而有些是通过串口或者网口.软件上,某些设备对应单一的操作接口,而某些设备的设备接口更加复杂.

需要注意的是,udev 是一个用户空间的程序,所以可以想到,硬件相关的操作是和 udev 完全无关的,因为 linux 中只有内核才有操作硬件资源的权限,所以内核负责处理设备连接到系统,包括总线的匹配,连接,底层通信等工作.

而 udev 负责以下的用户空间工作:

在 linux 下,一切皆文件,上文中所说的软件接口也正是以文件的形式导出,所以 udev 的工作也是和设备文件接口打交道,包括命名、权限等,当然,这依赖于内核提供的设备信息.

udev 是如何实现设备管理的?

设备管理中大部分的工作都是围绕设备接口相关,最多的自然是设备的创建,,下面我们就以系统中的实时时钟(RTC)为例,看看一个硬件设备从连接到用户接口的导出是怎么样的一个过程。

这是一个相对简单的示例,展示了一个设备从硬件的连接到内核总线的处理再到用户接口的导出整个过程,而设备的变动通常被称为设备事件,设备事件由内核传递到应用空间,再由应用空间的 udevd 处理。

rules 规则文件

对于系统管理员来说,udev 最核心的部分在于 .rules 规则文件,设备的插拔与修改信息由内核传递到用户空间,而用户空间将会做出怎样的操作几乎完全取决于规则文件中预定义的行为(udevd存在一些內建函数和默认操作),因此,如果要掌握 udev 的使用,掌握规则文件是第一步,辛运的是,这并不难.

规则文件被放置在系统目录中,且必须以 .rules 为后缀,对应的系统目录有:/run/udev/rule.d,/etc/udev/rules.d,/lib/udev/rules.d. 其中,系统软件在安装时通常会把规则文件放在 /lib/udev/rules.d 目录下,而 /run,/etc 下的 rules.d/ 目录下的规则文件则用于系统管理员的本地配置.
(注:在我的嵌入式设备和 ubuntu18 上,发现 /run/udev/rules.d 并不存在,如果手动地创建了对应的目录,udev才会去读取该目录下的文件。)

当系统中存在同名不同目录的规则文件时,/etc 下的优先级最高,/run 次之,/lib 优先级最低,高优先级的同名文件将会覆盖低优先级文件.如果要屏蔽一个规则文件,直接在 /etc 下创建该文件的一个软链接,指向 /dev/null 是不错的方法。

同时,对于不同名的规则文件,其优先级的管理不是由存放目录来决定的,而是通过文件名来实现的,规则文件命名通常是以数字开头,比如 50-udev-default.rules,通过判断规则文件命名的前导数字来确定规则文件被解析的优先级.

以数字开头并不是硬性规定,这是一种约定俗成的规则,如果某个调皮的用户不使用数字开头,udev 同样会以字母顺序进行排序,只是看起来这种方式不直观,不建议这么做.

udev 总体解析规则

udev 在解析所有规则文件时,遵循以下的规则:

规则文件的编写规则

规则文件是由多条规则以及少量的逻辑控制语句组成,规则文件内容的编写也应该遵循相应的规则:

udevd 守护进程

在系统启动阶段,udev 会启动其守护进程 udevd,udevd 是 udev 的核心部分,执行了 udev 的大部分功能,包括监听并处理内核设备事件、给客户端提供调试和操作接口、维护设备事件的数据库等等。

在上文中提到,udev 被集成到了 systemd 中,默认情况下,其对应的服务文件为:

进程选项

udevd 守护进程的执行支持多个命令行选项,可以通过将命令行选项添加到 /lib/systemd/system/udev.service 文件中 ExecStart=/lib/systemd/systemd-udevd 语句后面来为 udevd 守护进程提供命令行选项。

配置文件

除了提供程序执行时的命令行选项,另一种配置 udevd 的方式就是配置文件,配置文件为 /etc/udev/udev.conf.该文件包含一组 允许用户修改的变量( VAR=VALUE 格式),以控制该进程的行为。 空行或以”#”开头的行将被忽略。 可以设置的变量(VAR)如下:

相对于指定命令行参数而言,推荐使用修改配置文件来更改守护进程行为.

在后续的文章中,将会继续介绍规则文件的编写,以及 udev 的使用.

参考:http://www.jinbuguo.com/systemd/systemd-udevd.service.html
参考:http://www.jinbuguo.com/systemd/udev.conf.html