關於linux設備模型網上有一些論述,有些東西我就用了拿來主義,進行了修改和整理。
§1 Kobject
Kobject 是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 type
struct 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. kset
kset最重要的是建立上層(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);
關於那些函數的用法,會在後面的舉例中詳細講。這裡僅僅是一個介紹。