Udev守护进程解析uevent数据,并且对/etc/udev/rules.d中指定的规则进行匹配.
根据指定的规则为设备创建设备节点和符号链接.
Udev守护进程读取/etc/udev/rules.d/*.rules 中的规则并且保存到内存里面.
Udev接收接收inotify事件,如果某个规则发生了改变,读取这些改变并更新内存副本.
设备驱动程序加载
Udev使用modalias方法来加载设备驱动程序. 位于/lib/modules/`uname -r`/modules.alias 的modalias文件用于协助Udev加载设备驱动. modalias文件由depmod命令创建,包括了设备驱动的别名。
让我们检查一个Linux设备驱动加载的例子:
我使用一个C程序来从netlink套接字收集数据,并且使用它们来创建设备节点以及加载模块。
[root@arch ~]# ./a.outadd@/devices/pci0000:00/0000:00:02.1/usb1/1-4ACTION=addDEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-4SUBSYSTEM=usbMAJOR=189MINOR=1DEVTYPE=usb_deviceDEVICE=/proc/bus/usb/001/002PRODUCT=1058/1010/105TYPE=0/0/0BUSNUM=001DEVNUM=002SEQNUM=1163add@/devices/pci0000:00/0000:00:02.1/usb1/1-4/1-4:1.0ACTION=addDEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-4/1-4:1.0SUBSYSTEM=usbDEVTYPE=usb_interfaceDEVICE=/proc/bus/usb/001/002PRODUCT=1058/1010/105 …………………………………………你可以看到它提供了很多关于这个设备的信息。这其中包括了用来告诉Udev加载某个特定模块的modalias变量。
modalias数据看起来像这样:
MODALIAS=pci:v000010ECd00008169sv00001385sd0000311Abc02sc00i00The modalias data contains all the information required to find the corresponding device driver :
pci :- 这是一个PCI设备 v :- 设备的厂商ID. 在这里就是 000010EC ( 即 10EC )d :- 设备的设备ID. 在这里就是 00008169 ( 即 8169 )sv 和 sd 是厂商和设备的子系统版本号. 依据ID查找一个PCI设备的厂商/产品的最好地方是 http://www.pcidatabase.com.
Udev使用modalias数据来从/lib/modules/`uname -r`/modules.alias 查找正确的设备驱动。
$ grep -i 10EC /lib/modules/`uname -r`/modules.alias | grep -i 8169alias pci:v000010ECd00008129sv*sd*bc*sc*i* r8169alias pci:v000010ECd00008169sv*sd*bc*sc*i* r8169你可以看到适合这个设备的模块是r8169. 让我们获取关于这个驱动程序的更多的信息.
$ /sbin/modinfo r8169filename: /lib/modules/2.6.18-53.el5/kernel/drivers/net/r8169.koversion: 2.2LK-NAPIlicense: GPLdescription: RealTek RTL-8169 Gigabit Ethernet driverauthor: Realtek and the Linux r8169 crew srcversion: D5EDA4980B92CA2CF677B62alias: pci:v00001737d00001032sv*sd00000024bc*sc*i*alias: pci:v000016ECd00000116sv*sd*bc*sc*i*alias: pci:v00001186d00004300sv*sd*bc*sc*i*alias: pci:v000010ECd00008129sv*sd*bc*sc*i*alias: pci:v000010ECd00008169sv*sd*bc*sc*i*depends:vermagic: 2.6.18-53.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1parm: media:force phy operation. Deprecated by ethtool (8). (array of int)parm: rx_copybreak:Copy breakpoint for copy-only-tiny-frames (int)parm: use_dac:Enable PCI DAC. Unsafe on 32 bit PCI slot. (int)parm: debug:Debug verbosity level (0=none, …, 16=all) (int)注意查看从"depends”开始的那些行. 它描述了r8169这个模块所依赖的其他一些模块。因此Udev也会加载这些模块。
规则处理和设备节点创建
如前所述,Udev会为内核中每个设备状态的改变解析/etc/udev/rules.d/ 中的规则。Udev规则可以用于在用户空间操作设备节点的名字/权限/符号链接。
让我们看一些示例规则,有利于帮助你更好地理解Udev规则。
内核通过netlink提供的数据可以被Udev用来创建设备节点。这些数据包括主/次设备号对和另外一些设备相关的数据,比如设备/厂商id,设备序列号等。Udev规则可以匹配所有的这些数据,并且用来改变设备节点的名字,创建符号链接,或者注册网络连接。
下面这个例子展示了怎样书写Udev规则来重命名系统中的一个网络设备。
我们需要得到一些用于创建规则的设备信息。
# udevadm info -a -p /sys/class/net/eth0/llooking at device '/devices/pci0000:00/0000:00:04.0/0000:01:06.0/net/eth0':KERNEL==”eth0″SUBSYSTEM==”net”DRIVER==”"ATTR{addr_len}==”6″ATTR{dev_id}==”0×0″ATTR{ifalias}==”"ATTR{iflink}==”3″ATTR{ifindex}==”3″ATTR{features}==”0×829″ATTR{type}==”1″ATTR{link_mode}==”0″ATTR{address}==”00:80:48:62:2a:33″ATTR{broadcast}==”ff:ff:ff:ff:ff:ff”ATTR{carrier}==”1″ATTR{dormant}==”0″ATTR{operstate}==”unknown”ATTR{mtu}==”1500″ATTR{flags}==”0×1003″ATTR{tx_queue_len}==”1000″looking at parent device ‘/devices/pci0000:00/0000:00:04.0/0000:01:06.0′:KERNELS==”0000:01:06.0″SUBSYSTEMS==”pci”DRIVERS==”8139too”ATTRS{vendor}==”0×10ec”ATTRS{device}==”0×8139″ATTRS{subsystem_vendor}==”0×10ec”ATTRS{subsystem_device}==”0×8139″ATTRS{class}==”0×020000″ATTRS{irq}==”19″ATTRS{local_cpus}==”ff”ATTRS{local_cpulist}==”0-7″ATTRS{modalias}==”pci:v000010ECd00008139sv000010ECsd00008139bc02sc00i00″ATTRS{enable}==”1″ATTRS{broken_parity_status}==”0″ATTRS{msi_bus}==”"looking at parent device ‘/devices/pci0000:00/0000:00:04.0′:KERNELS==”0000:00:04.0″SUBSYSTEMS==”pci”DRIVERS==”"ATTRS{vendor}==”0×10de”ATTRS{device}==”0×03f3″ATTRS{subsystem_vendor}==”0×0000″ATTRS{subsystem_device}==”0×0000″ATTRS{class}==”0×060401″ATTRS{irq}==”0″ATTRS{local_cpus}==”ff”ATTRS{local_cpulist}==”0-7″ATTRS{modalias}==”pci:v000010DEd000003F3sv00000000sd00000000bc06sc04i01″ATTRS{enable}==”1″ATTRS{broken_parity_status}==”0″ATTRS{msi_bus}==”1″looking at parent device ‘/devices/pci0000:00′:KERNELS==”pci0000:00″SUBSYSTEMS==”"DRIVERS==”"你可以发现Udev拥有大量关于这个网络设备的信息。让我们深入检查一下:
KERNEL=="eth0" :- 该设备的内核名字是eth0DRIVERS==”8139too” :- 加载的驱动程序是8139tooATTR{address}==”00:80:48:62:2a:33″ :- 该设备的硬件地址ATTRS{vendor}==”0×10ec” :- 厂商 idATTRS{device}==”0×8139″ :- 设备 id让我们创建一个规则来将这个网络设备重命名为eth1 (这个名字将是永久性的并且重启系统以后也不会复原).
>[root@arch ~]# cat /etc/udev/rules.d/70-persistent-net.rulesSUBSYSTEM==”net”, ACTION==”add”, DRIVERS==”?*”, ATTR{address}==”00:80:48:62:2a:33″, ATTR{type}==”1″, KERNEL==”eth*”, NAME=”eth1″这个规则就将这个设备重命名成了eth1. 用这种方式我们可以很容易地管理系统中的网络设备或者其他设备节点。
Udev 实用工具
Udev提供了一些用户空间的实用程序,用于管理系统中的设备和设备节点。在所有最近的Linux发行版中都可以找到的这样的一个命令就是'udevadm',udevadm这个命令在功能上可以实现上面提到的各个命令完成的所有任务。
这个工具可以用来在正在运行的系统里面重新生成设备节点,如下所示:
[root@arch ~]# ls -l /dev/ | wc -l150[root@arch ~]# rm -rf /dev/*rm: cannot remove `/dev/pts/0′: Operation not permittedrm: cannot remove directory `/dev/shm’: Device or resource busy[root@arch ~]# ls -l /dev/ | wc -l4[root@arch ~]# udevadm trigger[root@arch ~]# ls -l /dev/ | wc -l150有更多的其他有用的操作都可以通过udevadm命令完成。你可以通过udevadm的man手册页来获取更多的信息。
Udev的未来会怎样 ?
预测Linux子系统的将来是不可能的。Linux正在快速开发的过程当中,因此预测Linux的内核的未来是不明智的。DEVfs曾经被当作静态设备节点的一个解决方案被引入,但是在经历一小段时间之后就消失了。而Udev则被证明是现代Linux内核中一个成功的设备管理器,并且有希望在未来的 发布中成为一个更加稳定,多功能的设备管理系统。
责任编辑:小草