14.2. 低級 sysfs 操作

2018-02-24 15:50 更新

14.2.?低級 sysfs 操作

kobject 是在 sysfs 虛擬文件系統(tǒng)之后的機制. 對每個在 sysfs 中發(fā)現(xiàn)的目錄, 有一個 kobject 潛伏在內(nèi)核某處. 每個感興趣的 kobject 也輸出一個或多個屬性, 它出現(xiàn)在 kobject 的 sysfs 目錄, 作為包含內(nèi)核產(chǎn)生的信息的文件. 本節(jié)檢查 kobject 和 sysfs 如何在低層交互.

使用 sysfs 的代碼應(yīng)當(dāng)包含 <linux/sysfs.h>.

使一個 kobject 在 sysfs 出現(xiàn)僅僅是調(diào)用 kobject_add 的事情. 我們已經(jīng)見到這個函數(shù)作為添加一個 kobject 到一個 kset 的方式; 在 sysfs 中創(chuàng)建入口也是它的工作的一部分. 有一些事情值得知道, 關(guān)于 sysfs 入口如何創(chuàng)建:

  • kobjects 的 sysfs 入口一直為目錄, 因此一個對 kobject_add 的調(diào)用導(dǎo)致在sysfs 中創(chuàng)建一個目錄. 常常地, 這個目錄包含一個或多個屬性; 我們稍后見到屬性如何指定.

  • 分配給 kobject 的名子( 用 kobject_set_name ) 是給 sysfs 目錄使用的名子. 因此, 出現(xiàn)在 sysfs 層次的相同部分的 kobjects 必須有獨特的名子. 分配給 kobjects 的名子也應(yīng)當(dāng)是合理的文件名子: 它們不能包含斜線字符, 并且空白的使用強烈不推薦.

  • sysfs 入口位于對應(yīng) kobject 的 parent 指針的目錄中. 如果 parent 是 NULL 當(dāng) kobject_add 被調(diào)用時, 它被設(shè)置為嵌在新 kobject 的 kset 中的 kobject; 因此, sysfs 層級常常匹配使用 kset 創(chuàng)建的內(nèi)部層次. 如果 parent 和 kset 都是 NULL, sysfs 目錄在頂級被創(chuàng)建, 這幾乎當(dāng)然不是你所要的.

使用我們至今所描述的, 我們可以使用一個 kobject 來在 sysfs 中創(chuàng)建一個空目錄. 常常地, 你想做比這更有趣的事情, 因此是時間看屬性的實現(xiàn).

14.2.1.?缺省屬性

當(dāng)被創(chuàng)建時, 每個 kobject 被給定一套缺省屬性. 這些屬性通過 kobj_type 結(jié)構(gòu)來指定. 這個結(jié)構(gòu), 記住, 看來如此:


struct kobj_type {
 void (*release)(struct kobject *);
 struct sysfs_ops *sysfs_ops;
 struct attribute **default_attrs; 
}; 

default_attr 成員列舉了對每個這樣類型的 kobject 被創(chuàng)建的屬性, 并且 sysfs_ops 提供方法來實現(xiàn)這些屬性. 我們從 default_attrs 開始, 它指向一個指向?qū)傩越Y(jié)構(gòu)的指針數(shù)組:


struct attribute {
 char *name;
 struct module *owner;
 mode_t mode; 
}; 

在這個結(jié)構(gòu)中, name 是屬性的名子( 如同它出現(xiàn)在 kobject 的 sysfs 目錄中), owner 是一個指向模塊的指針(如果有一個), 模塊負(fù)責(zé)這個屬性的實現(xiàn), 并且 mode 是應(yīng)用到這個屬性的保護(hù)位. mode 常常是 S_IRUGO 對于只讀屬性; 如果這個屬性是可寫的, 你可以扔出 S_IWUSR 來只給 root 寫權(quán)限( modes 的宏定義在 <linux/stat.h> 中). default_attrs 列表中的最后一個入口必須用 0 填充.

default_attr 數(shù)組說明這些屬性是什么, 但是沒有告訴 sysfs 如何真正實現(xiàn)這些屬性. 這個任務(wù)落到 kobj_type->sysfs_ops 成員, 它指向一個結(jié)構(gòu), 定義為:


struct sysfs_ops {
 ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buffer);
 ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
};

無論何時一個屬性從用戶空間讀取, show 方法被用一個指向 kobject 的指針和適當(dāng)?shù)膶傩越Y(jié)構(gòu)來調(diào)用. 這個方法應(yīng)當(dāng)將給定屬性值編碼進(jìn)緩沖, 要確定沒有覆蓋它( 它是 PAGE_SIZE 字節(jié)), 并且返回實際的被返回數(shù)據(jù)的長度. sysfs 的慣例表明每個屬性應(yīng)當(dāng)包含一個單個的, 人可讀的值; 如果你有許多消息返回, 你可要考慮將它分為多個屬性.

同樣的 show 方法用在所有的和給定 kobject 關(guān)聯(lián)的屬性. 傳遞到函數(shù)的 attr 指針可用來決定需要哪個屬性. 一些 show 方法包含對屬性名子的一系列測試. 其他的實現(xiàn)將屬性結(jié)構(gòu)嵌入另一個結(jié)構(gòu), 來包含需要返回屬性值的信息; 在這種情況下, container_of 可能用在 show 方法中來獲得一個指向嵌入結(jié)構(gòu)的指針.

store 方法類似; 它應(yīng)當(dāng)將存在緩沖的數(shù)據(jù)編碼( size 包含數(shù)據(jù)的長度, 這不能超過 PAGE_SIZE ), 存儲和以任何有意義的的方式響應(yīng)新數(shù)據(jù), 并且返回實際編碼的字節(jié)數(shù). store 方法只在屬性的許可允許寫才被調(diào)用. 當(dāng)編寫一個 store 方法時, 不要忘記你在接收來自用戶空間的任意信息; 你應(yīng)當(dāng)在采取對應(yīng)動作之前非常小心地驗證它. 如果到數(shù)據(jù)不匹配期望, 返回一個負(fù)的錯誤值, 而不是可能地做一些不想要的和無法恢復(fù)的事情. 如果你的設(shè)備輸出一個自銷毀的屬性, 你應(yīng)當(dāng)要求一個特定的字符串寫到那里來引發(fā)這個功能; 一個偶然的, 隨機寫應(yīng)當(dāng)只產(chǎn)生一個錯誤.

14.2.2.?非缺省屬性

在許多情況中, kobject 類型的 default_attrs 成員描述所有的 kobject 會擁有的屬性. 但是那不是一個設(shè)計中的限制; 屬性隨意可以添加到和刪除自 kojects. 如果你想添加一個新屬性到一個 kobject 的 sysfs 目錄, 簡單地填充一個屬性結(jié)構(gòu)并且傳遞它到:


int sysfs_create_file(struct kobject *kobj, struct attribute *attr);

如果所有都進(jìn)行順利, 文件被使用在屬性結(jié)構(gòu)中給定的名子創(chuàng)建, 并且返回值是 0; 否則, 返回通常的負(fù)錯誤碼.

注意, 相同的 show() 和 store() 函數(shù)被調(diào)用來實現(xiàn)對新屬性的操作. 在你添加一個新的, 非缺省屬性到 kobject, 你應(yīng)當(dāng)任何必要的步驟來確保這些函數(shù)知道如何實現(xiàn)這個屬性.

為去除一個屬性, 調(diào)用:


int sysfs_remove_file(struct kobject *kobj, struct attribute *attr); 

在調(diào)用后, 這個屬性不再出現(xiàn)在 kobject 的 sysfs 入口. 要小心, 但是, 一個用戶空間進(jìn)程可能有一個打開的那個屬性的文件描述符, 并且在這個屬性已經(jīng)被去除后 show 和 store 調(diào)用仍然可能.

14.2.3.?二進(jìn)制屬性

sysfs 慣例調(diào)用所有屬性來包含一個單個的人可讀文本格式的值. 就是說, 只是偶然地很少需要來創(chuàng)建能夠處理大量二進(jìn)制數(shù)據(jù)的屬性. 這個需要真正地只出現(xiàn)在必須傳遞數(shù)據(jù), 不可動地, 在用戶空間和設(shè)備. 例如, 上載固件到設(shè)備需要這個特性. 當(dāng)這樣一個設(shè)備在系統(tǒng)中遇到, 一個用戶程序可以被啟動( 通過熱插拔機制); 這個程序接著傳遞固件代碼到內(nèi)核通過一個二進(jìn)制 sysfs 屬性, 如同在"內(nèi)核固件接口"一節(jié)中所示.

二進(jìn)制屬性使用一個 bin+attribute 結(jié)構(gòu)來描述:


struct bin_attribute {
struct attribute attr;
size_t size;
ssize_t (*read)(struct kobject *kobj, char *buffer, loff_t pos, size_t size);
ssize_t (*write)(struct kobject *kobj, char *buffer, loff_t pos, size_t size);
};

這里, attr 是一個屬性結(jié)構(gòu), 給出名子, 擁有者, 和這個二進(jìn)制屬性的權(quán)限, 并且 size 是這個二進(jìn)制屬性的最大大小(或者 0 , 如果沒有最大值). read 和 write 方法類似于正常的字符驅(qū)動對應(yīng)物; 它們一次加載可被多次調(diào)用, 每次調(diào)用最大一頁數(shù)據(jù). 對于 sysfs 沒有辦法來指示最后一個寫操作, 因此實現(xiàn)二進(jìn)制屬性的代碼必須能夠以其他方式?jīng)Q定數(shù)據(jù)的結(jié)束.

二進(jìn)制屬性必須明確創(chuàng)建; 它們不能建立為缺省屬性. 為創(chuàng)建一個二進(jìn)制屬性, 調(diào)用:


int sysfs_create_bin_file(struct kobject *kobj, struct bin_attribute *attr);

去除二進(jìn)制屬性可用:


int sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);

14.2.4.?符號連接

sysfs 文件系統(tǒng)有通常的樹結(jié)構(gòu), 反映它代表的 kobjects 的層次組織. 但是內(nèi)核中對象間的關(guān)系常常比那個更加復(fù)雜. 例如, 一個 sysfs 子樹 (/sys/devices )代表所有的系統(tǒng)已知的設(shè)備, 而其他的子樹( 在 /sys/bus 之下 )表示設(shè)備驅(qū)動. 這些樹, 但是, 不代表驅(qū)動和它們所管理的設(shè)備間的關(guān)系. 展示這些附加關(guān)系需要額外的指針, 指針在 sysfs 中通過符號連接實現(xiàn).

創(chuàng)建一個符號連接在 sysfs 是容易的:


int sysfs_create_link(struct kobject *kobj, struct kobject *target, char *name);

這個函數(shù)創(chuàng)建一個連接(稱為 name)指向目標(biāo)的 sysfs 入口作為一個 kobj 的屬性. 它是一個相對連接, 因此它不管 sysfs 在任何特殊的系統(tǒng)中安裝在哪里都可用.

這個連接甚至當(dāng)目標(biāo)被從系統(tǒng)中移走也持續(xù). 如果你在創(chuàng)建對其他 kobjects 的符號連接, 你應(yīng)當(dāng)可能有一個方法知道對這個 kobjects 的改變, 或者某種保證目標(biāo) kobjects 不會消失. 結(jié)果( 在 sysfs 中的死的符號連接 )不是特別嚴(yán)重, 但是它們不代表最好的編程風(fēng)格并且可能導(dǎo)致在用戶空間的混亂.

去除符號連接可使用:


void sysfs_remove_link(struct kobject *kobj, char *name); 
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號