[TOC]
描述: Linux 用户常常会很难鉴别同一类型的设备名,比如 eth0, eth1, sda, sdb 等等。通过观察这些设备的内核设备名称,用户通常能知道这些是什么类型的设备,但是不知道哪一个设备是他们想要的
例如:在一个充斥着本地磁盘和光纤磁盘的设备名清单 (/dev/sd*) 中,用户无法以名称找到一个序列号为“35000c50000a7ef67”的磁盘。
在这种情况下通过udev
就能动态地在 /dev 目录里产生自己想要的、标识性强的设备文件或者设备链接,以此帮助用户方便快捷地找到所需的设备文件。
Q: 什么是 udev?
答: udev 是
Linux kernel 2.6
系列的一个设备管理器功能,由Greg Kroah-Hartman和Kay Sievers共同开发并得到Dan Stekloff等人的帮助, 它在2012年4月 udev 被合并至 systemd; udev 以守护进程的形式运行,通过侦听内核发出来的 uevent 来管理 /dev目录下的设备文件, 它替代了原来的 devfs 及 hotplug 的功能;
Q: 为何要选择使用udev?
答: 在传统的Linux系统中
/dev目录下
的设备节点为一系列静态存在的文件, 而udev则动态提供了在系统中实际存在的设备节点
, 虽然在Linux中是采用的devfs提供类似功能但是udev有更好使用的理由:
并不依赖于设备插入系统的顺序
, 即默认的udev设置提供了存储设备的固定命名可以使用其vid(vendor)、pid(device)、设备名称(model)
等属性或其父设备的对应属性来确认某一设备。不是像devfs在内核空间 (kernel space) 一样执行
, 结果就是udev将命名策略从内核中移走并可以在节点创建前用任意程序在设备属性中为设备命名。运行原理:
netlink socket
)所发出的 uevent(早期的版本使用hotplug,并在/etc/hotplug.d/default添加一个链接到自身来达到目的
),并通过一套规则用于匹配可发现的设备事件和属性的导出值, 该规则并可以根据匹配像内核子系统、内核设备名称、设备的物理等属性或设备序列号的属性
, 来对设备设定一个持久的名称,而不管该设备什么时候被发现添加;udev功能特点
不同版本实现或许不同
)Q: 总结一句话简述udev的作用? 答: 系统识别设备都会在/dev目录下创建设备文件与主、次设备表号等每次卸载挂载后其设备名称将会动态的变化, 对于我们来说当然不希望出现这样的情况, 它可以为设备提供持久、自定义的设备名称进行挂载到系统上便于使用者区分使用。
udev 工作流程图:
WeiyiGeek.流程图显示 udev 添加 / 删除设备文件的过程
系统架构:
相关术语:
可被应用程序用来和设备驱动交互的文件
。而不会特别地区分设备文件、设备节点或者设备特殊文件;把设备和驱动的信息从内核的设备模块导出到用户空间 (userspace)
。从该文件系统中Linux 用户可以获取很多设备的属性可以帮助我们编写udev规则。例如:sda的 devpath是 /block/sda,sda2 的 devpath是 /block/sda/sda2
udevadm info -a -n /dev/sda | grep "KERNEL"
返回的即为内核设备名称 KERNEL==”sda”注意事项:
描述:从 Fedora3 和 Red Hat Enterprise4 开始,udev 就是默认的设备管理工具并且现在udev已经被集成到systemd中,所以常用的Linux发行版本无需另外下载安装;
检查1.查看系统中版本以及udev运行情况
# 1.CentOS
$yum list | grep "libgudev1"
libgudev1.i686 219-73.el7_8.9 updates
libgudev1.x86_64 219-73.el7_8.9 updates
libgudev1-devel.i686 219-73.el7_8.9 updates
libgudev1-devel.x86_64 219-73.el7_8.9 updates
# 2.Ubuntu
$apt list | egrep "^udev"
udev/focal-updates,now 245.4-4ubuntu3.2 amd64 [installed,automatic]
# 3.运行状态查看
$ ps -ef | grep "udev"
UID PID PPID C STIME TTY TIME CMD
root 15981 1 0 9月11 ? 00:00:00 /usr/lib/systemd/systemd-udevd # 已经集成到systemd中了
$ systemctl status udev.service
● systemd-udevd.service - udev Kernel Device Manager
Loaded: loaded (/lib/systemd/system/systemd-udevd.service; static; vendor preset: enabled)
Active: active (running) since Tue 2020-09-15 09:27:07 CST; 13h ago
TriggeredBy: ● systemd-udevd-kernel.socket
● systemd-udevd-control.socket
Docs: man:systemd-udevd.service(8)
man:udev(7)
Main PID: 823 (systemd-udevd)
Status: "Processing with 96 children at max"
Tasks: 1
Memory: 171.5M
CGroup: /system.slice/systemd-udevd.service
└─823 /lib/systemd/systemd-udevd
udev 配置目录一览:
# 此处以Ubuntu 20.04 TLS 为例
$ tree -l /etc/udev/
/etc/udev/
├── hwdb.d
├── rules.d
│ ├── 70-snap.snapd.rules
│ └── ubuntu--vg-ubuntu--lv.rules
└── udev.conf
2 directories, 3 files
说明1.udev 的配置文件/etc/udev/udev.conf
$ cat /etc/udev/udev.conf # Ubuntu
# see udev.conf(5) for details
#
# udevd is also started in the initrd. When this file is modified you might
# also want to rebuild the initrd, so that it will include the modified configuration.
#udev_log=info
#children_max=
#exec_delay=
#event_timeout=180
#resolve_names=early
不建议修改
)不建议修改
)# (1) udev指令操作符:
== # 表示匹配 比较键、值,若等于,则该条件满足;
!= # 表示不匹配 比较键、值,若不等于,则该条件满足;
= # 指定要赋予的值 对一个键赋值;
+= # 添加新值 为一个表示多个条目的键赋值。
:= # 指定的值且不允许被替换 对一个键赋值,并拒绝之后所有对该键的改动
描述:当编写可能处理多个类似设备的规则时,udev的类似printf的字符串替换操作符非常有用。Linux 用户可以随意地定制 udev 规则文件的值;
例如:my_root_disk, my_printer 同时也可以引用下面的替换操作符:
$kernel, %k:设备的内核设备名称, 例如“sda3”表示将(默认情况下)出现在/dev/sda3上的设备
$number, %n: 计算设备的内核号(存储设备的分区号): e.g. "3" for /dev/sda3
$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:临时设备名。
%%:符号 % 本身。
$$:符号 $ 本身。
简单实例:
# 1.下面示例中的$kernel和$number是替换操作符的规则例子
# 第一个规则确保mice设备节点只出现在/dev/input目录中(默认情况下是在/dev/mice)
# 第二个规则确保名为loop0的设备节点在/dev/loop/0处创建,并且像往常一样在/dev/loop0处创建一个符号链接。
KERNEL=="mice", NAME="input/%k"
KERNEL=="loop0", NAME="loop/%n", SYMLINK+="%k"
# 2.该规则的执行:如果有一个内核设备名称以 sd 开头,且 SCSI ID 为 35000c50000a7ef67,则为设备文件产生一个符号链接“sda_35000c50000a7ef67”.
KERNEL=="sd*", PROGRAM="/lib/udev/scsi_id -g -s %p", \
RESULT=="35000c50000a7ef67", SYMLINK="%k_%c"
# 使用shell风格的模式匹配(实际都是正则这里不过多接受了)
* - match any character, zero or more times
? - match any character exactly once
[] - match any single character specified in the brackets, ranges are also permitted
# 1.基础示例
# 第一个规则匹配所有软盘驱动器,并确保设备节点被放置在/dev/floppy目录中,并从默认名称创建符号链接。
# 第二条规则确保hiddev设备只存在于/dev/usb目录中。
KERNEL=="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"
KERNEL=="hiddev*", NAME="usb/%k"
注意在 RHEL5.3 的 udev 已经没有权限文件,所有的权限都是通过规则文件 (*.rules)
来设置
描述:用于精确装置匹配设备的规则常用如下:
/dev/block/
和/dev/net
;SYSFS{model}==“ST936701SS”
表示如果设备的型号为 ST936701SS,则该设备匹配该匹配键。简单实例:
# 示例1.匹配键与操作符
NAME = "udisk", # 定义设备名称
SYMLINK += "data1", # 定义设备的别名
OWNER = "student", # 定义设备的所有者
MODE = "0600", # 定义设备的权限
ACTION == "add", # 判断设备的操作动作、添加或删除设备等
KERNEL == "sd[a-z]1", # 判断设备的内核名称
RUN += 程序 # 为设备添加程序
# 示例2.如果设备的型号为 ST936701SS并且sysfs的size属性匹配234441648值,则该设备匹配该匹配键
SUBSYSTEM=="block",SYSFS{model}=="ST936701SS",ATTR{size}=="234441648", SYMLINK+="my_disk"
# 示例3.调用外部命令 /lib/udev/scsi_id查询设备的 SCSI ID,如果返回结果为 35000c50000a7ef67,则该设备匹配该匹配键。
SUBSYSTEM=="block",PROGRAM=="/lib/udev/scsi_id -g -s $devpath", RESULT=="35000c50000a7ef67"
注意事项:
描述: 当我们为指定的设备设定规则时,首先需要知道该设备的属性,比如设备的序列号、磁盘大小、厂商 ID、设备路径等等。通常我们可以通过以下的方法获得:
sysfs设备的信息(属性):
# (1) 目录表示具有相应设备节点的实际设备
$sudo find /sys -name dev | grep "pci"
/sys/devices/pci0000:00/0000:00:1f.2/ata10/host11/target11:0:0/11:0:0:0/scsi_generic/sg1/dev
/sys/devices/pci0000:00/0000:00:1f.2/ata10/host11/target11:0:0/11:0:0:0/block/sr0/dev
/sys/devices/pci0000:00/0000:00:1f.2/ata10/host11/target11:0:0/11:0:0:0/bsg/11:0:0:0/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/scsi_generic/sg0/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda4/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda2/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda3/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda1/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/bsg/0:2:0:0/dev
/sys/devices/pci0000:00/0000:00:1c.3/0000:03:00.0/ptp/ptp2/dev
/sys/devices/pci0000:00/0000:00:1c.3/0000:03:00.1/ptp/ptp3/dev
/sys/devices/pci0000:00/0000:00:1c.1/0000:07:00.0/0000:08:00.0/0000:09:00.0/0000:0a:00.0/graphics/fb0/dev
/sys/devices/pci0000:00/0000:00:1c.1/0000:07:00.0/0000:08:00.0/0000:09:00.0/0000:0a:00.0/i2c-0/i2c-dev/i2c-0/dev
/sys/devices/pci0000:00/0000:00:1c.1/0000:07:00.0/0000:08:00.0/0000:09:00.0/0000:0a:00.0/drm/card0/dev
/sys/devices/pci0000:00/0000:00:1a.0/usb1/dev
/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/dev
/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.6/dev
/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/dev
/sys/devices/pci0000:00/0000:00:1d.0/usb2/dev
/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.0/host4/port-4:1/end_device-4:1/bsg/end_device-4:1/dev
/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.0/host4/port-4:0/end_device-4:0/bsg/end_device-4:0/dev
/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.0/host4/bsg/sas_host4/dev
/sys/devices/pci0000:00/0000:00:1c.2/0000:02:00.0/ptp/ptp0/dev
/sys/devices/pci0000:00/0000:00:1c.2/0000:02:00.1/ptp/ptp1/dev
# (2) 例如在我的系统上 `/sys/block/sda` 目录是我的硬盘的设备路径, 它通过 /sys/block/sda/device 符号链接链接到它的上级SCSI磁盘设备;
$ cat /sys/block/sda/size
2341994496 # 在规则中可以使用ATTR{size}=="234441648"来标识该磁盘
$ cat /sys/block/sda/dev
8:0
补充udev规则所需属性:
# (0) 通过 scsi_id 查询磁盘的 SCSI_ID 的例子
/usr/lib/udev/scsi_id -g -u 设备名
scsi_id -g -s /block/sda
35000c50000a7ef67
# (1) 例如:用 udevinfo 查询设备 sda 的 model 和 size 信息:
udevinfo -a -p /sys/block/sda
udevinfo -a -p /block/sda | egrep "model|size"
SYSFS{size}=="71096640"
SYSFS{model}=="ST936701SS"
# 或者
udevadm info -q path -n /dev/sda
/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0/1:0:0:0/block/sda
udevadm info -a -q $(udevadm info -q path -n /dev/sda) |
udevadm info -a -n /dev/sda | egrep "model|size"
# ATTR{size}=="104857600"
# ATTRS{model}=="Virtual disk "
描述:udev 配置文件是 /etc/udev/udev.conf 该文件内容中有指定udev规则存储目录形如 udev_rules="/etc/udev/rules.d"
该指定的目录中存储一系列以.rules结束的规则文件, 每个文件处理一系列规则来帮助udev分配名字给设备文件并保证内核可以识别此设备名称。
(1) 规则文件由系列键-值对组成, 键值对分两类:匹配键(使用操作符"==","!="等
) 和 赋值键(使用"=","+=",":="等)
, 匹配键判断规则是否应被应用,赋值键可以被分配一到多个值。
# 规则语法: 每个规则由一系列键 - 值对,这是由逗号分隔的构造
# 实例1.KERNEL 是匹配键,NAME 和 MODE 是赋值键
KERNEL=="hdb", NAME="my_spare_disk"
# 如果有一个设备的内核设备名称为 sda则该条件生效,执行后面的赋值:在 /dev下产生一个名为 my_root_disk的设备文件,并把设备文件的权限设为 0660。
KERNEL=="sda", NAME="my_root_disk", MODE="0660"
(2) 规则文件必须以”.rules”为后缀名, 在 RHEL 有默认的规则文件,这些默认规则文件不仅为设备产生内核设备名称,还会产生标识性强的符号链接。
/dev/disk/by-uuid/ 16afe28a-9da0-482d-93e8-1a9474e7245c
查看已为您的存储硬件创建的持久性名称:
$ls -lR /dev/disk
/dev/disk:
total 0
drwxr-xr-x 2 root root 60 Sep 14 08:48 by-dname
drwxr-xr-x 2 root root 140 Sep 14 08:48 by-id
drwxr-xr-x 2 root root 120 Sep 14 08:48 by-partuuid
drwxr-xr-x 2 root root 180 Sep 14 08:48 by-path
$tree -l /dev/disk
/dev/disk
├── by-id
│ ├── ata-VMware_Virtual_SATA_CDRW_Drive_00000000000000000001 -> ../../sr0
│ ├── dm-name-centos-root -> ../../dm-0
│ ├── dm-name-centos-swap -> ../../dm-1
│ ├── dm-uuid-LVM-aU2d8DppVRkxbqQEFXw2K1tUjzEIAQ83cLOioKmuP4CzguVYh6jGG8qKYeQH9BLJ -> ../../dm-1
│ ├── dm-uuid-LVM-aU2d8DppVRkxbqQEFXw2K1tUjzEIAQ83pkIKVVfwHPfFSrDXwmzJgh1BD4v7yjbJ -> ../../dm-0
│ └── lvm-pv-uuid-dBw5Er-e0CA-NnE5-9EZW-PQ08-iW0e-smzxdQ -> ../../sda2
├── by-path
│ ├── pci-0000:02:01.0-ata-1.0 -> ../../sr0
│ ├── pci-0000:03:00.0-scsi-0:0:0:0 -> ../../sda
│ ├── pci-0000:03:00.0-scsi-0:0:0:0-part1 -> ../../sda1
│ └── pci-0000:03:00.0-scsi-0:0:0:0-part2 -> ../../sda2
└── by-uuid
├── b4d40c4d-2103-4825-8c1e-0d3ce53fa1a1 -> ../../dm-1
├── dc1ba57c-3df8-43b5-a9c6-d7410a40f598 -> ../../sda1
└── e1e3ac22-fd97-4841-baa0-0c3e3a333f0f -> ../../dm-0
描述:该文件为udev主配置文件一般不用进行更改,如需更改请参考udev(5)
# 主配置文件:/etc/udev/udev.conf
- udev_root:创建设备文件位置,默认为/dev
- udev_rules:udev规则文件位置,默认为/etc/udev/rules.d
- udev_log : syslog优先级,缺省为err
# 文件位置及格式
- /etc/udev/rules.d/<rule_name>.rules
# 规则格式
<match-key><op><value>[,...]<assignment-key><op>value[,...]
描述: 这里是存放了相关规则来指定匹配硬件设备按照何种方式进行绑定名称;
基础实例:
# 示例1.匹配这是由内核建屋局并在名为设备的驱动程序是IDE磁盘。命名与默认名称的设备节点并创建一个符号链接到它命名sparedisk设备节点名称为my_spare_disk;
KERNEL=="hdb", DRIVER=="ide-disk", NAME="my_spare_disk", SYMLINK+="sparedisk"
# 示例2.它创建于的/dev/CDROM 和/dev/CDROM0两个点的/dev/hdc符号链接。同样没有名称分配指定因此将使用默认的内核名称HDC
KERNEL=="hdc", SYMLINK+="cdrom cdrom0"
# 示例3.匹配的sysfs中size属性234441648的设备创建/dev/my_disk符号连接
SUBSYSTEM=="block", ATTR{size}=="234441648", SYMLINK+="my_disk"
# 实例4.子系统是一个block设备匹配设备类型大小以及scsi id匹配RESULT规则时候将为该设备创建/dev/ipsan符号连接
$vim /etc/udev/rules.d/100-ipsan.rules
SUBSYSTEM=="block", // 设备类型
ATTR{size}=="41943040", // 设备大小
ATTRS{vendor}=="LIO-ORG ", // 厂家
PROGRAM=="/usr/lib/udev/scsi_id -g -u $devnode", // 要执行的程序
RESULT=="36001405423854f332574ae7ae493f2b0", // 执行程序后的结果
SYMLINK+="ipsan" // 别名
# 示例5.产生网卡设备文件的规则
# 该规则表示:如果存在设备的子系统为 net,并且地址 (MAC address) 为“AA:BB:CC:DD:EE:FF”,为该设备产生一个名为 public_NIC 的设备文件。
SUBSYSTEM=="net", SYSFS{address}=="AA:BB:CC:DD:EE:FF", NAME="public_NIC"
# 实例6.为指定大小的磁盘产生符号链接的规则
# 如果存在设备的子系统为 block,并且大小为 71096640(block),则为该设备的设备文件名产生一个名为 my_disk 的符号链接。
SUBSYSTEM=="block", SYSFS{size}=="71096640", SYMLINK ="my_disk"
# 实例7.通过外部命令为指定序列号的磁盘产生设备文件的规则
# 如果存在设备的内核设备名称是以 sd 开头 ( 磁盘设备 ),以数字结尾 ( 磁盘分区 ),并且通过外部命令查询该设备的 SCSI_ID 号为“35000c50000a7ef67”,则产生一个以 root_disk 开头,内核号码结尾的设备文件,并替换原来的设备文件(如果存在的话)。例如:产生设备名 /dev/root_disk2,替换原来的设备名 /dev/sda2。
KERNEL=="sd*[0-9]", PROGRAM=="/lib/udev/scsi_id -g -s %p", \
RESULT=="35000c50000a7ef67", NAME +="root_disk%n"
USB Printer 描述:我打开我的打印机它被分配了设备节点/dev/lp0,下面我想对其进行自定义设备符号名称;
# 设备信息获取
$udevadm info -a -p $(udevinfo -q path -n /dev/lp0)
looking at device '/class/usb/lp0':
KERNEL=="lp0"
SUBSYSTEM=="usb"
DRIVER==""
ATTR{dev}=="180:0"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb1/1-1':
SUBSYSTEMS=="usb"
ATTRS{manufacturer}=="EPSON"
ATTRS{product}=="USB Printer"
ATTRS{serial}=="L72010011070626380"
# udev 规则
SUBSYSTEM=="usb", ATTRS{serial}=="L72010011070626380", SYMLINK+="epson_680"
USB Camera 描述:和大多数相机一样,我的相机将自己标识为通过USB总线连接的外部硬盘使用SCSI传输。为了访问我的照片我挂载驱动器和复制图像文件到我的硬盘。
# USB Camera 设备信息
udevinfo -a -p $(udevinfo -q path -n /dev/sdb1)
looking at device '/block/sdb/sdb1':
KERNEL=="sdb1"
SUBSYSTEM=="block"
looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0/host6/target6:0:0/6:0:0:0':
KERNELS=="6:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{rev}=="1.00"
ATTRS{model}=="X250,D560Z,C350Z"
ATTRS{vendor}=="OLYMPUS "
ATTRS{scsi_level}=="3"
ATTRS{type}=="0"
# 规则
# 它出奇地简单:名称本身不同,因此我们可以在name字段上使用简单的模式匹配。
KERNEL=="sd?1", SUBSYSTEMS=="scsi", ATTRS{model}=="X250,D560Z,C350Z", SYMLINK+="camera" #即/dev/camera
USB Hard Disk 描述:USB硬盘可与我上面描述的USB相机相比较,然而典型的使用模式是不同的。 在相机的例子中我解释了我对sdb节点不感兴趣——它真正的用途只是用于分区(例如fdisk),但我为什么要对相机进行分区!?当然如果你有一个100GB的USB硬盘,这是完全可以理解的,你可能想要分区,在这种情况下,我们可以利用udev的字符串替换:
# This rule creates symlinks such as:
# /dev/usbhd - The fdiskable node
# /dev/usbhd1 - The first partition (mountable)
# /dev/usbhd2 - The second partition (mountable)
KERNEL=="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 Storage Device", SYMLINK+="usbhd%n"
USB Card Reader 描述:USB读卡器(CompactFlash、SmartMedia等)是另一种有不同使用要求的USB存储设备,比如下面将有节点命名:cfrdr, cfrdr1, cfrdr2, cfrdr3,…, cfrdr15。
# 利用all_partitions选项,它将为规则匹配的每个块设备创建16个分区节点:
KERNEL="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 CompactFlash Reader", SYMLINK+="cfrdr%n", OPTIONS+="all_partitions"
CD/DVD drives 描述:我有两个光驱在这台电脑:一个DVD阅读器(hdc)和一个DVD重写(hdd)。我不希望这些设备节点发生变化,除非我物理上重新连接我的系统。但是为了方便许多用户喜欢使用/dev/dvd这样的设备节点。
SUBSYSTEM=="block", KERNEL=="hdc", SYMLINK+="dvd", GROUP="cdrom"
SUBSYSTEM=="block", KERNEL=="hdd", SYMLINK+="dvdrw", GROUP="cdrom"
Network interfaces 描述:即使网络接口是通过名称引用的,它们通常也没有与之关联的设备节点。尽管如此规则编写过程几乎是相同的。
# udevadm info -a -p /sys/class/net/eth0
looking at class device '/sys/class/net/eth0':
KERNEL=="eth0"
ATTR{address}=="00:52:8b:d5:04:48"
#Here is my rule:
KERNEL=="eth*", ATTR{address}=="00:52:8b:d5:04:48", NAME="lan"
注意事项:
要使此规则生效需要重新加载网络驱动程序。您可以卸载并重新加载模块,或者简单地重新启动系统。您还需要重新配置您的系统,使其使用“lan”而不是“eth0”。
在我完全删除所有对eth0的引用之前,我在进行这个操作时遇到了一些麻烦(接口没有被重命名)。在此之后您应该能够在任何对ifconfig或类似实用程序的调用中使用“lan”而不是“eth0”;
$cat /etc/sysconfig/network-scripts/ifcfg-ens192
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="ens192"
UUID="78d46457-5eb7-4421-9637-ba4161637646"
DEVICE="ens192"
ONBOOT="yes"
生产实例1: ASM设备动态绑定
# 规则中写明了绑定源路径dm-*绑定磁盘的scsi id,绑定目标路径/dev/asm/hdisk00x,目标路径属组grid:asmadmin,目标路径权限066
$cat /etc/udev/rules.d/99-oracle-asmdevices.rules
KERNEL=="dm-*",ENV{DM_UUID}=="mpath-36005076xxx000000000010cb",SYMLINK+="asm/hdisk001",OWNER="grid",GROUP="asmadmin",MODE="0660"
KERNEL=="dm-*",ENV{DM_UUID}=="mpath-36005076xxx000000000010cc",SYMLINK+="asm/hdisk002",OWNER="grid",GROUP="asmadmin",MODE="0660"
KERNEL=="dm-*",ENV{DM_UUID}=="mpath-36005076xxx000000000010cd",SYMLINK+="asm/hdisk003",OWNER="grid",GROUP="asmadmin",MODE="0660"
# 执行结果:
[root@ybnode01 ~]# ls -lrt /dev/asm/hdisk0*
lrwxrwxrwx 1 root root 7 Jun 15 15:31 /dev/asm/hdisk017 -> ../dm-2
lrwxrwxrwx 1 root root 8 Jun 15 15:31 /dev/asm/hdisk002 -> ../dm-13
[root@ybnode01 ~]# ls -lrt /dev/dm*
brw-rw---- 1 grid asmadmin 253, 2 Jun 15 15:34 /dev/dm-2
brw-rw---- 1 grid asmadmin 253, 13 Jun 15 15:34 /dev/dm-13
root:root 777
。grid:asmadmin 0660
生产实例2: 在multipath中绑定了scsi id 而又在udev中再次绑定显得有些多余(但最好是这么做),在 scsi id 已绑定的前提下udev可以有如下绑定方式:
# 绑定方式没有在udev规则中绑定磁盘路径与磁盘scsi id 没有生成额外的路径,仅修改了/dev/dm*的权限。
# 这里的udev规则只是用来绑定磁盘权限,数据库可直接使用dm*
$cat /etc/udev/rules.d/12-dm-permissions.rules
ENV{DM_NAME}=="dm*",OWNER:="grid", GROUP:="asmadmin", MODE:="660"
另外做法是在 multipath.conf 中不写明wwid和alias的对应关系,只在udev中绑定源路径dm、目标路径、scsi id权限。
虽然这种方法有效但是很难理解
,其缺陷是如果multipath不生成dm那也轮不到udev去绑定,所以udev一定在multipath之后,multipath没有绑定scsi id那么是不是可能会multipath在启动的时候把scsi id识别错了,这个时候udev在去绑定scsi id和dm所以我个人并不推荐这种绑定方式。
不同的运维人员有不同的做法但无论哪种绑定方式,最终的目的就把磁盘路径和scsi id绑定,且绑定asm要使用的asm_disk的path的权限,理解multipath和udev才可以处理异常状况。
注意事项:
当设备名改变时在 /etc/fstab
里保持系统分区名称的一致性,而不会受驱动加载顺序或者磁盘标签被破坏的影响,导致操作系统启动时找不到系统分区。
触发udev编写的规则配置生效:
start_udev # RHEL6
systemctl restart systemd-udev-trigger.service # RHEL7
注:本地文件系统 ext2/3/4 xfs ,同时只能单台设备使用gfs 集群文件系统(谷歌的一个文件系统)
描述:udevadm需要命令和命令特定的选项, 它控制system-udevd的运行时行为、请求内核事件、管理事件队列,并提供简单的调试机制。
语法选项:
# Synx
udevadm [--debug] [--version] [--help]
udevadm info [options] [devpath]
udevadm trigger [options] [devpath]
udevadm settle [options]
udevadm control option
udevadm monitor [options]
udevadm test [options] devpath
udevadm test-builtin [options] command devpath
# Option
-d, --debug #打印调试消息到标准错误
-h, --help #打印一个简短的帮助文本并退出。
子命令:
info :查询udev数据库以获取设备信息(查询的可以是设备名称以/dev)或者一个sys路径。
# Option
-q, --query=TYPE #在数据库中查询指定类型的设备数据Valid TYPEs are: name, symlink, path, property, all.
-p, --path=DEVPATH #要查询的设备的/sys路径
# e.g. [/sys]/class/block/sda. This option is an alternative to the positional argument with a /sys/ prefix.
udevadm info --path=/class/block/sda is equivalent to udevadm info /sys/class/block/sda.
-n, --name=FILE # 查询的设备节点或符号链接的名称(/dev)
#e.g. [/dev]/sda. This option is an alternative to the positional argument with a /dev/ prefix.
udevadm info --name=sda is equivalent to udevadm info /dev/sda.
-r, --root
Print absolute paths in name or symlink query.
-a, --attribute-walk
Print all sysfs properties of the specified device that can be used in udev rules to match the specified device. It prints all devices along the
chain, up to the root of sysfs that can be used in udev rules.
-x, --export
Print output as key/value pairs. Values are enclosed in single quotes. This takes effects only when --query=property or --device-id-of-file=FILE is specified.
-P, --export-prefix=NAME
Add a prefix to the key name of exported values. This implies --export.
-d, --device-id-of-file=FILE
Print major/minor numbers of the underlying device, where the file lives on. If this is specified, all positional arguments are ignored.
-e, --export-db
Export the content of the udev database.
-e, --export-db
Export the content of the udev database.
-c, --cleanup-db
Cleanup the udev database.
-w[SECONDS], --wait-for-initialization[=SECONDS]
Wait for device to be initialized. If argument SECONDS is not specified, the default is to wait forever.
trigger: 主要是用于在系统冷插拔时重放事件。
-v, --verbose
Print the list of devices which will be triggered.
-n, --dry-run
Do not actually trigger the event.
-t, --type=TYPE
Trigger a specific type of devices. Valid types are: devices, subsystems. The default value is devices.
-c, --action=ACTION
Type of event to be triggered. Possible actions are "add", "remove", "change", "move", "online", "offline", "bind", and "unbind". Also, the special
value "help" can be used to list the possible actions. The default value is "change".
-s, --subsystem-match=SUBSYSTEM
Trigger events for devices which belong to a matching subsystem. This option supports shell style pattern matching. When this option is specified
more than once, then each matching result is ORed, that is, all the devices in each subsystem are triggered.
-S, --subsystem-nomatch=SUBSYSTEM
Do not trigger events for devices which belong to a matching subsystem. This option supports shell style pattern matching. When this option is
specified more than once, then each matching result is ANDed, that is, devices which do not match all specified subsystems are triggered.
-a, --attr-match=ATTRIBUTE=VALUE
Trigger events for devices with a matching sysfs attribute. If a value is specified along with the attribute name, the content of the attribute is
matched against the given value using shell style pattern matching. If no value is specified, the existence of the sysfs attribute is checked. When
this option is specified multiple times, then each matching result is ANDed, that is, only devices which have all specified attributes are
triggered.
-A, --attr-nomatch=ATTRIBUTE=VALUE
Do not trigger events for devices with a matching sysfs attribute. If a value is specified along with the attribute name, the content of the
attribute is matched against the given value using shell style pattern matching. If no value is specified, the existence of the sysfs attribute is
checked. When this option is specified multiple times, then each matching result is ANDed, that is, only devices which have none of the specified
attributes are triggered.
-g, --tag-match=PROPERTY
Trigger events for devices with a matching tag. When this option is specified multiple times, then each matching result is ANDed, that is, devices
which have all specified tags are triggered.
-y, --sysname-match=NAME
Trigger events for devices for which the last component (i.e. the filename) of the /sys path matches the specified PATH. This option supports shell
style pattern matching. When this option is specified more than once, then each matching result is ORed, that is, all devices which have any of the
specified NAME are triggered.
--name-match=NAME
Trigger events for devices with a matching device path. When this option is specified more than once, then each matching result is ORed, that is,
all specified devices are triggered.
-b, --parent-match=SYSPATH
Trigger events for all children of a given device. When this option is specified more than once, then each matching result is ORed, that is, all
children of each specified device are triggered.
-w, --settle
Apart from triggering events, also waits for those events to finish. Note that this is different from calling udevadm settle. udevadm settle waits
for all events to finish. This option only waits for events triggered by the same command to finish.
--wait-daemon[=SECONDS]
Before triggering uevents, wait for systemd-udevd daemon to be initialized. Optionally takes timeout value. Default timeout is 5 seconds. This is
equivalent to invoke invoking udevadm control --ping before udevadm trigger.
settle : 监视udev事件队列,如果所有当前事件都被处理,则退出。
-t, --timeout=SECONDS
Maximum number of seconds to wait for the event queue to become empty. The default value is 120 seconds. A value of 0 will check if the queue is
empty and always return immediately.
-E, --exit-if-exists=FILE
Stop waiting if file exists.
control: 修改正在运行的udev守护进程的内部状态。
-e, --exit
Signal and wait for systemd-udevd to exit. No option except for --timeout can be specified after this option. Note that systemd-udevd.service
contains Restart=always and so as a result, this option restarts systemd-udevd. If you want to stop systemd-udevd.service, please use the following:
systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service
-l, --log-priority=value
Set the internal log level of systemd-udevd. Valid values are the numerical syslog priorities or their textual representations: emerg, alert, crit,
err, warning, notice, info, and debug.
-s, --stop-exec-queue
Signal systemd-udevd to stop executing new events. Incoming events will be queued.
-S, --start-exec-queue
Signal systemd-udevd to enable the execution of events.
-R, --reload
Signal systemd-udevd to reload the rules files and other databases like the kernel module index. Reloading rules and databases does not apply any
changes to already existing devices; the new configuration will only be applied to new events.
-p, --property=KEY=value
Set a global property for all events.
-m, --children-max=value
Set the maximum number of events, systemd-udevd will handle at the same time.
--ping
Send a ping message to systemd-udevd and wait for the reply. This may be useful to check that systemd-udevd daemon is running.
-t, --timeout=seconds
The maximum number of seconds to wait for a reply from systemd-udevd.
monitor : 侦听内核uevents和udev规则发送的事件,并将事件的devpath打印到控制台。它可以用来分析事件计时,通过比较内核uevent和udev事件的时间戳。
-k, --kernel
Print the kernel uevents.
-u, --udev
Print the udev event after the rule processing.
-p, --property
Also print the properties of the event.
-s, --subsystem-match=string[/string]
Filter kernel uevents and udev events by subsystem[/devtype]. Only events with a matching subsystem value will pass. When this option is specified
more than once, then each matching result is ORed, that is, all devices in the specified subsystems are monitored.
-t, --tag-match=string
Filter udev events by tag. Only udev events with a given tag attached will pass. When this option is specified more than once, then each matching
result is ORed, that is, devices which have one of the specified tags are monitored.
test :针对一个设备,在不需要 uevent 触发的情况下模拟一次 udev的运行,并输出查询规则文件的过程、所执行的行为、规则文件的执行结果。
-a, --action=ACTION
Type of event to be simulated. Possible actions are "add", "remove", "change", "move", "online", "offline", "bind", and "unbind". Also, the special value "help" can be used to list the possible actions. The default
value is "add".
-N, --resolve-names=early|late|never
Specify when udevadm should resolve names of users and groups. When set to early (the default), names will be resolved when the rules are parsed. When set to late, names will be resolved for every event. When set to
never, names will never be resolved and all devices will be owned by root.
test-builtin : 为设备DEVPATH运行内置的命令命令,并打印调试输出。
简单实例: monitor 子命令
# 实例1.UDEV事件监控实时监控内核所处理的事件,比如添加/移除一块设备会提示相对应的信息
udevadm monitor -u # 在规则处理之后打印udev事件。
udevadm monitor --property # 还要打印事件的属性。
udevadm monitor -k # 内核 uevent 事件信息查看
info 子命令
# 实例2.查看磁盘设备在内核中的属性(替代udevinfo命令)
$udevadm info -a -p /sys/block/sda
# looking at device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0/1:0:0:0/block/sda':
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0/1:0:0:0':
# KERNELS=="1:0:0:0"
# SUBSYSTEMS=="scsi"
# DRIVERS=="sd"
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0':
# KERNELS=="target1:0:0"
# SUBSYSTEMS=="scsi"
# DRIVERS==""
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1':
# KERNELS=="host1"
# SUBSYSTEMS=="scsi"
# DRIVERS==""
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0':
# KERNELS=="0000:03:00.0"
# SUBSYSTEMS=="pci"
# DRIVERS=="vmw_pvscsi"
# looking at parent device '/devices/pci0000:00/0000:00:15.0':
# KERNELS=="0000:00:15.0"
# SUBSYSTEMS=="pci"
# DRIVERS=="pcieport"
# looking at parent device '/devices/pci0000:00':
# KERNELS=="pci0000:00"
# SUBSYSTEMS==""
# DRIVERS==""
# 实例3.为已经存在的设备节点编写规则可以直接使用以下属性
$udevadm info -n /dev/sda
# P: /devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
# N: sda
# L: 0
# S: disk/by-path/pci-0000:00:10.0-scsi-0:0:0:0
# E: DEVPATH=/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
# E: DEVNAME=/dev/sda
# E: DEVTYPE=disk
# E: MAJOR=8
# E: MINOR=0
# E: SUBSYSTEM=block
# E: USEC_INITIALIZED=2120529
# E: SCSI_TPGS=0
# E: SCSI_TYPE=disk
# E: SCSI_VENDOR=VMware
# E: SCSI_VENDOR_ENC=VMware\x20\x20
# E: SCSI_MODEL=Virtual_disk
# E: SCSI_MODEL_ENC=Virtual\x20disk\x20\x20\x20\x20
# E: SCSI_REVISION=1.0
# E: ID_SCSI=1
# E: ID_VENDOR=VMware
# E: ID_VENDOR_ENC=VMware\x20\x20
# E: ID_MODEL=Virtual_disk
# E: ID_MODEL_ENC=Virtual\x20disk\x20\x20\x20\x20
# E: ID_REVISION=1.0
# E: ID_TYPE=disk
# E: MPATH_SBIN_PATH=/sbin
# E: ID_BUS=scsi
# E: ID_PATH=pci-0000:00:10.0-scsi-0:0:0:0
# E: ID_PATH_TAG=pci-0000_00_10_0-scsi-0_0_0_0
# E: ID_PART_TABLE_UUID=36f4f6a3-6312-408e-8497-a333afa589f7
# E: ID_PART_TABLE_TYPE=gpt
# E: DEVLINKS=/dev/disk/by-path/pci-0000:00:10.0-scsi-0:0:0:0
# E: TAGS=:systemd:
$udevadm info -q path -n /dev/sda
/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
$udevadm info -a -p $(udevadm info -q path -n /dev/sda) # 效果同2
control 子命令
# 判断守护进程是否在线
sudo udevadm control --ping
test 子命令 描述:通常使用来调试规则文件;
# 1.由于 udevtest是扫描所有的规则文件 ( 包括系统自带的规则文件 ),所以会产生冗长的输出。为了让读者清楚地了解 udevtest,本例只在规则目录里保留一条规则:
$ vim /etc/udev/rules.d/99-test.rules
KERNEL=="sd*", PROGRAM="/lib/udev/scsi_id -g -s %p", RESULT=="35000c50000a7ef67", \
NAME="root_disk%n", SYMLINK="symlink_root_disk%n"
# 从 test 的执行过程可以看出,test对 sda 执行了外部命令 scsi_id, 得到的 stdout 和规则文件里的 RESULT 匹配,所以该规则匹配。然后 ( 模拟 ) 产生设备文件 /dev/root_disk和符号链接 /dev/symlink_root_disk,并为其设定权限。
$ udevadm test /block/sda
# main: looking at device '/block/sda' from subsystem 'block'
# run_program: '/lib/udev/scsi_id -g -s /block/sda'
# run_program: '/lib/udev/scsi_id' (stdout) '35000c50000a7ef67'
# run_program: '/lib/udev/scsi_id' returned with status 0
# udev_rules_get_name: reset symlink list
# udev_rules_get_name: add symlink 'symlink_root_disk'
# udev_rules_get_name: rule applied, 'sda' becomes 'root_disk'
# udev_device_event: device '/block/sda' already in database, \
# validate currently present symlinks
# udev_node_add: creating device node '/dev/root_disk', major = '8', \
# minor = '0', mode = '0660', uid = '0', gid = '0'
# udev_node_add: creating symlink '/dev/symlink_root_disk' to 'root_disk'
描述:该命令用来构建udev规则的最直接方便的工具,现已经被系统整合进入udevadm形成了子命令,但是对于一些老系统仍然存在以下命令;
基础示例:
$udevinfo -a -p /sys/block/sda
looking at device '/block/sda':
KERNEL=="sda"
SUBSYSTEM=="block"
ATTR{stat}==" 128535 2246 2788977 766188 73998 317300 3132216 5735004 0 516516 6503316"
ATTR{size}=="234441648"
ATTR{removable}=="0"
ATTR{range}=="16"
ATTR{dev}=="8:0"
looking at parent device '/devices/pci0000:00/0000:00:07.0/host0/target0:0:0/0:0:0:0':
KERNELS=="0:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{ioerr_cnt}=="0x0"
ATTRS{iodone_cnt}=="0x31737"
ATTRS{iorequest_cnt}=="0x31737"
ATTRS{iocounterbits}=="32"
ATTRS{timeout}=="30"
ATTRS{state}=="running"
ATTRS{rev}=="3.42"
ATTRS{model}=="ST3120827AS "
ATTRS{vendor}=="ATA "
ATTRS{scsi_level}=="6"
ATTRS{type}=="0"
ATTRS{queue_type}=="none"
ATTRS{queue_depth}=="1"
ATTRS{device_blocked}=="0"
looking at parent device '/devices/pci0000:00/0000:00:07.0':
KERNELS=="0000:00:07.0"
SUBSYSTEMS=="pci"
DRIVERS=="sata_nv"
ATTRS{vendor}=="0x10de"
ATTRS{device}=="0x037f"
# 使用udevinfo来为你查找设备路径对于已经存在的设备节点编写规则
udevinfo -a -p $(udevinfo -q path -n /dev/sda)
Tips:可依据其编写udev规则及其注意点
# 1.udevinfo 只生成一个属性列表,您可以在udev规则中作为匹配键使用。
SUBSYSTEM=="block", ATTR{size}=="234441648", NAME="my_hard_disk"
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", ATTRS{model}=="ST3120827AS", NAME="my_hard_disk"
# 2.以下规则无效因为它试图匹配来自两个父设备的属性(不能进行设备关联匹配):
SUBSYSTEM=="block", ATTRS{model}=="ST3120827AS", DRIVERS=="sata_nv", NAME="my_hard_disk"
描述: udev 是高效的设备管理工具,其最大的优势是动态管理设备和自定义设备的命名规则,因此替代 devfs 成为 Linux 默认的设备管理工具。
上文主要描述了Linux 用户能够了解到 udev 的工作原理和流程,灵活地运用 udev 规则文件,从而方便地管理 Linux 设备文件。
在udev规则中可以规定了系统所有设备绑定的条件当匹配则按照就规则创建符号链接, 在日常使用并不要您全部进行绑定而是按照需求绑定即可;
参考连接