日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux设备模型的主要功能,Linux设备模型(3)

發布時間:2024/9/27 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux设备模型的主要功能,Linux设备模型(3) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux設備模型(3)_Uevent

作者:蝸蝸 發布于:2014-3-10 20:39

分類:統一設備模型

1. Uevent的功能

Uevent是Kobject的一部分,用于在Kobject狀態發生改變時,例如增加、移除等,通知用戶空間程序。用戶空間程序收到這樣的事件后,會做相應的處理。

該機制通常是用來支持熱拔插設備的,例如U盤插入后,USB相關的驅動軟件會動態創建用于表示該U盤的device結構(相應的也包括其中的kobject),并告知用戶空間程序,為該U盤動態的創建/dev/目錄下的設備節點,更進一步,可以通知其它的應用程序,將該U盤設備mount到系統中,從而動態的支持該設備。

2. Uevent在kernel中的位置

下面圖片描述了Uevent模塊在內核中的位置:

由此可知,Uevent的機制是比較簡單的,設備模型中任何設備有事件需要上報時,會觸發Uevent提供的接口。Uevent模塊準備好上報事件的格式后,可以通過兩個途徑把事件上報到用戶空間:一種是通過kmod模塊,直接調用用戶空間的可執行文件;另一種是通過netlink通信機制,將事件從內核空間傳遞給用戶空間。

注1:有關kmod和netlink,會在其它文章中描述,因此本文就不再詳細說明了。

3. Uevent的內部邏輯解析

3.1 Source Code位置

Uevent的代碼比較簡單,主要涉及kobject.h和kobject_uevent.c兩個文件,如下:

include/linux/kobject.h

lib/kobject_uevent.c

3.2 數據結構描述

kobject.h定義了uevent相關的常量和數據結構,如下:

kobject_action

1: /* include/linux/kobject.h, line 50 */

2: enum kobject_action {

3: ????KOBJ_ADD,

4: ????KOBJ_REMOVE,

5: ????KOBJ_CHANGE,

6: ????KOBJ_MOVE,

7: ????KOBJ_ONLINE,

8: ????KOBJ_OFFLINE,

9: ????KOBJ_MAX

10: };

kobject_action定義了event的類型,包括:

ADD/REMOVE,Kobject(或上層數據結構)的添加/移除事件。

ONLINE/OFFLINE,Kobject(或上層數據結構)的上線/下線事件,其實是是否使能。

CHANGE,Kobject(或上層數據結構)的狀態或者內容發生改變。

MOVE,Kobject(或上層數據結構)更改名稱或者更改Parent(意味著在sysfs中更改了目錄結構)。

CHANGE,如果設備驅動需要上報的事件不再上面事件的范圍內,或者是自定義的事件,可以使用該event,并攜帶相應的參數。

kobj_uevent_env

1: /* include/linux/kobject.h, line 31 */

2: #define UEVENT_NUM_ENVP 32 /* number of env pointers */

3: #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */

4:

5: /* include/linux/kobject.h, line 116 */

6: struct kobj_uevent_env {

7: ????char *envp[UEVENT_NUM_ENVP];

8: ????int envp_idx;

9: ????char buf[UEVENT_BUFFER_SIZE];

10:int buflen;

11: };

前面有提到過,在利用Kmod向用戶空間上報event事件時,會直接執行用戶空間的可執行文件。而在Linux系統,可執行文件的執行,依賴于環境變量,因此kobj_uevent_env用于組織此次事件上報時的環境變量。

envp,指針數組,用于保存每個環境變量的地址,最多可支持的環境變量數量為UEVENT_NUM_ENVP。

envp_idx,用于訪問環境變量指針數組的index。

buf,保存環境變量的buffer,最大為UEVENT_BUFFER_SIZE。

buflen,訪問buf的變量。

kset_uevent_ops

1: /* include/linux/kobject.h, line 123 */

2: struct kset_uevent_ops {

3: ????int (* const filter)(struct kset *kset, struct kobject *kobj);

4: ????const char *(* const name)(struct kset *kset, struct kobject *kobj);

5: ????int (* const uevent)(struct kset *kset, struct kobject *kobj,

6: ????????????????????????struct kobj_uevent_env *env);

7: };

kset_uevent_ops是為kset量身訂做的一個數據結構,里面包含filter和uevent兩個回調函數,用處如下:

filter,當任何Kobject需要上報uevent時,它所屬的kset可以通過該接口過濾,阻止不希望上報的event,從而達到從整體上管理的目的。

name,該接口可以返回kset的名稱。如果一個kset沒有合法的名稱,則其下的所有Kobject將不允許上報uvent

uevent,當任何Kobject需要上報uevent時,它所屬的kset可以通過該接口統一為這些event添加環境變量。因為很多時候上報uevent時的環境變量都是相同的,因此可以由kset統一處理,就不需要讓每個Kobject獨自添加了。

3.3 內部動作

通過kobject.h,uevent模塊提供了如下的API(這些API的實現是在"lib/kobject_uevent.c”文件中):

1: /* include/linux/kobject.h, line 206 */

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

3: int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,

4: ????????????????????????char *envp[]);

5:

6: __printf(2, 3)

7: int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);

8:

9: int kobject_action_type(const char *buf, size_t count,

10: ????????????????????????enum kobject_action *type);

kobject_uevent_env,以envp為環境變量,上報一個指定action的uevent。環境變量的作用是為執行用戶空間程序指定運行環境。具體動作如下:

查找kobj本身或者其parent是否從屬于某個kset,如果不是,則報錯返回(注2:由此可以說明,如果一個kobject沒有加入kset,是不允許上報uevent的)

查看kobj->uevent_suppress是否設置,如果設置,則忽略所有的uevent上報并返回(注3:由此可知,可以通過Kobject的uevent_suppress標志,管控Kobject的uevent的上報)

如果所屬的kset有uevent_ops->filter函數,則調用該函數,過濾此次上報(注4:這佐證了3.2小節有關filter接口的說明,kset可以通過filter接口過濾不希望上報的event,從而達到整體的管理效果)

判斷所屬的kset是否有合法的名稱(稱作subsystem,和前期的內核版本有區別),否則不允許上報uevent

分配一個用于此次上報的、存儲環境變量的buffer(結果保存在env指針中),并獲得該Kobject在sysfs中路徑信息(用戶空間軟件需要依據該路徑信息在sysfs中訪問它)

調用add_uevent_var接口(下面會介紹),將Action、路徑信息、subsystem等信息,添加到env指針中

如果傳入的envp不空,則解析傳入的環境變量中,同樣調用add_uevent_var接口,添加到env指針中

如果所屬的kset存在uevent_ops->uevent接口,調用該接口,添加kset統一的環境變量到env指針

根據ACTION的類型,設置kobj->state_add_uevent_sent和kobj->state_remove_uevent_sent變量,以記錄正確的狀態

調用add_uevent_var接口,添加格式為"SEQNUM=%llu”的序列號

如果定義了"CONFIG_NET”,則使用netlink發送該uevent

以uevent_helper、subsystem以及添加了標準環境變量(HOME=/,PATH=/sbin:/bin:/usr/sbin:/usr/bin)的env指針為參數,調用kmod模塊提供的call_usermodehelper函數,上報uevent。

其中uevent_helper的內容是由內核配置項CONFIG_UEVENT_HELPER_PATH(位于./drivers/base/Kconfig)決定的(可參考lib/kobject_uevent.c, line 32),該配置項指定了一個用戶空間程序(或者腳本),用于解析上報的uevent,例如"/sbin/hotplug”。

call_usermodehelper的作用,就是fork一個進程,以uevent為參數,執行uevent_helper。

kobject_uevent,和kobject_uevent_env功能一樣,只是沒有指定任何的環境變量。

add_uevent_var,以格式化字符的形式(類似printf、printk等),將環境變量copy到env指針中。

kobject_action_type,將enum kobject_action類型的Action,轉換為字符串。

說明:怎么指定處理uevent的用戶空間程序(簡稱uevent helper)?

上面介紹kobject_uevent_env的內部動作時,有提到,Uevent模塊通過Kmod上報Uevent時,會通過call_usermodehelper函數,調用用戶空間的可執行文件(或者腳本,簡稱uevent helper )處理該event。而該uevent helper的路徑保存在uevent_helper數組中。

可以在編譯內核時,通過CONFIG_UEVENT_HELPER_PATH配置項,靜態指定uevent helper。但這種方式會為每個event fork一個進程,隨著內核支持的設備數量的增多,這種方式在系統啟動時將會是致命的(可以導致內存溢出等)。因此只有在早期的內核版本中會使用這種方式,現在內核不再推薦使用該方式。因此內核編譯時,需要把該配置項留空。

在系統啟動后,大部分的設備已經ready,可以根據需要,重新指定一個uevent helper,以便檢測系統運行過程中的熱拔插事件。這可以通過把helper的路徑寫入到"/sys/kernel/uevent_helper”文件中實現。實際上,內核通過sysfs文件系統的形式,將uevent_helper數組開放到用戶空間,供用戶空間程序修改訪問,具體可參考"./kernel/ksysfs.c”中相應的代碼,這里不再詳細描述。

原創文章,轉發請注明出處。蝸窩科技,www.wowotech.net。

評論:

2014-12-02 12:01

之前一直以為uevent_ops->uevent是完成具體的事件上報函數回調,誤解為就是wowo開始所說的uevent機制。看了這篇文章和代碼才知道這個callback的作用只是添加一個環境變量,名字比較迷惑人。

另外整個kernel中鮮有利用uevent的場景,所以uevent其實用處不大,更有用的是uevent_ops->filter回調。

說起環境變量上報,搞不清楚上報這些個環境變量的用處是什么,如果是上報Kobject在sysfs中路徑信息倒是好理解,至于環境變量,用戶空間處理程序(hotplug什么的)的執行需要上報的這些環境變量嗎?

wowo

2014-12-02 13:27

@puppypyb:其實環境變量是使用usermodehelper的方式處理uevent時才會需要,如果使用的netlink的話,確實不需要。

環境變量存在的本質,是因為exec系列的“文件執行”函數需要(這也是Linux下文件執行的基礎),這可以從do_execve(fs/exec.c)接口從看出:

int do_execve(const char *filename,

const char __user *const __user *__argv,

const char __user *const __user *__envp)

至于kernel中uevent用處,還真不好說。如果你需要一些例子的話,可以去看看Android的switch class(drivers/switch/)。

我的觀點是,如果軟件設計的足夠好,一定用不到uevent,poll機制足夠了。如果poll解決不了,則說明設計者根本不知道event要上報給誰,才使用uevent的方式隨便一扔,誰想收就收吧。

另外,無論是usermodehelper還是netlink的方式,uevent對系統性能是有影響的。特別是netlink的方式,上報的event會通知到所有的用戶進程,所以還是少用為妙。

2014-12-02 14:27

@wowo:understood, thanks~

2014-10-28 23:10

注1:有關kmod和netlink,會在其它文章中描述,因此本文就不再詳細說明了。

===>這兩個在哪講啊 啊?????

2014-10-28 23:17

@xxx:不好意思,還沒有來得及寫…

總結

以上是生活随笔為你收集整理的linux设备模型的主要功能,Linux设备模型(3)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。