Linux 設(shè)備模型之 Uevent

前言

此文始于 2019-04-02,這是在簡(jiǎn)書的第一篇文章,目的是為了練習(xí) markdown語(yǔ)法。先選擇一篇文章進(jìn)行 copy to write,結(jié)合目前正在看的內(nèi)容 android ueventd,選一篇對(duì) uevent 的描述來(lái)進(jìn)行練習(xí)。

進(jìn)展

Linux 設(shè)備模型之 Uevent

1. Uevent的功能

uevent 是 Kobject 的一部分,用于在 Kobject 狀態(tài)發(fā)生改變時(shí),例如增加、移除等,通知用戶空間程序,用戶空間程序接收到這樣的時(shí)間后,會(huì)做出相應(yīng)的處理。該機(jī)制通常是用來(lái)支持熱插拔設(shè)備的,例如U盤插入后,USB相關(guān) 的驅(qū)動(dòng)軟件會(huì)動(dòng)態(tài)創(chuàng)建用于表示該 U盤的 device 結(jié)構(gòu)(相應(yīng)的也包括其中的 kobject),并告知用戶空間程序,為該 U盤動(dòng)態(tài)的創(chuàng)建/dev/目錄下的設(shè)備節(jié)點(diǎn),更進(jìn)一步,可以通知其他應(yīng)用程序,將該 U盤 mount 到系統(tǒng)中,從而動(dòng)態(tài)的支持該設(shè)備。

2. sysfs 概述

設(shè)備節(jié)點(diǎn)是為設(shè)備驅(qū)動(dòng)所創(chuàng)建的,而設(shè)備device和驅(qū)動(dòng)driver都是以鏈表的形式連接在總線bus上的,而設(shè)備——驅(qū)動(dòng)——總線的更上一層就是sysfs層。
sysfs是一個(gè)內(nèi)存文件系統(tǒng),它把連接在系統(tǒng)上的設(shè)備和總線組織成為一個(gè)分級(jí)的文件,用戶空間的程序同樣可以利用這些信息,以實(shí)現(xiàn)和內(nèi)核的交互。sysfs文件系統(tǒng)是當(dāng)前系統(tǒng)上實(shí)際設(shè)備樹的一個(gè)直觀反映,用mount命令查看可以得知其掛載在“/sys”下 sysfs on /sys type sysfs (rw,seclabel,relatime))。當(dāng)一個(gè)kobject被創(chuàng)建的時(shí)候,對(duì)應(yīng)的sys文件和目錄也就被創(chuàng)建了;其主要文件目錄如下:

  • /sys/block 存放塊設(shè)備,提供以設(shè)備名(如sda)到/sys/devices的符號(hào)鏈接
  • /sys/bus 按總線類型分類,在某個(gè)總線目錄之下可以找到連接該總線的設(shè)備的符號(hào)鏈接,指向/sys/devices。某個(gè)總線目錄之下的 drivers 目錄包含了該總線所需的所有驅(qū)動(dòng)的符號(hào)鏈接對(duì)應(yīng)kernel中的 struct bus_type
  • /sys/class 按設(shè)備功能分類,如輸入設(shè)備在 /sys/class/input 之下,圖形設(shè)備在 /sys/class/graphics 之下,是指向 /sys/devices 目錄下對(duì)應(yīng)設(shè)備的符號(hào)鏈接對(duì)應(yīng)kernel中的 struct class
  • /sys/dev 按設(shè)備驅(qū)動(dòng)程序分層(字符設(shè)備/塊設(shè)備),提供以major:minor為名到 /sys/devices 的符號(hào)鏈接對(duì)應(yīng)kernel中的 struct device_driver
  • /sys/devices 包含所有被發(fā)現(xiàn)的注冊(cè)在各種總線上的各種物理設(shè)備。
    所有的物理設(shè)備都按其在總線上的拓?fù)浣Y(jié)構(gòu)來(lái)顯示,除了 platform devices 和 system devices 。platform devices一般是掛在芯片內(nèi)部高速或者低速總線上的各種控制器和外設(shè),能被CPU直接尋址。system devices不是外設(shè),他是芯片內(nèi)部的核心結(jié)構(gòu),比如CPU,timer等,他們一般沒(méi)有相關(guān)的driver,但是會(huì)有一些體系結(jié)構(gòu)相關(guān)的代碼來(lái)配置他們對(duì)應(yīng)kernel中的 struct device
    上面展現(xiàn)了在sys目錄下總線,設(shè)備,驅(qū)動(dòng)和類所對(duì)應(yīng)的文件,而他們的區(qū)別為:
  • device用于描述各種設(shè)備,其保存了所有的設(shè)備信息
  • driver 用于驅(qū)動(dòng) device ,其保存了所有能夠被它所驅(qū)動(dòng)的設(shè)備鏈表。
  • bus 是連接 CPU 和 device 的橋梁,其保存了所有掛載在它上面的設(shè)備鏈表和驅(qū)動(dòng)這些設(shè)備的驅(qū)動(dòng)鏈表。
  • class 用于描述一類 device ,其保存了所有該類 device 的設(shè)備鏈表。

創(chuàng)建設(shè)備節(jié)點(diǎn)文件的過(guò)程

下圖描述了設(shè)備節(jié)點(diǎn)文件的創(chuàng)建過(guò)程:


創(chuàng)建設(shè)備節(jié)點(diǎn)文件的整個(gè)過(guò)程

由此可知,設(shè)備模型中任何設(shè)備有事件需要上報(bào)時(shí),會(huì)觸發(fā) uevent提供的接口,uevent模塊準(zhǔn)備好上報(bào)事件的格式后,可以通過(guò)兩個(gè)途徑上報(bào)到用戶空間:

  • 通過(guò) kmod 模塊,直接調(diào)動(dòng)用戶空間的可執(zhí)行文件
  • 通過(guò) netlink 通信機(jī)制,將事件從內(nèi)核空間傳遞給用戶空間
    PS: 目前多采用 netlink 通信機(jī)制,ueventd 也是采用 netlink機(jī)制創(chuàng)建 socket 與 kernel 進(jìn)行通信。
    netlink基本概念
    用戶空間程序接收到上報(bào)的uevent之后就可以根據(jù)其event類型進(jìn)行相應(yīng)操作了。

uevent的數(shù)據(jù)結(jié)構(gòu)描述

kobject.h定義了uevent相關(guān)的常量和數(shù)據(jù)結(jié)構(gòu),如下:

kernel/lib/kobject_uevent.c  
/* the strings here must match the enum in include/linux/kobject.h */  
static const char *kobject_actions[] = {  
    [KOBJ_ADD] =        "add",  
    [KOBJ_REMOVE] =     "remove",  
    [KOBJ_CHANGE] =     "change",  
    [KOBJ_MOVE] =       "move", //暫未看到ueventd有具體處理  
    [KOBJ_ONLINE] =     "online",  
    [KOBJ_OFFLINE] =    "offline",//暫未看到ueventd有具體處理  
};  
/* 
 * The actions here must match the index to the string array 
 * in lib/kobject_uevent.c 
 * 
 * Do not add new actions here without checking with the driver-core 
 * maintainers. Action strings are not meant to express subsystem 
 * or device specific properties. In most cases you want to send a 
 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event 
 * specific variables added to the event environment. 
 */  
kernel/include/linux/kobject.h  
 enum kobject_action {     
     KOBJ_ADD,
     KOBJ_REMOVE,      
     KOBJ_CHANGE, 
     KOBJ_MOVE,  
     KOBJ_ONLINE, 
     KOBJ_OFFLINE,  
     KOBJ_MAX   
 };  

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

  • ADD/REMOVE,Kobject(或上層數(shù)據(jù)結(jié)構(gòu))的添加/移除事件。
  • ONLINE/OFFLINE,Kobject(或上層數(shù)據(jù)結(jié)構(gòu))的上線/下線事件,其實(shí)是是否使能。
  • CHANGE,Kobject(或上層數(shù)據(jù)結(jié)構(gòu))的狀態(tài)或者內(nèi)容發(fā)生改變。
  • MOVE,Kobject(或上層數(shù)據(jù)結(jié)構(gòu))更改名稱或者更改Parent(意味著在sysfs中更改了目錄結(jié)構(gòu))。
  • CHANGE,如果設(shè)備驅(qū)動(dòng)需要上報(bào)的事件不再上面事件的范圍內(nèi),或者是自定義的事件,可以使用該event,并攜帶相應(yīng)的參數(shù)。

小結(jié)

以上就是 uevent 的基礎(chǔ)知識(shí),作為了解 ueventd 前的準(zhǔn)備。

期望

在后續(xù)日子可以完全使用 markdown 語(yǔ)言謄寫文檔

參考的文章

Linux設(shè)備模型之 Uevent

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容