2.6内核相比2.4内核,有了很大改动,一个大改动就是增加/sys文件系统和使用udev来管理/dev目录。
什么是udev?为什么需要udev?
udev是一个可以在user space就控制设备的一个东西。以前Linux用的是devfs,但是这个东西有很大的弊病,比如设备名称不固定(按照设备插入机器的先后顺序确定设备文件名,即在/dev目录下的文件名,或根据硬件所在的插槽确定设备文件名,这就导致了比如硬盘换个IDE口,USB设备反复插拔的时候,设备文件名不统一的情况),等很多问题,详情看来自Linux Device Driver一书的说明:
One of the main reasons for creating the unified driver model in the kernel was to allow user space to manage the /dev tree in a dynamic fashion. This had previously been done in user space with the implementation of devfs, but that code base has slowly rotted away, due to a lack of an active maintainer and some unfixable core bugs. A number of kernel developers realized that if all device information was exported to user space, it could perform all the necessary management of the /dev tree.
devfs has some very fundamental flaws in its design. It requires every device driver to be modified to support it, and it requires that device driver to specify the name and location within the /dev tree where it is placed. It also does not properly handle dynamic major and minor numbers, and it does not allow user space to override the naming of a device in a simple manner, forcing the device naming policy to reside within the kernel and not in user space. Linux kernel developers really hate having policy within the kernel, and since the devfs naming policy does not follow the Linux Standard Base specification, it really bothers them.
As the Linux kernel started to be installed on huge servers, a lot of users ran into the problem of how to manage very large numbers of devices. Disk drive arrays of over 10,000 unique devices presented the very difficult task of ensuring that a specific disk was always named with the same exact name, no matter where it was placed in the disk array or when it was discovered by the kernel. This same problem also plagued desktop users who tried to plug two USB printers into their system and then realized that they had no way of ensuring that the printer known as /dev/lpt0 would not change and be assigned to the other printer if the system was rebooted.
So, udev was created. It relies on all device information being exported to user space through sysfs and on being notified by /sbin/hotplug that a device was added or removed. Policy decisions, such as what name to give a device, can be specified in user space, outside of the kernel. This ensures that the naming policy is removed from the kernel and allows a large amount of flexibility about the name of each device
什么是udev?为什么需要udev?
udev是一个可以在user space就控制设备的一个东西。以前Linux用的是devfs,但是这个东西有很大的弊病,比如设备名称不固定(按照设备插入机器的先后顺序确定设备文件名,即在/dev目录下的文件名,或根据硬件所在的插槽确定设备文件名,这就导致了比如硬盘换个IDE口,USB设备反复插拔的时候,设备文件名不统一的情况),等很多问题,详情看来自Linux Device Driver一书的说明:
One of the main reasons for creating the unified driver model in the kernel was to allow user space to manage the /dev tree in a dynamic fashion. This had previously been done in user space with the implementation of devfs, but that code base has slowly rotted away, due to a lack of an active maintainer and some unfixable core bugs. A number of kernel developers realized that if all device information was exported to user space, it could perform all the necessary management of the /dev tree.
devfs has some very fundamental flaws in its design. It requires every device driver to be modified to support it, and it requires that device driver to specify the name and location within the /dev tree where it is placed. It also does not properly handle dynamic major and minor numbers, and it does not allow user space to override the naming of a device in a simple manner, forcing the device naming policy to reside within the kernel and not in user space. Linux kernel developers really hate having policy within the kernel, and since the devfs naming policy does not follow the Linux Standard Base specification, it really bothers them.
As the Linux kernel started to be installed on huge servers, a lot of users ran into the problem of how to manage very large numbers of devices. Disk drive arrays of over 10,000 unique devices presented the very difficult task of ensuring that a specific disk was always named with the same exact name, no matter where it was placed in the disk array or when it was discovered by the kernel. This same problem also plagued desktop users who tried to plug two USB printers into their system and then realized that they had no way of ensuring that the printer known as /dev/lpt0 would not change and be assigned to the other printer if the system was rebooted.
So, udev was created. It relies on all device information being exported to user space through sysfs and on being notified by /sbin/hotplug that a device was added or removed. Policy decisions, such as what name to give a device, can be specified in user space, outside of the kernel. This ensures that the naming policy is removed from the kernel and allows a large amount of flexibility about the name of each device
udev说穿了,一个非常重要的功能就是可以通过sysfs提供的硬件信息,加上我们(即Linux的用户)定义好的匹配逻辑,来给设备命名,即维护/dev目录下的文件。用户可以配置的就是/etc/udev/rules.d目录下的.rules文件,在这些文件中,通过定义匹配逻辑,就可以给设备命名,改名,建立符号链接,修改owner和权限,在设备插入或拔出的时候执行特定的程序等等:
CentOS4.4开始内置支持Infiniband,在/etc/udev/rules.d目录下就有一个90-ib.rules的文件,其中就规定了infiniband设备的文件名的创建逻辑,有兴趣可以去参考哦。
2.6内核的sys文件系统和udev真是好东西,给了一个很好的途径让我们来了解设备信息,控制设备文件。
这里有一篇非常非常经典的有关udev,udev rules writing的文章,文章中不仅讲解清晰,而且例子很典型,有问题就可以来读这篇文章,非常非常不错。这里列举一些例子吧,文章请check 附件1
KERNEL=="hdc", SYMLINK+="cdrom cdrom0"
查找kernel中名字为hdc的设备(一般是光驱),然后在/dev目录下建立链接文件/dev/cdrom, /dev/cdrom0,指向/dev/hdc,我们也可以通过NAME来指定设备的文件名(不是链接文件)
KERNEL=="mice", NAME="input/%k"
查找kernel中名为mice的设备(鼠标),然后在/dev目录下建立设备文件/dev/input/mice。%k表示kernel,这个通配符就表示kernel name。还有%n,这个表示device number(比如/dev/hda3,%n就表示3)
KERNEL=="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"
查找kernel中名为fd, fd0, fd1, ... fd9的设备(软驱),在/dev目录下建立设备文件/dev/floopy/0, /dev/floppy/1, ... /dev/floppy/9,并建立链接文件/dev/fd0.../dev/fd9,指向/dev/floppy/0.../dev/floppy/9
BUS=="scsi", SYSFS{model}=="ST3120827AS", NAME="my_hard_disk"
这里就用到了SYSFS了,比如这个model显然是个希捷的硬盘,就可以这样匹配哦。
KERNEL=="eth*", SYSFS{address}=="00:52:8b:d5:04:48", NAME="lan"
这里是一个对网络接口操作的rule,匹配eth*的设备,通过MAC地址来匹配,然后建立设备文件/dev/lan,很不错吧?
我们可以用udevinfo来查看设备的信息,比如:
# udevinfo -a -p /sys/class/net/eth0
looking at class device '/sys/class/net/eth0':
SYSFS{address}=="00:52:8b:d5:04:48"
CentOS4.4开始内置支持Infiniband,在/etc/udev/rules.d目录下就有一个90-ib.rules的文件,其中就规定了infiniband设备的文件名的创建逻辑,有兴趣可以去参考哦。
2.6内核的sys文件系统和udev真是好东西,给了一个很好的途径让我们来了解设备信息,控制设备文件。
这里有一篇非常非常经典的有关udev,udev rules writing的文章,文章中不仅讲解清晰,而且例子很典型,有问题就可以来读这篇文章,非常非常不错。这里列举一些例子吧,文章请check 附件1
KERNEL=="hdc", SYMLINK+="cdrom cdrom0"
查找kernel中名字为hdc的设备(一般是光驱),然后在/dev目录下建立链接文件/dev/cdrom, /dev/cdrom0,指向/dev/hdc,我们也可以通过NAME来指定设备的文件名(不是链接文件)
KERNEL=="mice", NAME="input/%k"
查找kernel中名为mice的设备(鼠标),然后在/dev目录下建立设备文件/dev/input/mice。%k表示kernel,这个通配符就表示kernel name。还有%n,这个表示device number(比如/dev/hda3,%n就表示3)
KERNEL=="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"
查找kernel中名为fd, fd0, fd1, ... fd9的设备(软驱),在/dev目录下建立设备文件/dev/floopy/0, /dev/floppy/1, ... /dev/floppy/9,并建立链接文件/dev/fd0.../dev/fd9,指向/dev/floppy/0.../dev/floppy/9
BUS=="scsi", SYSFS{model}=="ST3120827AS", NAME="my_hard_disk"
这里就用到了SYSFS了,比如这个model显然是个希捷的硬盘,就可以这样匹配哦。
KERNEL=="eth*", SYSFS{address}=="00:52:8b:d5:04:48", NAME="lan"
这里是一个对网络接口操作的rule,匹配eth*的设备,通过MAC地址来匹配,然后建立设备文件/dev/lan,很不错吧?
我们可以用udevinfo来查看设备的信息,比如:
# udevinfo -a -p /sys/class/net/eth0
looking at class device '/sys/class/net/eth0':
SYSFS{address}=="00:52:8b:d5:04:48"
udevinfo的option含义如下:
[root@jofo80 ~]# udevinfo
Usage: udevinfo [-anpqrVh]
-q TYPE query database for the specified value:
'name' name of device node
'symlink' pointing to node
'path' sysfs device path
'env' the device related imported environment
'all' all values
-p PATH sysfs device path used for query or chain
-n NAME node/symlink name used for query
-r prepend to query result or print udev_root
-a print all SYSFS_attributes along the device chain
-e export the content of the udev database
-V print udev version
-h print this help text
Usage: udevinfo [-anpqrVh]
-q TYPE query database for the specified value:
'name' name of device node
'symlink' pointing to node
'path' sysfs device path
'env' the device related imported environment
'all' all values
-p PATH sysfs device path used for query or chain
-n NAME node/symlink name used for query
-r prepend to query result or print udev_root
-a print all SYSFS_attributes along the device chain
-e export the content of the udev database
-V print udev version
-h print this help text
因为要通过-p命令来指定设备在/sys下的具体位置,有的时候我们不知道设备在/sys下的具体位置啊,这是就可以用udevinfo的-q option来查询,当然了,要能查询必须这个设备现在连在机器上,而且我们知道这个设备在/dev下面的设备文件名,如:
udevinfo -q path -n /dev/hda
这样就能查到我们的硬盘在/sys下的路径是/block/hda
所以,综合以下,可以这样查询:
udevinfo -a -p $(udevinfo -q path -n /dev/hda)
参考资料:/Files/super119/Writing_udev_rules.mht.zip
这里还有一篇中文文章,可以参考,不过看明白了上面的文章,这个也是仅仅参考参考的了,因为这篇文章也来自上面那篇英文文章:
背景:
昨天在gnome的一个panel上加了几个disk Mounter的按钮,每个都有一个设置的界面,需要设mount的位置,
当Mouse点击时,disk mounter会调用mount程序,具体mount什么设置由/etc/fstab来决定,
/dev/hde1 /media/ms0 vfat user,sync,noauto,uni_xlate 0 0
/dev/hdg1 /media/cf0 vfat user,sync,noauto,uni_xlate 0 0
当MS插入系统时,系统发现他是一个BLOCK设备,于是就在/hde开始找第一个安全空闲的盘符,同样CF插入的情况也类似,
这里有一个问题,当CF先插入时,系统会把/dev/hde1分配给它。此时对应的关系就发生了混乱。
为了解决这个问题可以使用linux2.6kernel的UDEV规则。
udev规则简介
关于这个规则,有一篇很经典的英文说明 http://www.reactivated.net/writing_udev_rules.html
udev是一种Linux2.6内核采用的/dev 目录的管理系统,它通过从sysfs获得的信息,可以提供对特定设备的固定的设备名。
sysfs是linux 2.6内核的一种新型文件系统,它提供了当前设备的基本信息。
udev的一个重要目的就是提供固定的设备名,像我们刚才碰到的情况,如果ms插入系统,系统能使用固定的设备名
(例如/dev/ms) CF卡插入系统,使用/dev/cf,就可以很方便的解决我们需要到的困难。
/etc/udev/rules.d/ 下面的文件根据字母的顺序来解析,一般udev当找到满足它条件的说明项后就会终于解析过程,
因为为了使用我们的配置优先于系统的默认值,选择文件名时一定要注意,例如,我们选择 /etc/udev/rule.d/10-local.rules
BUS="usb", SYSFS{serial}="HXOLL0012202323480", NAME="lp_epson", SYMLINK="printers/epson_stylus"
上面是一个USB打印机的印子。当一台USB打印机序列号是HXOLL0012202323480,就会创建一个device名 /dev/lp_epson,
同时创建一个symbol link /dev/printers/epson_styles
注意:在任何规则修改后,为了让它生效:需要执行udevstart
规则书写格式
最方便的查找方法是 man udev 或在线文档 http://www.die.net/doc/linux/man/man8/udev.8.html
常用的有
* BUS - 匹配总路类型,比如PCI USB等 * KERNEL - 匹配Kernel设备名,比如hda hdb. * DRIVER - 匹配Kernel的驱动程序名 * SUBSYSTEM - 匹配子系统名。 * ID - 匹配总路系统的ID (e.g. PCI bus ID)。 * PLACE - 匹配物理位置 (对USB很有用)。 * SYSFS{filename} - 匹配从sysfs得到的信息,比如label, vendor, USB serial number, SCSI UUID or file system label. * PROGRAM - 调用外部程序。 * RESULT - 匹配最后一次调用外部程序所得到的返回字符串 * NAME - 需要创建的设备或 * SYMLINK -需要创建的符号链接名 * OWNER, GROUP, MODE 设置设备的所有者,组,及模式
匹配符号:
%n 内核设备号 例如 sda3 的3 %k 内核设备名 %M 设备的major号 %m 设备的minor号 %b bus id %c %s{filename} sysfs属性的内容 %% 引用%时使用 * 可以匹配任意个字符 ? 可以匹配一个字符 [ ] 从中选一个字符sample:
# if /sbin/scsi_id returns "OEM 0815" device will be called disk1BUS="scsi", PROGRAM="/sbin/scsi_id", RESULT="OEM 0815", NAME="disk1"# USB printer to be called lp_colorBUS="usb", SYSFS{serial}="W09090207101241330", NAME="lp_color"# SCSI disk with a specific vendor and model number will be called bootBUS="scsi", SYSFS{vendor}="IBM", SYSFS{model}="ST336", NAME="boot%n"# sound card with PCI bus id 00:0b.0 to be called dspBUS="pci", ID="00:0b.0", NAME="dsp"# USB mouse at third port of the second hub to be called mouse1BUS="usb", PLACE="2.3", NAME="mouse1"# ttyUSB1 should always be called pda with two additional symlinksKERNEL="ttyUSB1", NAME="pda", SYMLINK="palmtop handheld"# multiple USB webcams with symlinks to be called webcam0, webcam1, ……BUS="usb", SYSFS{model}="XV3", NAME="video%n", SYMLINK="webcam%n"
查看sysfs的信息
这里使用udevinfo的指令, man udevinfo 在线文档http://www.die.net/doc/linux/man/man8/udevinfo.8.html 基本用法
-a SYSFS{filename} attributes along the device chain. -p sysfs_path Specify the sysfs path of the device to query. -q query_type Query the database for specified value of a created device node or network interface. valid type: name, symlink, mode ,owner , group , path or all. -n name Specify the name of the node, the symlink or the network interface for the device to queue sample:
udevinfo -a -p /sys/path/to/hardware/info udevinfo -a -p /sys/block/sda udevinfo -q path -n /dev/sda 联起来用: # udevinfo -a -p $(udevinfo -q path -n /dev/sda)
测试方法
# udevtest /sys/class/sound/dsp/version 056looking at '/class/sound/dsp/'opened class_dev->name='dsp'configured rule in '/etc/udev/rules.d/50-udev.rules[132]' applied, added symlink '%k'configured rule in '/etc/udev/rules.d/50-udev.rules[132]' applied, 'dsp' becomes 'sound/%k'creating device node '/dev/sound/dsp', major = '14', minor = '3', mode = '0660', uid = '0', gid = '18'
实际的例子
010_local.rules
#Clie th55#syncBUS="usb", SYSFS{product}="Palm Handheld", KERNEL="ttyUSB*", SYMLINK="pilot%n"#exportBus="usb", SYSFS{product}="Sony PEG Mass Storage", KERNEL="sd*",SYMLINK="cliems"#usb HDDBUS="usb", SYSFS{product}="USB TO IDE", KERNEL="sd*", SYMLINK="usbhdd%n"#cf1 used for 5in1 card readerBUS="ide", ID="2.0", KERNEL="hd*", SYMLINK="ms"]
昨天在gnome的一个panel上加了几个disk Mounter的按钮,每个都有一个设置的界面,需要设mount的位置,
当Mouse点击时,disk mounter会调用mount程序,具体mount什么设置由/etc/fstab来决定,
/dev/hde1 /media/ms0 vfat user,sync,noauto,uni_xlate 0 0
/dev/hdg1 /media/cf0 vfat user,sync,noauto,uni_xlate 0 0
当MS插入系统时,系统发现他是一个BLOCK设备,于是就在/hde开始找第一个安全空闲的盘符,同样CF插入的情况也类似,
这里有一个问题,当CF先插入时,系统会把/dev/hde1分配给它。此时对应的关系就发生了混乱。
为了解决这个问题可以使用linux2.6kernel的UDEV规则。
udev规则简介
关于这个规则,有一篇很经典的英文说明 http://www.reactivated.net/writing_udev_rules.html
udev是一种Linux2.6内核采用的/dev 目录的管理系统,它通过从sysfs获得的信息,可以提供对特定设备的固定的设备名。
sysfs是linux 2.6内核的一种新型文件系统,它提供了当前设备的基本信息。
udev的一个重要目的就是提供固定的设备名,像我们刚才碰到的情况,如果ms插入系统,系统能使用固定的设备名
(例如/dev/ms) CF卡插入系统,使用/dev/cf,就可以很方便的解决我们需要到的困难。
/etc/udev/rules.d/ 下面的文件根据字母的顺序来解析,一般udev当找到满足它条件的说明项后就会终于解析过程,
因为为了使用我们的配置优先于系统的默认值,选择文件名时一定要注意,例如,我们选择 /etc/udev/rule.d/10-local.rules
BUS="usb", SYSFS{serial}="HXOLL0012202323480", NAME="lp_epson", SYMLINK="printers/epson_stylus"
上面是一个USB打印机的印子。当一台USB打印机序列号是HXOLL0012202323480,就会创建一个device名 /dev/lp_epson,
同时创建一个symbol link /dev/printers/epson_styles
注意:在任何规则修改后,为了让它生效:需要执行udevstart
规则书写格式
最方便的查找方法是 man udev 或在线文档 http://www.die.net/doc/linux/man/man8/udev.8.html
常用的有
* BUS - 匹配总路类型,比如PCI USB等 * KERNEL - 匹配Kernel设备名,比如hda hdb. * DRIVER - 匹配Kernel的驱动程序名 * SUBSYSTEM - 匹配子系统名。 * ID - 匹配总路系统的ID (e.g. PCI bus ID)。 * PLACE - 匹配物理位置 (对USB很有用)。 * SYSFS{filename} - 匹配从sysfs得到的信息,比如label, vendor, USB serial number, SCSI UUID or file system label. * PROGRAM - 调用外部程序。 * RESULT - 匹配最后一次调用外部程序所得到的返回字符串 * NAME - 需要创建的设备或 * SYMLINK -需要创建的符号链接名 * OWNER, GROUP, MODE 设置设备的所有者,组,及模式
匹配符号:
%n 内核设备号 例如 sda3 的3 %k 内核设备名 %M 设备的major号 %m 设备的minor号 %b bus id %c %s{filename} sysfs属性的内容 %% 引用%时使用 * 可以匹配任意个字符 ? 可以匹配一个字符 [ ] 从中选一个字符sample:
# if /sbin/scsi_id returns "OEM 0815" device will be called disk1BUS="scsi", PROGRAM="/sbin/scsi_id", RESULT="OEM 0815", NAME="disk1"# USB printer to be called lp_colorBUS="usb", SYSFS{serial}="W09090207101241330", NAME="lp_color"# SCSI disk with a specific vendor and model number will be called bootBUS="scsi", SYSFS{vendor}="IBM", SYSFS{model}="ST336", NAME="boot%n"# sound card with PCI bus id 00:0b.0 to be called dspBUS="pci", ID="00:0b.0", NAME="dsp"# USB mouse at third port of the second hub to be called mouse1BUS="usb", PLACE="2.3", NAME="mouse1"# ttyUSB1 should always be called pda with two additional symlinksKERNEL="ttyUSB1", NAME="pda", SYMLINK="palmtop handheld"# multiple USB webcams with symlinks to be called webcam0, webcam1, ……BUS="usb", SYSFS{model}="XV3", NAME="video%n", SYMLINK="webcam%n"
查看sysfs的信息
这里使用udevinfo的指令, man udevinfo 在线文档http://www.die.net/doc/linux/man/man8/udevinfo.8.html 基本用法
-a SYSFS{filename} attributes along the device chain. -p sysfs_path Specify the sysfs path of the device to query. -q query_type Query the database for specified value of a created device node or network interface. valid type: name, symlink, mode ,owner , group , path or all. -n name Specify the name of the node, the symlink or the network interface for the device to queue sample:
udevinfo -a -p /sys/path/to/hardware/info udevinfo -a -p /sys/block/sda udevinfo -q path -n /dev/sda 联起来用: # udevinfo -a -p $(udevinfo -q path -n /dev/sda)
测试方法
# udevtest /sys/class/sound/dsp/version 056looking at '/class/sound/dsp/'opened class_dev->name='dsp'configured rule in '/etc/udev/rules.d/50-udev.rules[132]' applied, added symlink '%k'configured rule in '/etc/udev/rules.d/50-udev.rules[132]' applied, 'dsp' becomes 'sound/%k'creating device node '/dev/sound/dsp', major = '14', minor = '3', mode = '0660', uid = '0', gid = '18'
实际的例子
010_local.rules
#Clie th55#syncBUS="usb", SYSFS{product}="Palm Handheld", KERNEL="ttyUSB*", SYMLINK="pilot%n"#exportBus="usb", SYSFS{product}="Sony PEG Mass Storage", KERNEL="sd*",SYMLINK="cliems"#usb HDDBUS="usb", SYSFS{product}="USB TO IDE", KERNEL="sd*", SYMLINK="usbhdd%n"#cf1 used for 5in1 card readerBUS="ide", ID="2.0", KERNEL="hd*", SYMLINK="ms"]