linux热插拔
来源:互联网 发布:html中js用函数传值 编辑:程序博客网 时间:2024/05/01 00:03
当用户向系统添加或删除设备时,内核会产生一个热插拔事件,并在/proc/sys/kernel/hotplug文件里查找处理设备连接的用户空间程序,这个用户空间程序主要有/sbin/hotplug与/sbin/mdev.
echo /sbin/hotplug > /proc/sys/kernel/hotplug
或者
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
hotplug
是一个bash脚本具有如下类似的代码:
DIR="/etc/hotplug.d"for I in "${DIR}/$1"*.hotplug "${DIR}/"default/*.hotplug ; do if [-f $I]; then test -x $I && $I $1; fidoneexit 1
1) 当driver执行kobject_uevent会调用hotplughelper,从而调用这个/sbin/hotplug脚本。
2) 该脚本在/etc/hotplug.d目录搜索所有以hotplug为后缀的程序并调用,
3) 传递给被调用的程序的参数就是事件的名字,
4) 被调用的程序还可以读取大量的环境变量,包括ACTION、DEVPATH、SUBSYSTEM等。
5) 被调用的程序根据这些环境变量在/lib/module/KERNEL_VERSION/modules.*map文件找到对应需要加载的模块并加载。
(*.map是当驱动程序使用MODULE_DEVICE_TABLE宏时,depmod程序使用这些信息并创建了/lib/module/KERNEL_VERSION/modules.*map文件。)
udev/mdev/vold
为用户空间提供使用固定设备名的动态/dev目录的解决办法。
mdev是简化的udev,是busybox所带的程序,适合嵌入式系统的使用。/sbin/mdev是一个链接,指向/bin/busybox
android系统中的vold机制与udev一样,android的源码NetlinkManager.cpp同样是监听基于netlink的套接字,并解析接收到的消息。
udev创建每个设备的名字和权限由/etc/udev/rules.d目录下的文件指定规则来设置,如果udev找不到所创建设备的权限文件,就将其缺省的权限设置为660,所有者root:root
热插拔设备
由于启动的时候运行了命令: echo /sbin/mdev > /proc/sys/kernel/hotplug,那么当有热插拔事件产生时,/sbin/mdev就会被调用,mdev根据环境变量中的ACTION和DEVPATH来确定此次热插拔事件的动作以及影响了/sys中的哪个目录,接着查看这个目录中是否有dev文件,如果有,就用这些信息在/dev目录下创建设备节点文件。
冷插拔设备
冷插拔的设备在开机时就存在,在udev启动前已经被插入了,对于冷插拔的设备,linux内核提供了sysfs下面的一个uevent节点,可以往该节点写入一个add,导致内核重新发送netlink,之后udev就可以收到冷插拔的netlink的消息了。
mdev -s
在/sys/class和/sys/block目录树中查找一个称为dev的文件,根据dev文件中记录的设备节点的主次设备号,从而在/dev目录下创建相应的设备节点。
/sys/bus/和/sys/class目录下的devices、drivers都是对/sys/devices目录下的文件的符号连接。
解决使用mdev时“cannot create /proc/sys/kernel/hotplug:nonexistent directory”错误
确保编译内核时编译如下选项:
CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
CONFIG_HOTPLUG=y
CONFIG_NET=y
如果CONFIG_HOTPLUG和CONFIG_NET不选或没全选上的话,/proc/sys/kernel下将不会创建hotplug文件.(参见kernel/sysctl.c)
原理
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)int device_register(struct device *dev) device_initialize(dev) device_add(dev) kobject_add(&dev->kobj, dev->kobj.parent, NULL); kobject_uevent(&dev->kobj, KOBJ_ADD);
上面device_create和device_register都可以用来添加struct device,其实在device_create中就是调用的device_register。
在kobject_uevent中既可以通过netlink向用户空间程序udevd发送uevent事件,也可以直接调用用户空间程序hotplug_helper
需要注意的是,
如果在device_add中dev_t = 0,则最后udevd不会在/dev目录下创建相应的设备节点
如果在device_add中dev_t != 0,则mdev或者hotplug根据dev中的内容(major:minor)来生成设备节点。
device_add是在/sys/devices/目录下添加设备,/sys/bus/和/sys/class目录下的devices、drivers都是对/sys/devices目录下的文件的符号连接。
Udev完全工作在用户态,利用设备加入或者移除时内核所发送的热插拔事件来工作
在热插拔的时候,设备的详细信息会由内核通过netlink套接字发送出来,发出来的事情叫做的uevent,udev的命名策略、权限控制和事件处理都是在用户态下完成的,他利用从内核收到的信息来创建设备文件节点等工作。
下面这段程序就是用来接收内核netlink发出来的信息,将设备插到系统中会打印从内核中接收到的信息。
Udev就是用这种方式接收netlink的消息,并根据他的内容和用户设置的udev的规则做匹配来进行工作的。
#include <linux/netlink.h>Static void die(char *s){ Write(2, s, strlen(s)); Exit(1);}Int main(int argc, char *argv[]){ Struct sockaddr_nl nls; Struct pollfd pfd; Char buf[512]; //open hotplug event netlilnk socket Memset(nls, 0, sizeof(struct sockaddr_nl)); Nls.nl_family = AF_NETLINK; Nls.nl_pid = getpid(); Nls.nl_group = -1; Pfd.event = POLLIN; Pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); If (pfd. Fd == -1) Die(“no root\n”); //listen to netlink socket If (bind(pfd.fd, (void *)&nls, sizeof(struct sockaddr_nl)); Die(“bind failed\n”); While(-1 != poll(&pfd, 1, -1)) { Int i, len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT); If (len == -1) Die(“recv\n”); I = 0; //print the data to stdout While(i < len) { Printf(“%s\n”, buf + i); I = i + strlen(buf + i) + 1 } } Die(“poll\n”); Return 0;}
可以借助udev的工具udevadm info查找规则文件所能利用的内核信息和sysfs属性信息,
如运行”udevadm info -a -p /sys/devices/platform/serial8250/tty/ttyS0”
如果/dev目录下的节点已经被创建,但是不知道他对应的/sys/具体节点路径,
Udevadm info -q path -n /dev/节点名
参考文章:
1. Linux设备模型(热插拔、mdev 与 firmware)
2. mdev hotplug设备
3. Linux设备模型、sysfs文件系统与udev设备文件
- Linux热插拔
- Linux 热插拔
- Linux热插拔
- Linux热插拔
- linux 热插拔
- linux热插拔
- linux热插拔
- [转载]Linux热插拔
- Linux热插拔处理机制
- Linux热插拔处理机制
- Linux 接收热插拔事件
- Linux热插拔处理机制
- linux scsi硬盘热插拔
- Linux 热插拔事件
- linux
- linux
- Linux
- Linux
- hdu5115Dire Wolf 区间dp
- 【codevs1425】最小的N个和,如何像煞笔一样地写堆
- LVS工作原理
- win8+VS2008"fatal error LNK1181: 无法打开输入文件“GxIAPI.lib"
- hdu 3501
- linux热插拔
- 【Java基础】--J2SE深度总结
- 带条件查询离当前时间最近的一条记录
- Codeforces Round #321 (Div. 2)B. Kefa and Company
- Android开机启动扫描SD卡apk流程
- Investigating Your RAM Usage(一)
- UVA592字符串推断题加暴力假设搜索
- 构建二叉树、二叉树的深度、广度优先遍历
- WEB 容器、WEB服务和应用服务器的区别与联系