叶绍琛,Unix/Linux/Android操作系统内核技术专家,大中华区前50位RHCA系统架构师,Oracle OCM认证数据库大师,曾任网易互娱云计算平台技术负责人,关注技术创新,关注云计算背景下的技术变革。
分类: Delphi
2012-06-19 09:51:40
第二章:Udev硬件设备管理机制
2.00 本章内容简介:
·理解Linux中的Udev是如何管理硬件设备;
·学习如何为自定义设备名编写udev规则;
2.01 Udev的功能:
在Linux系统中,内核的主要功能可以分为5大部分:文件系统、内存调度、进程调度、协议管理、硬件管理。其中的硬件管理就是由Udev提供的。
系统中的/dev目录是一个包含了大量设备条目的目录,通过Udev来对设备进行管理,给设备提供对应的名称空间,为设备命名,应用程序可以查询设备是否存在以及设备的名称等。它同时也是用来接替devfs及hotplug的功能,这意味着它要在添加/删除硬件时处理/dev目录以及所有用户空间的行为。Udev遵从LSB(Linux Standard Based)的标准,但也支持用户自定义的规则。很重要的一点,Udev是一个极其小而精的程序,所以嵌入式设备上常常使用它。
2.02 HAL硬件抽象层:
HAL(Hardware Abstraction Layer)硬件抽象层是一个为设备服务的程序,应用程序需要了解任何硬件设备信息或底层架构,只需要跟HAL索取相应的设备信息即可,简单点说,硬件抽象层就是介于硬件层和应用层之间一个起着桥梁作用的逻辑层服务。
HAL为每一个物理上接入到计算机的设备加入到一个实时数据库中,为每个设备对象提供了一个API去使用D-bus(system message bus)系统总线,应用程序可以使用API在设备上进行发现、监控、调用等操作。系统中会有一个hald的服务,他便是HAL的服务,但内核发现新设备时,hald将通告应用程序进行识别。可以使用hal-device-manager来查看存储在HAL中的设备信息,在view菜单下,选择Device Properties可以查看该设备的详细信息。
HAL管理的设备信息是以文件的形式存在,其配置文件存放在/usr/share/hal/fdi/下,用户管理配置文件存放在/etc/hal/fdi/下,且数据文件都是以.fdi为后缀的。在设备信息文件里面有3个部分:Information、Policy、Preprobe。分别包含了设备信息、策略和设备配置信息。
可以通过查看/usr/share/doc/hal-version/spec文档来了解HAL更多的信息。
2.03 插入设备发生的事件:
1.当一个设备插入到计算机,系统内核检测到插入的设备,并将设备的信息写入到/sys中。Sysfs是一个内核级别的保持追踪所有设备的设备虚拟文件系统,在系统中挂载为/sys。
2.通过netlink socket(一个在内核和用户空间之间传送信息的方便的无连接的Socket),系统内核通知udev该事件。
3.此时,udev将读取在/etc/udev/rule.d/中的一系列udev规则文件,在通知HAL之前,为设备创建设备文件或运行一段程序。在90-hal.rules规则中的RUN+="socket:/org/freedesktop/hal/udev_event"即是执行socket通知HAL该设备事件。Udev的事件可以使用udevmonitor --eny来进行监控。
4.当HAL接到该设备事件的通知,HAL便开始通过多个渠道获取设备相关信息,如内核、配置文件、硬件信息数据库等。
5.hald服务之后再D-BUS上广播该设备事件,让用户空间的程序接收调用。
以上便是设备插入到系统中,整个系统的硬件管理机制的工作流程,熟悉了硬件管理规则,有利于以后在项目中解决各类奇怪的突发问题,也有利于以后的学习。
2.04 Udev机制:
当一个设备从系统中添加/删除时,系统内核会发送一个信息到udevd且会将信息展示在/sys中。Udev之后会在/sys中查询设备信息,根据udev的相关定义规则来决定创建设备节点或创建symlink链接。
Sysfs是udev用来在系统中查询所有设备相关属性的,如location、name、serial number、major/minor number、vendor/product IDs等等。
通过udev规则可以对各类设备进行自定义的设置,可以自定义设备名,可以为某设备创建symlink,可以为某设备设置某属性等等。可以使用udevmonitor工具来进行监控udev的事件,--env参数可以显示详细信息。
2.05 配置udev:
所有的udev配置文件存放在/etc/udev目录下,配置文件是由一行行的配置信息组成的,#号表示注销该行配置。
/etc/udev/udev.conf是udev的全局配置文件,其中有几个重要参数项,udev_root表示创建的设备文件存放在哪里,默认是/dev;udev_rules表示udev规则存放在哪里,默认是/etc/udev/rules.d/;udev_log设置udev的日志级别,默认级别是err,在运行udev进行debug时,可以使用命令临时改变日志级别“udevcontrol log_priority=debug”,日志级别分为err,info,debug三类。
2.06 Udev规则:
Udev的规则文件默认是存放在/etc/udev/rules.d/目录下,文件以数字序号开头,以.rules为后缀,例如75-custom.rules。序号不能大于100,自定义的规则最好设置序号为99,因为序号越大则规则的优先权越高,这样最能保证你的自定义策略会被udev执行。
Udev规则的语法相当简单,举个例子:
BUS=="usb", SYSFS{serial}=="123123", SYMLINK+="xxx%n"
其中,“==”表示如果等于,“+=”表示添加一个,以上规则的意思是,如果该设备的总线是usb,如果设备的序列号是123123,则创建一个设备连接为xxx,%n表示设备的序号。
用户可以根据自己的需求对某设备的特征信息进行匹配绑定,可以匹配多个特征值,最后一项为对该设备的操作。写入规则后,可以使用“udevcontrol reload_rules”命令重新加载udev规则,也可以touch更新规则文件的时间戳,通常情况下系统讲自动读取到新的规则文件。
2.07 Udev规则的匹配键值:
“==”表示如果等于某键值时;“!=”表示如果不等于某键值时;以下为一些匹配键值实例:
ACTION=="add"
KERNEL=="sd[a-z]1"
BUS=="scsi"
DEVICE!="ide-cdrom"
PROGRAM=="custom_app.pl" RESULT=="some return strings"此实例较为难理解,表示当执行custom_app.pl程序时,如果返回的值是“some return strings”,则如何如何。
Udev规则支持使用通配符,“*”可以通配一个或多个字符;“?”可以通配一个字符;“[a-z]”通配a-z任一字母;“[!a]”可以通配除a外任一字母。
2.08 查找udev的匹配键值:
之前一直都没有介绍udev的作用,可以很多新人并不大了解,到了这里就来介绍一下。
现在的IT架构都是将运算和存储分离的,即计算交给服务器,而存储则交给存储,例如一个双机的HA集群,两台服务器连的是同一套存储,存储连到服务器上被识别成一个硬件设备,就像插了一块磁盘那样。由于这样的属于外围设备接入,所以设备名常常会飘,特别是多个数据存储接入到同一台服务器时,这样给HA带来很大的麻烦。而udev就可以根据各块盘的特有的特征值进行绑定,设置易于管理的自定义的设备名,方便了HA的使用。
那么,要怎样才能查到这些设备的特征值呢?
通常地,我们可以使用udevinfo来收集设备信息。
# udevinfo -a -p $(udevinfo -q path -n /dev/
对于SCSI设备可以使用:
# scsi_id -g -x -s /block/sdX
对于sata设备:
# /lib/udev/ata_id /dev/hdX
对于usb设备:
# /lib/udev/usb_id /block/sdX
2.09 Udev规则分配键值:
“=”表示分配一个值;“+=”表示新增一个链接;“:=”表示分配一个值,且任何最新的规则都不能改变;
分配键值实例:
NAME="usb_crypto" 分配名称键值;
SYMLINK+="data1" 新增链接;
OWNER="student" 设置设备文件所有者;
MODE="0600" 设置设备文件的权限;
LABEL="test_rule_end" 设置设备文件的标签;
GOTO="test_rule_end" 转向命令;
RUN="app.sh" 执行某程序;
更多的键值可以查看udev的帮助文档进行设置。
2.10 Udev规则字符串:
当udev规则生效的时候,规则中相应的替换变量便开始生效,通过这些替换变量,可以简化和缩写规则,便于读和写。以下各项支持使用替换变量:NAME,SYMLINK,PROGRAM,OWNER,GROUP,RUN等。
如此实例:
KERNEL=="sda*", SYMLINK+="iscsi%n"
其中,%n就是$number的缩写替换,用于表示设备数量。以下便是常用的替换变量:
$kernel = %k 表示设备名;
$devpath = %p 表示设备devpath(例如是/block/sda/...下的,而不是/sys/block/sda/...下的设备文件);
$id = %b 表示设备名和devpath的匹配;
$sysfs{file} = %s{file} 当前设备的SYSFS属性值;
$env{key} = %E{key} 表示环境变量的值;
$major = %M 表示设备的主设备号;
$minor = %m 表示设备的次设备号;
$result = %c 表示使用GROGRAM执行返回的结果串;
$root = %r 表示udev_root的值;
$parent = %P 表示父设备的设备名;
$$ 表示“$”字符;
%% 表示“%”字符;
2.11 Udev规则实例:
BUS=="scsi", SYSFS{serial}=="123123", NAME="/dev/sda..."
此规则表示当设备总线为scsi时,且设备序列号为123123时,将设备文件放置带/dev/sda...
KERNEL=="sd*", BUS=="scsi", PROGRAM=="xx.sh", RESULT=="123123", NAME="xxx%n"
此规则表示当设备内核设备名为sd*,其中*为通配符,总线为scsi时,执行程序xx.sh,若得出的结果为123123时,则将设备命名为xxx,其中%n则表示设备数量号。
ACTION=="add",KERNEL=="PPP0",RUN+="wall PPP Success!"
此规则表示当设备动作为添加时,当设备名为PPP0时,运行命令广播拨号接口添加成功。
2.12 Udev监控工具:
可以使用udevmonitor工具对系统内核和udev规则事件进行持续性地监控。
# udevmonitor --env查看完整的udev事件日志;