關於linux設備模型網上有一些論述,有些東西我就用了拿來主義,進行了修改和整理。
§1
KobjectKobject 是Linux 2.6引入的新的設備管理機制,在內核中由struct kobject表示。通過這個數據結構使所有設備在底層都具有統一的接口,kobject提供基本的對象管理,是構成Linux2.6設備模型的核心結構,它與sysfs文件系統緊密關聯,每個在內核中注冊的kobject對象都對應於sysfs文件系統中的一個目錄。Kobject是組成設備模型的基本結構。類似於C++中的基類,它嵌入於更大的對象的對象中--所謂的容器--用來描述設備模型的組件。如bus,devices,
drivers 都是典型的容器。這些容器就是通過kobject連接起來了,形成了一個樹狀結構。這個樹狀結構就與/sys向對應。
kobject 結構為一些大的數據結構和子系統提供了基本的對象管理,避免了類似機能的重復實現。這些機能包括
- 對象引用計數.
- 維護對象鏈表(集合).
- 對象上鎖.
- 在用戶空間的表示.
Kobject結構定義為:
struct kobject {
char * k name; 指向設備名稱的指針
char name[KOBJ NAME LEN]; 設備名稱
struct kref kref; 對象引用計數
struct list head entry; 掛接到所在kset中去的單元
struct kobject * parent; 指向父對象的指針
struct kset * kset; 所屬kset的指針
struct kobj type * ktype; 指向其對象類型描述符的指針
struct dentry * dentry; sysfs文件系統中與該對象對應的文件節點路徑指針
};
其中的kref域表示該對象引用的計數,內核通過kref實現對象引用計數管理,內核提供兩個函數kobject_get()、kobject_put()分別用於增加和減少引用計數,當引用計數為0時,所有該對象使用的資源釋放。Ktype 域是一個指向kobj type結構的指針,表示該對象的類型。
相關函數
void kobject_init(struct kobject * kobj);kobject初始化函數。
int kobject_set_name(struct kobject *kobj, const char *format, ...);設置指定kobject的名稱。
struct kobject *kobject_get(struct kobject *kobj);將kobj 對象的引用計數加1,同時返回該對象的指針。
void kobject_put(struct kobject * kobj); 將kobj對象的引用計數減1,如果引用計數降為0,則調用kobject release()釋放該kobject對象。
int kobject_add(struct kobject * kobj);將kobj對象加入Linux設備層次。掛接該kobject對象到kset的list鏈中,增加父目錄各級kobject的引用計數,在其parent指向的目錄下創建文件節點,並啟動該類型內核對象的hotplug函數。
int kobject_register(struct kobject * kobj);kobject注冊函數。通過調用kobject init()初始化kobj,再調用kobject_add()完成該內核對象的注冊。
void kobject_del(struct kobject * kobj);從Linux設備層次(hierarchy)中刪除kobj對象。
void kobject_unregister(struct kobject * kobj);kobject注銷函數。與kobject register()相反,它首先調用kobject del從設備層次中刪除該對象,再調用kobject put()減少該對象的引用計數,如果引用計數降為0,則釋放kobject對象。
§2 Kobj typestruct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};
Kobj type數據結構包含三個域:一個release方法用於釋放kobject占用的資源;一個sysfs ops指針指向sysfs操作表和一個sysfs文件系統缺省屬性列表。Sysfs操作表包括兩個函數store()和show()。當用戶態讀取屬性時,show()函數被調用,該函數編碼指定屬性值存入buffer中返回給用戶態;而store()函數用於存儲用戶態傳入的屬性值。
attribute
struct attribute {
char * name;
struct module * owner;
mode_t mode;
};
attribute, 屬性。它以文件的形式輸出到sysfs的目錄當中。在kobject對應的目錄下面。文件
名就是name。文件讀寫的方法對應於kobj type中的sysfs ops。
§3. ksetkset最重要的是建立上層(sub-system)和下層的(kobject)的關聯性。kobject 也會利用它了分辨自已是屬於那一個類型,然後在/sys 下建立正確的目錄位置。而kset 的優先權比較高,kobject會利用自已的*kset 找到自已所屬的kset,並把*ktype 指定成該kset下的ktype,除非沒有定義kset,才會用ktype來建立關系。Kobject通過kset組織成層次化的結構,kset是具有相同類型的kobject的集合,在內核中用kset數據結構表示,定義為:
struct kset {
struct subsystem * subsys; 所在的subsystem的指針
struct kobj type * ktype; 指向該kset對象類型描述符的指針
struct list head list; 用於連接該kset中所有kobject的鏈表頭
struct kobject kobj; 嵌入的kobject
struct kset hotplug ops * hotplug ops; 指向熱插拔操作表的指針
};
包含在kset中的所有kobject被組織成一個雙向循環鏈表,list域正是該鏈表的頭。Ktype域指向一個kobj type結構,被該kset中的所有kobject共享,表示這些對象的類型。Kset數據結構還內嵌了一個kobject對象(由kobj域表示),所有屬於這個kset 的kobject對象的parent域均指向這個內嵌的對象。此外,kset還依賴於kobj維護引用計數:kset的引用計數實際上就是內嵌的kobject對象的引用計數。
見圖1,kset與kobject的關系圖
這幅圖很經典,她反映了整個kobject的連接情況。
相關函數
與kobject 相似,kset_init()完成指定kset的初始化,kset_get()和kset_put()分別增加和減少kset對象的引用計數。Kset_add()和kset_del()函數分別實現將指定keset對象加入設備層次和從其中刪除;kset_register()函數完成kset的注冊而kset_unregister()函數則完成kset的注銷。
§4 subsystem如果說kset 是管理kobject 的集合,同理,subsystem 就是管理kset 的集合。它描述系統中某一類設備子系統,如block subsys表示所有的塊設備,對應於sysfs文件系統中的block目錄。類似的,devices subsys對應於sysfs中的devices目錄,描述系統中所有的設備。Subsystem由struct subsystem數據結構描述,定義為:
struct subsystem {
struct kset kset; 內嵌的kset對象
struct rw semaphore rwsem; 互斥訪問信號量
};
可以看出,subsystem與kset的區別就是多了一個信號量,所以在後來的代碼中,subsystem已經完全被kset取締了。
每個kset屬於某個subsystem,通過設置kset結構中的subsys域指向指定的subsystem可以將一個kset加入到該subsystem。所有掛接到同一subsystem的kset共享同一個rwsem信號量,用於同步訪問kset中的鏈表。
相關函數
subsystem有一組類似的函數,分別是:
void subsystem_init(struct subsystem *subsys);
int subsystem_register(struct subsystem *subsys);
void subsystem_unregister(struct subsystem *subsys);
struct subsystem *subsys_get(struct subsystem *subsys)
void subsys_put(struct subsystem *subsys);
關於那些函數的用法,會在後面的舉例中詳細講。這裡僅僅是一個介紹。