linux热插拔
當用戶向系統添加或刪除設備時,內核會產生一個熱插拔事件,并在/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 ; doif [-f $I]; thentest -x $I && $I $1;fi done exit 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 socketMemset(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 socketIf (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 stdoutWhile(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設備文件
轉自:?http://blog.csdn.net/luckywang1103/article/details/48686181
總結
- 上一篇: Linux下实现USB口的热插拔
- 下一篇: Doc2Vec训练相似文章识别模型