Linux熱插拔及mdev機制

理解如下:

1、創建設備類,是為了讓mdev知道根據這些信息來創建設備節點,根據/sys來創建,所以從devfs開始,根文件系統就引入了一個/sys目錄,/sys/dev下面都是內核加載的驅動的主從設備號

2、class的初始化過程(在/sys/下創建class目錄):

\tstart_kernel() -> 
\trest_init() ->
\tkernel_init() ->
\tdo_basic_setup() ->
\tdriver_init() ->
\tclasses_init()
Linux熱插拔及mdev機制

3、所謂的uevent機制,就是由內核來啟動一個用戶進程

4、uevent通知機制:kobject_uevent() -> kobject_uevent_env()

4.1、得到kset->uevent_ops,通過filter判斷kset中的內核對象狀態改變是否需要通知到用戶層,返回0就不通知

4.2、如果內核對象狀態變化需要通知用戶層,分配環境變量空間env,並設置環境變量

4.3、內核來啟動一個用戶空間的程序,一般默認為這個屬性文件(/proc/sys/kernel/hotplug)指定的進程,如:/sbin/mdev

5、在x86系統下,用戶空間一般會有udevd這個守護進程一直監聽kobject_uevent通過netlink廣播的uevent數據包,來獲取內核的各種變化,可通過命令查看:ps -aux |grep udevd

6、調用通知用戶過程:

設備端:device_add() ->

\tkobject_uevent(&dev->kobj, KOBJ_ADD);

驅動端:driver_register() ->

\tbus_add_driver() -> 
\tkobject_uevent(&priv->kobj, KOBJ_ADD);

設備端卸載:

\tdevice_del() ->  

\tbus_remove_device() ->
\tbus_put() ->
\tkset_put() ->
\tkobject_put() ->
\tkobject_release() ->
\tkobject_cleanup() ->
\tkobject_uevent(kobj, KOBJ_REMOVE);
\tdevice_del() -> put_device() -> kobject_put() ......

驅動端卸載:

\tdriver_unregister() -> 
\tbus_remove_driver() -> kobject_put() ......
\tdriver_unregister() ->
\tbus_remove_driver() ->
\tbus_put() -> kset_put() -> kobject_put() ......

7、當內核對象kset改變時,內核會採用內核對象通知機制(kobject_uevent),通知用戶層,那麼用戶程序必須指定一個進程給/proc/sys/kernel/hotplug,比如/sbin/mdev

8、咱們也可以替換/sbin/mdev來觀察現象,但被替換的應用程序由於沒有任何描述符可用,所以需要自己打開標準輸入輸出,如:

\t fd = open("/dev/console",O_RDWR);
\t fd = open("/dev/console",O_RDWR);

替換方法:echo /mnt/t > /proc/sys/kernel/hotplug

9、可以通過熱插拔usb設備來觀察現象,也可以通過自己寫一個驅動程序,在驅動中調用kobject_uevent()向用戶發送消息,但自己來實現向用戶空間發送改變的狀態,通過屬性文件操作實現,那麼傭有屬性文件的kobject必須要隸屬於一個kset,即要有subsystem。

應用程序測試代碼(參考busybox中的mdev完成),如下:

#include // FILE
#include // O_RDWR
#include // getenv()
// debug:
// echo /mnt/t > /proc/sys/kernel/hotplug
// hotplug operation
int main(int argc, char *argv[])
{
int i;
int fd;
char *env[6];
char *pname[] = {"ACTION","DEVNAME","DEVPATH","SUBSYSTEM","FIRMWARE","SEQNUM"};
fd = open("/dev/console",O_RDWR);
fd = open("/dev/console",O_RDWR);
printf("\\n");
for(i=0;i<argc;i++)
printf("argv[%d] = %s\\n",i,argv[i]);
printf("\\n");

env[0] = getenv("ACTION");
env[1] = getenv("DEVNAME");
env[2] = getenv("DEVPATH");
env[3] = getenv("SUBSYSTEM");
env[4] = getenv("FIRMWARE");
env[5] = getenv("SEQNUM");
for(i=0;i<6;i++)
if(env[i] != NULL)
printf("%s = %s\\n",pname[i],env[i]);

close(0);
close(1);
return 0;
}

10、udev和mdev都有著相似的功能,即完成設備文件的動態創建,但實現機制略有不同,有時候也說成mdev是udev的嵌入式簡化版

11、兩者使是用uevent 機制處理熱插拔問題的用戶空間程序,uevent 是“user event”的簡稱,是一種內核向用戶空間發送信息的方式

12、udev 是基於netlink 機制的,它在系統啟動時運行了一個daemon (守護進程)程序udevd,通過監聽內核發送的uevent 來執行相應的熱拔插動作

13、mdev 是基於uevent_helper 機制的,它在系統啟動時修改了內核中的uevnet_helper 變量(通過寫/proc/sys/kernel/hotplug),這樣內核產生uevent 時會調用uevent_helper 所指的用戶級程序,也就是mdev,來執行相應的熱拔插動作,uevent_helper 的初始值在內核編譯時可配置:

\t -> Device Drivers 
\t -> Generic Driver Options
\t (/proc/sys/kernel/hotplug) path to uevent helper

14、udev 使用的netlink 機制在有大量uevent 的場合效率高,適合用在PC 機上;而mdev 使用的uevent_helper 機制實現簡單,適合用在嵌入式系統中


分享到:


相關文章: