Skip to the content.

udev 机制

使用的经典案例

网卡重命名

for r in `rpm -qa |grep mlnx`;do rpm -ql $r |grep udev ;done

/lib/udev/mlnx_bf_udev
/lib/udev/auxdev-sf-netdev-rename
/lib/udev/rules.d/83-mlnx-sf-name.rules
/lib/udev/rules.d/90-ib.rules
/lib/udev/sf-rep-netdev-rename
/usr/lib/udev/rdma_rename
/usr/lib/udev/rules.d
/usr/lib/udev/rules.d/60-rdma-ndd.rules
/usr/lib/udev/rules.d/60-rdma-persistent-naming.rules
/usr/lib/udev/rules.d/75-rdma-description.rules
/usr/lib/udev/rules.d/90-rdma-umad.rules
/usr/share/doc/rdma-core/udev.md

中可以找到类似这样的写法:

ACTION=="add", SUBSYSTEM=="infiniband", PROGRAM="rdma_rename %k NAME_GUID"

权限修改

例如将 /dev/kvm 放到 kvm group 中去

kernel module 自动添加

原因在 /usr/lib/udev/rules.d/80-drivers.rules 中的这个通用规则中:

ENV{MODALIAS}=="?*", RUN{builtin}+="kmod load"

当系统检测到一个新设备,且该设备携带了非空的 MODALIAS 时,udev 会自动执行:

  kmod load

kmod 会拿这个 MODALIAS 去 /lib/modules/$(uname -r)/modules.alias 里查找匹配项,然后调用 modprobe 加载对应的驱动模块。

所以,我们再回到那个问题, kvm 为什么总是可以自动加载? 执行 modinfo kvm_intel 显然可以看到其 alias 关联的内容:

$ modinfo kvm_intel

filename:       /lib/modules/7.0.8-200.fc44.x86_64/kernel/arch/x86/kvm/kvm-intel.ko.xz
license:        GPL
description:    KVM support for VMX (Intel VT-x) extensions
author:         Qumranet
alias:          cpu:type:x86,ven*fam*mod*:feature:*0085*
depends:        kvm

同时,是可以观察一个设备的 alias 的:

find /sys -name "modalias"

/dev 目录的构建

udev 会监控盘的读写

这个问题比较细节:

打开关闭 /dev/sda (HDD 盘) 的操作都会让 udevd 来进行 重新获取 disk capacity 。

为什么要做这个机制: 如果盘是有问题的,那么 udev 会来 这里的 blk_execute_rq 会执行失败,它会将盘的容量设置为 0 。接下来,所有的 process 都可以 open ,但是 write 立刻触发容量为 0 的错误并且导致 disk 关闭

实现原理:

  1. 通过 inotify 来监听文件是否被打开

通过打开额外的日志来验证

sudo udevadm control --log-level=debug
sudo journalctl -u systemd-udevd -f
Jun 06 10:44:25 localhost.localdomain systemd-udevd[1159]: sda: Received inotify event of watch handle 154.
Jun 06 10:44:25 localhost.localdomain systemd-udevd[1159]: Successfully forked off '(udev-synth)' as PID 1023046.
  1. 触发 uevent + netlink 机制的 ```txt
    • sudo bpftrace -e ‘kprobe:netlink_broadcast { @[curtask->comm] = count() } interval:s:1000 { exit(); }’ @[udev-synth]: 16

sudo bpftrace -e ‘kprobe:netlink_broadcast { @[kstack(bpftrace)] = count(); } interval:s:1000 { exit(); }’ @[ netlink_broadcast+5 kobject_uevent_net_broadcast+191 kobject_uevent_env+906 kobject_synth_uevent+316 uevent_store+32 kernfs_fop_write_iter+369 vfs_write+641 ksys_write+123 do_syscall_64+265 entry_SYSCALL_64_after_hwframe+118 ]: 14


3. 执行容量检测
```txt
[<0>] blk_execute_rq+0x147/0x220
[<0>] scsi_execute_cmd+0x15c/0x2d0
[<0>] read_capacity_10+0x104/0x230
[<0>] sd_revalidate_disk.isra.0+0x1441/0x2860
[<0>] sd_open+0x13d/0x1d0
[<0>] blkdev_get_whole+0x23/0x90
[<0>] blkdev_get_by_dev.part.0+0x174/0x320
[<0>] disk_scan_partitions+0x69/0xe0
[<0>] blkdev_ioctl+0x10a/0x270
[<0>] __x64_sys_ioctl+0x94/0xd0
[<0>] do_syscall_64+0x3b/0x90
[<0>] entry_SYSCALL_64_after_hwframe+0x6e/0xd8

也就是:

进程打开 /dev/sda 然后关闭
           |
           v
   内核 inotify 子系统检测到 CLOSE
           |
           v
   systemd-udevd 读取 inotify 事件(read fd)
           |
           v
   systemd-udevd fork 出 udev-synth
           |
           v
   udev-synth 写 /sys/.../sda/uevent (change)
           |
           v
   内核广播 uevent
           |
           v
   udev-worker 处理规则 -> 调用 scsi_id/blkid -> blk_execute_rq

参考文档

其他问题

https://wiki.archlinux.org/title/Modalias

👷 devtmpfs 的作用

derivers/base/devtmpfs.c

devtmpfs on /dev type devtmpfs (rw,nosuid,size=65474912k,nr_inodes=16368728,mode=755,inode64)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,inode64,usrquota)

devtmpfs_create_node 是什么时候调用

经典命令

  1. udevadm monitor –property
  2. udevadm test /dev/kvm
  3. udevadm info 查询 udev 数据库和 sysfs 中的设备信息
  4. udevadm control –reload-rules

测试实验

sudo modprobe dummy sudo modprobe -r dummy

sudo bpftrace -e 'kprobe:netlink_broadcast { @[kstack(bpftrace)] = count(); } interval:s:1000 { exit(); }'
@[
        netlink_broadcast+5
        kobject_uevent_net_broadcast+191
        kobject_uevent_env+906
        do_init_module+188
        init_module_from_file+200
        idempotent_init_module+574
        __x64_sys_finit_module+127
        do_syscall_64+265
        entry_SYSCALL_64_after_hwframe+118
]: 8
@[
        netlink_broadcast+5
        kobject_uevent_net_broadcast+191
        kobject_uevent_env+906
        __kobject_del+96
        kobject_cleanup+177
        mod_sysfs_teardown+375
        free_module+27
        __do_sys_delete_module.isra.0+672
        do_syscall_64+265
        entry_SYSCALL_64_after_hwframe+118
]: 8
udevadm monitor --property
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[832099.357555] add      /module/dummy (module)
ACTION=add
DEVPATH=/module/dummy
SUBSYSTEM=module
SEQNUM=69035

UDEV  [832099.360212] add      /module/dummy (module)
ACTION=add
DEVPATH=/module/dummy
SUBSYSTEM=module
SEQNUM=69035
USEC_INITIALIZED=832099357572

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。