前言
此文始于 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ò)程:

由此可知,設(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ǔ)言謄寫文檔