Linux內核熱拔插機制

在Linux2.6.30.4的內核中,註冊驅動時調用device_create,卸載驅動時調用
device_destory函數最終都將導致kobject_uevent_env函數被調用,該函數用於
通知用戶空間設備發送了動態變化

添加:
device_create(struct class *class, struct device *parent,
    dev_t devt, void *drvdata, const char *fmt, ...)
device_register(dev);
device_add(dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
kobject_uevent_env(kobj, action, NULL);



移除:
device_destroy(struct class *class, dev_t devt)
device_unregister(dev);
device_del(dev);
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_uevent_env(kobj, action, NULL);
mdev函數分析:(busybox:mdev.c)

uevent_helper = /sbin/mdev
env->envp[0] = ACTION=add
env->envp[1] = DEVPATH=/devices/virtual/misc/buttons
env->envp[2] = SUBSYSTEM=misc
env->envp[3] = MAJOR=10
env->envp[4] = MINOR=58
env->envp[5] = SEQNUM=410
env->envp[6] = HOME=/
env->envp[7] = PATH=/sbin:/bin:/usr/sbin:/usr/bin

action = getenv("ACTION"); // action = "add"
env_path = getenv("DEVPATH"); // env_path ="/devices/virtual/misc/buttons"
seq = getenv("SEQNUM"); // seq = "410" 
snprintf(temp, PATH_MAX, "/sys%s", env_path); // temp[] = "sys/devices/virtual/misc/buttons"
if (!strcmp(action, "remove"))
make_device(temp, 1);
else if (!strcmp(action, "add")) 
make_device(temp, 0);
add:
// 讀取主次設備號
len = open_read_close("sys/devices/virtual/misc/buttons/dev", dev_maj_min + 1, 64);
device_name = bb_basename(path);
type = S_IFCHR; // 判斷是字符設備還是塊設備
if (strstr("sys/devices/virtual/misc/buttons/", "/block/"))
type = S_IFBLK;
// 如果有"/etc/mdev.conf"文件將依據該文件創建設備文件
mknod(device_name, mode | type, makedev(major, minor))

使用mdev在初始化腳本中需要以下代碼片段:
[0] mount -t proc proc /proc
[1] mount -t sysfs sysfs /sys
[2] echo /bin/mdev > /proc/sys/kernel/hotplug
[3] mdev -s
或者不使用/proc文件系統:
[1] mount -t sysfs sysfs /sys
[2] sysctl -w kernel.hotplug=/bin/mdev
[3] mdev -s
完整的啓動腳本中還會有以下代碼片段:
[4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev
[5] mkdir /dev/pts
[6] mount -t devpts devpts /dev/pts

mdev.conf文件的編寫
mdev.conf是一個可選的配置文件,控制設備節點的所有權/權限,如果你的系統需要改變默認的root/root
660權限
文件的格式如下:
設備的正則表達式 用戶id  組id    八進制的權限
<device regex>       <uid> : <gid> <octal permissions>
示例:
hd[a-z][0-9]* 0:3 660
正則表達式:
*  : 重複0次或更多次
+  :重複1次或更多次
? :重複0次或1次
.  : 匹配換行符以外的任意字符
[] : 匹配裏面的某個字符

配置文件的解析將停止於第一個匹配的行,如果沒有一行可以匹配,將使用默認的0:0 660
你也可以重命名/移除設備節點通過以下可選的域:
設備的正則表達式 用戶id 組id 八進制的權限
<device regex>      <uid> : <gid>  <octal permissions> [=path]
如果你想將設備節點放置於某個子目錄中,確保路徑中含"/",如果你想給某個設備節點重命名
只需要放置名字。
hda 0:3 660 =drives/
這樣會將設備文件"hda"放置到drives/ 子目錄中
hdb 0:3 660 =cdrom
這樣會將"hdb"重命名爲"cdrom"
類似的,">path" 重命名/移除設備但還會創建一個符號鏈接從"/dev/DEVNAME"到重命名/移除的設備

可以支持運行自己編寫的命令,此時文件的格式如下:
<device regex>   <uid>:<gid> <octal permissions> [=path] [@|$|*<command>]
    或者
<device regex> <uid>:<gid> <octal permissions> [>path] [@|$|*<command>]
相關字符的意思:
@ 創建設備之後運行
$ 移除設備之前運行
* 在創建設備之後和移除設備之前都運行

命令是通過system()函數來執行(這意味着你應該給shell提供命令),所以你應該確保/bin/sh shell
已經安裝,當內核指向hotplug helpers時將stdin,stdout,stderr連接到/dev/null
使用環境變量$MDEV被設置成設備名。

掛載U盤的mdev.conf
sd[a-d]+[1-9]+ 0:0  660 * /bin/mount_udisk.sh
其中/bin/mount_udisk.sh的內容如下:
#!/bin/sh
if [ $ACTION = "add" ];
then
mount /dev/$MDEV /mnt/udisk;
else
umount /mnt/udisk;
fi

相關連接:
正則表達式 :http://deerchao.net/tutorials/regex/regex.htm
mdev的配置文檔: busyboxXXX/doc/mdev.txt
發佈了30 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章