Linux下udev详细介绍
每次在搭建OracleRAC环境中,遇到问题最多的就是关于ASM磁盘的的问题,通过查看网上许多搭建RAC的文档,发现Oracle10g RAC大家普遍的修改/etc/udev/rules.d/60-raw.rules,而一些搭建Oracle11R2的RAC,大家都在配置的是/etc/udev/rules.d/99-oracle-asmdevices.rules这个文件,面对这样一种情况,我不是很明白,这两个文件到底有什么区别,这个问题困扰了我很久,直到今天遇到这样一个问题:使用udev管理asmdisk执行/sbin/scsi_id不显示UUID。通过查询相关的资料才算是对这个问题有了更深层次的理解。
Linux平台通过udev的方式将块设备转换为字符设备,并固定设备的权限和所有者,这种需求只在安装11gR1之前的RAC数据库的时候需要这样做,安装11gR2的RAC,ASM可以直接使用块设备。udev除了用于将块设备转换为字符设备外,还可用于固定设备文件名称。
之后,通过实验来验证这个结论:
详细的步骤请参考我的另一篇博文:
使用udev管理asmdisk执行/sbin/scsi_id不显示UUID
目录
一、udev简介... 1
二、udev的优势... 2
2.1 动态管理... 2
2.2 自定义命名规则... 2
2.3 设定设备的权限和所有者/ 组... 2
2.4 下面的流程图显示udev 添加/删除设备文件的过程。... 3
三、配置和使用udev(CentOS6.4)... 4
3.1 检查udev在CentOS6.5中的版本和运行情况... 4
3.2 udev的配置文件... 4
3.3 通过udev设定设备文件的权限... 5
3.4 udev的规则和规则文件... 5
四、制定udev 规则和查询设备信息的实例... 8
4.1 查找设备的信息(属性)来制定udev规则... 8
4.2 udev的简单规则... 10
4.3 其他常用的udev命令... 11
一、udev简介
udev 是Linux2.6内核里的一个功能,它替代了原来的devfs,成为当前Linux 默认的设备管理工具。udev以守护进程的形式运行,通过侦听内核发出来的uevent来管理/dev目录下的设备文件。不像之前的设备管理工具,udev在用户空间(userspace) 运行,而不在内核空间(kernel space) 运行。
二、udev的优势
2.1 动态管理
当设备添加/删除时,udev的守护进程侦听来自内核的uevent,以此添加或者删除/dev下的设备文件,所以udev只为已经连接的设备产生设备文件,而不会在/dev下产生大量虚无的设备文件。
2.2 自定义命名规则
通过Linux默认的规则文件,udev在/dev/里为所有的设备定义了内核设备名称,比如/dev/sda、/dev/hda、/dev/fd等等。由于udev是在用户空间(user space) 运行,Linux用户可以通过自定义的规则文件,灵活地产生标识性强的设备文件名,比如/dev/boot_disk、/dev/root_disk、/dev/color_printer等等。
2.3 设定设备的权限和所有者/ 组
udev可以按一定的条件来设置设备文件的权限和设备文件所有者/组。在不同的udev 版本中,实现的方法不同。
2.4 下面的流程图显示udev 添加/删除设备文件的过程。
PS:
1.设备文件:由于本文以较通俗的方式讲解udev,所以设备文件是泛指在/dev/下,可被应用程序用来和设备驱动交互的文件。而不会特别地区分设备文件、设备节点或者设备特殊文件。
2.sysfs:sysfs是Linux2.6 内核里的一个虚拟文件系统(/sys)。它把设备和驱动的信息从内核的设备模块导出到用户空间(userspace)。从该文件系统中,Linux用户可以获取很多设备的属性。
3.devpath:本文的devpath是指一个设备在sysfs文件系统(/sys)下的相对路径,该路径包含了该设备的属性文件。udev里的多数命令都是针对devpath操作的。例如:sda的devpath是/block/sda,sda2的devpath是/block/sda/sda2。
4.内核设备名称:设备在sysfs里的名称,是udev默认使用的设备文件名。
三、配置和使用udev(CentOS6.4)
3.1 检查udev在CentOS6.5中的版本和运行情况
[root@testboot]# rpm -qa |grep -i udev
udev-147-2.46.el6.x86_64
libgudev1-147-2.46.el6.x86_64
python-gudev-147.1-4.el6_0.1.x86_64
libudev-147-2.46.el6.x86_64
system-config-printer-udev-1.1.16-23.el6.x86_64
[root@testboot]# ps -ef |grep -i udev
root 27957 1 0 10:23 ? 00:00:00 /sbin/udevd -d
root 28584 27957 0 10:34 ? 00:00:00 /sbin/udevd -d
root 29017 1955 0 13:28 pts/0 00:00:00 grep -i udev
3.2 udev的配置文件
[root@test~]# cat/etc/udev/udev.conf
#The initial syslog(3) priority: "err", "info","debug" or its
#numerical equivalent. For runtime debugging, the daemons internal
#state can be changed with: "udevadm control--log-priority=
udev_log="err"
udev_log:syslog记录日志的级别,默认值是err。如果改为info或者debug的话,会有冗长的udev日志被记录下来。
实际上在CentOS里,除了配置文件里列出的参数udev_log外,Linux用户还可以修改参数udev_root和udev_rules,只不过这2个参数是不建议修改的,所以没显示在udev.conf 里。syslog默认会记录udev的日志,Linux用户只能修改日志的级别(err、info、degub等);设备的权限不能在udev.conf里设定,而是要在规则文件(*.rules) 里设定。
3.3 通过udev设定设备文件的权限
在CentOS6.4 的udev,已经没有权限文件,所有的权限都是通过规则文件(*.rules)来设置,在下面的规则文件配置过程会介绍到。
3.4 udev的规则和规则文件
规则文件是udev里最重要的部分,默认是存放在/etc/udev/rules.d/下。所有的规则文件必须以".rules"为后缀名。CentOS有默认的规则文件,这些默认规则文件不仅为设备产生内核设备名称,还会产生标识性强的符号链接。例如:
[root@test~]# ls/dev/disk/by-uuid/
18f9b7a4-f6a9-4a87-a63b-2660b12c87db 8ac6170e-8e4d-4385-a166-92c2aaeb75ca
5e2405ac-1cb5-4a90-a6c9-67c2c245667b c42b1176-beaf-4e52-98e3-1b6d386908c0
但这些链接名较长,不易调用,所以通常需要自定义规则文件,以此产生易用且标识性强的设备文件或符号链接。
udev按照规则文件名的字母顺序来查询全部规则文件,然后为匹配规则的设备管理其设备文件或文件链接。虽然udev不会因为一个设备匹配了一条规则而停止解析后面的规则文件,但是解析的顺序仍然很重要。通常情况下,建议让自己想要的规则文件最先被解析。比如,创建一个名为/etc/udev/rules.d/10-myrule.rules的文件,并把你的规则写入该文件,这样udev就会在解析系统默认的规则文件之前解析到你的文件。
在规则文件里,除了以"#"开头的行(注释),所有的非空行都被视为一条规则,但是一条规则不能扩展到多行。规则都是由多个键值对(key-valuepairs)组成,并由逗号隔开,键值对可以分为条件匹配键值对(以下简称"匹配键")和赋值键值对(以下简称"赋值键"),一条规则可以有多条匹配键和多条赋值键。匹配键是匹配一个设备属性的所有条件,当一个设备的属性匹配了该规则里所有的匹配键,就认为这条规则生效,然后按照赋值键的内容,执行该规则的赋值。下面是一个简单的规则:
KERNEL=="sda",NAME="my_root_disk",MODE="0660"
KERNEL是匹配键,NAME和MODE是赋值键。这条规则的意思是:如果有一个设备的内核设备名称为sda,则该条件生效,执行后面的赋值:在/dev下产生一个名为my_root_disk的设备文件,并把设备文件的权限设为0660。
仅当操作符是"=="或者"!="时,其为匹配键;若为其他操作符时,都是赋值键。
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,则该设备匹配该匹配键。
在一条规则中,可以设定最多五条SYSFS的匹配键。
ENV{key}:环境变量。在一条规则中,可以设定最多五条环境变量的匹配键。
PROGRAM:调用外部命令。
RESULT:外部命令PROGRAM 的返回结果。例如:
PROGRAM=="/lib/udev/scsi_id-g -s $devpath", RESULT=="35000c50000a7ef67"
调用外部命令/lib/udev/scsi_id查询设备的SCSIID,如果返回结果为35000c50000a7ef67,则该设备匹配该匹配键。
udev 的重要赋值键:
NAME:在/dev下产生的设备文件名。只有第一次对某个设备的NAME的赋值行为生效,之后匹配的规则再对该设备的NAME赋值行为将被忽略。如果没有任何规则对设备的NAME赋值,udev将使用内核设备名称来产生设备文件。
SYMLINK:为/dev/下的设备文件产生符号链接。由于udev只能为某个设备产生一个设备文件,所以为了不覆盖系统默认的udev规则所产生的文件,推荐使用符号链接。
OWNER, GROUP, MODE:为设备设定权限。
ENV{key}:导入一个环境变量。
udev 的值和可调用的替换操作符:
在键值对中的键和操作符都介绍完了,最后是值(value)。Linux用户可以随意地定制udev规则文件的值。例如:my_root_disk,my_printer。同时也可以引用下面的替换操作符:
$kernel, %k:设备的内核设备名称,例如:sda、cdrom。
$number, %n:设备的内核号码,例如:sda3的内核号码是3。
$devpath, %p:设备的devpath路径。
$id, %b:设备在devpath里的ID号。
$sysfs{file},%s{file}:设备的sysfs里file的内容。其实就是设备的属性值。例如:$sysfs{size}表示该设备(磁盘) 的大小。
$env{key}, %E{key}:一个环境变量的值。
$major, %M:设备的major号。
$minor %m:设备的minor号。
$result, %c:PROGRAM返回的结果。
$parent, %P:父设备的设备文件名。
$root, %r:udev_root的值,默认是/dev/。
$tempnode, %N:临时设备名。
%%:符号%本身。
$$:符号$本身。
KERNEL=="sd*",PROGRAM="/lib/udev/scsi_id -g -s %p", \RESULT=="35000c50000a7ef67", SYMLINK="%k_%c"
该规则的执行:如果有一个内核设备名称以sd开头,且SCSI ID 为35000c50000a7ef67,则为设备文件产生一个符号链接"sda_35000c50000a7ef67".
四、制定udev 规则和查询设备信息的实例
4.1 查找设备的信息(属性)来制定udev规则
当我们为指定的设备设定规则时,首先需要知道该设备的属性,比如设备的序列号、磁盘大小、厂商ID、设备路径等等。通常我们可以通过以下的方法获得:
查询sysfs文件系统:
前面介绍过,sysfs里包含了很多设备和驱动的信息。
例如:设备sda的SYSFS{size} 可以通过cat/sys/block/sda/size得到;SYSFS{model}信息可以通过cat/sys/block/sda/device/model得到。
udevadm info命令:(Centos5.3为udevinfo命令)
udevadm info 可以查询udev数据库里的设备信息。例如:用udevadm info 查询设备sda的model 和size信息:
[root@test~]# udevadm info-a -p /sys/block/sda | egrep "model|size"
ATTR{size}=="62914560"
ATTRS{model}=="VBOX HARDDISK "
[root@test~]# udevadm info-a -p /sys/block/sda
Udevadminfo starts with the device specified by the devpath and then
walksup the chain of parent devices. It prints for every device
found,all possible attributes in the udev rules key format.
Arule to match, can be composed by the attributes of the device
andthe attributes from one single parent device.
looking at device'/devices/pci0000:00/0000:00:0d.0/host2/target2:0:0/2:0:0:0/block/sda':
KERNEL=="sda"
SUBSYSTEM=="block"
DRIVER==""
ATTR{range}=="16"
ATTR{ext_range}=="256"
ATTR{removable}=="0"
ATTR{ro}=="0"
ATTR{size}=="62914560"
ATTR{alignment_offset}=="0"
ATTR{discard_alignment}=="0"
ATTR{capability}=="52"
ATTR{stat}==" 30322 6547 1191594 333118 7382 94590 811468 137604 0 154932 470661"
ATTR{inflight}==" 0 0"
looking at parent device'/devices/pci0000:00/0000:00:0d.0/host2/target2:0:0/2:0:0:0':
KERNELS=="2:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{device_blocked}=="0"
ATTRS{type}=="0"
ATTRS{scsi_level}=="6"
ATTRS{vendor}=="ATA "
ATTRS{model}=="VBOX HARDDISK "
ATTRS{rev}=="1.0 "
ATTRS{state}=="running"
ATTRS{timeout}=="30"
ATTRS{iocounterbits}=="32"
ATTRS{iorequest_cnt}=="0x95a8"
ATTRS{iodone_cnt}=="0x957d"
ATTRS{ioerr_cnt}=="0x5"
ATTRS{modalias}=="scsi:t-0x00"
ATTRS{evt_media_change}=="0"
ATTRS{dh_state}=="detached"
ATTRS{queue_depth}=="31"
ATTRS{queue_ramp_up_period}=="120000"
ATTRS{queue_type}=="simple"
looking at parent device'/devices/pci0000:00/0000:00:0d.0/host2/target2:0:0':
KERNELS=="target2:0:0"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device'/devices/pci0000:00/0000:00:0d.0/host2':
KERNELS=="host2"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device'/devices/pci0000:00/0000:00:0d.0':
KERNELS=="0000:00:0d.0"
SUBSYSTEMS=="pci"
DRIVERS=="ahci"
ATTRS{vendor}=="0x8086"
ATTRS{device}=="0x2829"
ATTRS{subsystem_vendor}=="0x0000"
ATTRS{subsystem_device}=="0x0000"
ATTRS{class}=="0x010601"
ATTRS{irq}=="21"
ATTRS{local_cpus}=="1"
ATTRS{local_cpulist}=="0"
ATTRS{modalias}=="pci:v00008086d00002829sv00000000sd00000000bc01sc06i01"
ATTRS{numa_node}=="-1"
ATTRS{enable}=="1"
ATTRS{broken_parity_status}=="0"
ATTRS{msi_bus}==""
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
4.2 udev的简单规则
产生网卡设备文件的规则:
SUBSYSTEM=="net",SYSFS{address}=="AA:BB:CC:DD:EE:FF", NAME="public_NIC"
该规则表示:如果存在设备的子系统为net,并且地址(MACaddress) 为"AA:BB:CC:DD:EE:FF",为该设备产生一个名为public_NIC的设备文件。
为指定大小的磁盘产生符号链接的规则
SUBSYSTEM=="block",SYSFS{size}=="71096640", SYMLINK ="my_disk"
该规则表示:如果存在设备的子系统为block,并且大小为71096640(block),则为该设备的设备文件名产生一个名为my_disk的符号链接。
通过外部命令为指定序列号的磁盘产生设备文件的规则
KERNEL=="sd*[0-9]",PROGRAM=="/lib/udev/scsi_id -g -s %p", \ RESULT=="35000c50000a7ef67",NAME +="root_disk%n"
该规则表示:如果存在设备的内核设备名称是以sd 开头( 磁盘设备),以数字结尾(磁盘分区),并且通过外部命令查询该设备的SCSI_ID号为"35000c50000a7ef67",则产生一个以root_disk开头,内核号码结尾的设备文件,并替换原来的设备文件(如果存在的话)。例如:产生设备名/dev/root_disk2,替换原来的设备名/dev/sda2。
运用这条规则,可以在/etc/fstab里保持系统分区名称的一致性,而不会受驱动加载顺序或者磁盘标签被破坏的影响,导致操作系统启动时找不到系统分区。
4.3 其他常用的udev命令
udevadm test(udevadm的子命令):针对一个设备,在不需要uevent触发的情况下模拟一次udev的运行,并输出查询规则文件的过程、所执行的行为、规则文件的执行结果。
Simulate a udevevent run for the given device, and print debugoutput
start_udev:start_dev命令重启udev守护进程,并对所有的设备重新查询规则目录下所有的规则文件,然后执行所匹配的规则里的行为。通常使用该命令让新的规则文件立即生效:
[root@test~]# start_udev
Startingudev: [ OK ]
start_udev一般没有标准输出,所有的udev相关信息都按照配置文件(udev.conf)的参数设置,由syslog记录。
作者:SEian.G(苦练七十二变,笑对八十一难)
ITPUB:http://blog.itpub.net/31015730/
51CTO:http://seiang.blog.51cto.com/