linux下熱插拔事件的產生是怎樣通知到用戶空間,kobject_uevent_env之uevent【轉載】

1.kobject, ktype, kset

kobject表明sysfs中的目錄。shell

ktype表明kobject的類型,主要包含release函數和attr的讀寫函數。好比,全部的bus都有同一個bus_type;全部的class都有同一個class_type。函數

kset包含了subsystem概念,kset自己也是一個kobject,因此裏面包含了一個kobject對象。另外,kset中包含kset_uevent_ops,裏面主要定義了三個函數orm

       int (*filter)(struct kset *kset, struct kobject *kobj);對象

       const char *(*name)(struct kset *kset, struct kobject *kobj);事件

       int (*uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env);it

這三個函數都與uevent相關。filter用於判斷uevent是否要發出去。name用於獲得subsystem的名字。uevent用於填充env變量。io

2.uevent內核部分

uevent是sysfs向用戶空間發出的消息。好比,device_add函數中,會調用kobject_uevent(&dev->kobj, KOBJ_ADD); 這裏kobj是發消息的kobj,KOBJ_ADD是發出的事件。uevent的事件在kobject_action中定義:event

enum kobject_action {form

       KOBJ_ADD,class

       KOBJ_REMOVE,

       KOBJ_CHANGE,

       KOBJ_MOVE,

       KOBJ_ONLINE,

       KOBJ_OFFLINE,

       KOBJ_MAX

};

 

int kobject_uevent(struct kobject *kobj, enum kobject_action action)

{

       return kobject_uevent_env(kobj, action, NULL);

}

 

kobject_uevent_env:

       由kobject的parent向上查找,直到找到一個kobject包含kset。

       若是kset中有filter函數,調用filter函數,看看是否須要過濾uevent消息。

       若是kset中有name函數,調用name函數獲得subsystem的名字;不然,subsystem的名字是kset中kobject的名字。

       分配一個kobj_uevent_env,並開始填充env環境變量:

       增長環境變量ACTION=<action name>

       增長環境變量DEVPATH=<kobj’s path>

       增長環境變量SUBSYSTEM=<subsystem name>

       增長環境變量kobject_uevent_env中參數envp_ext指定的環境變量。

       調用kset的uevent函數,這個函數會繼續填充環境變量。

       增長環境變量SEQNUM=<seq>,這裏seq是靜態變量,每次累加。

       調用netlink發送uevent消息。

       調用uevent_helper,最終轉換成對用戶空間sbin/mdev的調用。

3.uevent用戶空間部分

uevent的用戶空間程序有兩個,一個是udev,一個是mdev。

udev經過netlink監聽uevent消息,它能完成兩個功能:

       1.自動加載模塊

       2.根據uevent消息在dev目錄下添加、刪除設備節點。

另外一個是mdev,mdev在busybox的代碼包中能找到,它經過上節提到的uevent_helper函數被調用。

 

下面簡要介紹udev的模塊自動加載過程:

etc目錄下有一個uevent規則文件/etc/udev/rules.d/50-udev.rules

udev程序收到uevent消息後,在這個規則文件裏匹配,若是匹配成功,則執行這個匹配定義的shell命令。例如,規則文件裏有這麼一行:

ACTION=="add", SUBSYSTEM=="?*", ENV{MODALIAS}=="?*", RUN+="/sbin/modprobe $env{MODALIAS}"

因此,當收到uevent的add事件後,shell能自動加載在MODALIAS中定義的模塊。

 

mdev的模塊自動加載過程與之相似,它的配置文件在/etc/mdev.conf中。例如:

$MODALIAS=.* 0:0 660 @modprobe "$MODALIAS"

這條規則指的是:當收到的環境變量中含有MODALIAS,那麼加載MODALIAS表明的模塊。

mdev的詳細說明在busybox的docs/mdev.txt中。

4.uevent在設備驅動模型中的應用

在sys目錄下有一個子目錄devices,表明一個kset。

建立設備時,調用的device_initialize函數中,默認會把kset設置成devices_kset,即devices子目錄表明的kset。

devices_kset中設置了uevent操做集device_uevent_ops。

static struct kset_uevent_ops device_uevent_ops = {

       .filter =    dev_uevent_filter,

       .name =   dev_uevent_name,

       .uevent = dev_uevent,

};

 

dev_uevent_filter中,主要是規定了要想發送uevent,dev必須有class或者bus。

dev_uevent_name中,返回dev的class或者bus的名字。

dev_uevent函數:

       若是dev有設備號,添加環境變量MAJOR與MINOR。

       若是dev->type有值,設置DEVTYPE=<dev->type->name>。

       若是dev->driver,設置DRIVER=<dev->driver->name>。

       若是有bus,調用bus的uevent函數。

       若是有class,調用class的uevent函數。

若是有dev->type,調用dev->type->uevent函數。

 

通常在bus的uevent函數中,都會添加MODALIAS環境變量,設置成dev的名字。這樣,uevent傳到用戶空間後,就能夠經過對MODALIAS的匹配自動加載模塊。這樣的bus例子有platform和I2C等等。

相關文章
相關標籤/搜索