Linux设备驱动之Kobject、Kset
LDD3中說,Kobject的作用為:
??? 1、sysfs 表述:在 sysfs 中出現的每個對象都對應一個 kobject, 它和內核交互來創建它的可見表述。
??? 2、熱插拔事件處理 :kobject 子系統將產生的熱插拔事件通知用戶空間。
? ? 3、數據結構關聯:整體來看, 設備模型是一個極端復雜的數據結構,通過其間的大量鏈接而構成一個多層次的體系結構。kobject 實現了該結構并將其聚合在一起。?
? ? 此篇文章,只分析第一條,kobject 與 kset sysfs 之間的關系。剩下的兩條將在后續的兩篇文章中分析
? ??
首先,什么是 kobject ,它也不過是內核里的一個結構體而已
? ??struct kobject {
??? ? ??const char??????? *name;
??? ? ??struct list_head??? entry;
??? ? ??struct kobject??????? *parent;
??? ? ??struct kset??????? *kset;
??? ? ??struct kobj_type??? *ktype;
??? ? ??......// 省略一些暫時不想看到的東西
? ??};
那么,這個結構體有何特殊之處呢?
??? ? ??每一個 kobject 對應 文件系統 /sys 里的一個 目錄,目錄的名字就是結構體中的 name
???
什么又是 kset ,kset 也是個結構體而已
? ??struct kset {
??? ? ??struct list_head list;???
??? ? ??struct kobject kobj;???
??? ? ??struct kset_uevent_ops *uevent_ops;
??? ? ??spinlock_t list_lock;
? ??};
? ??我們前面說了,每一個 kobj 對應 文件系統 /sys 里的一個 目錄,那么每一個 kset 都包含了一個 kobj,那樣的話,kset也對應于 /sys 里的一個 目錄
? ??簡單來說,kset 與 kobj 都是目錄,既然是目錄,那么在就是一個樹狀結構,每一個目錄都將有一個 父節點,
? ??? ??在kset中使用kset.kobj->parent 指定
? ??? ??在kboject中使用? kobj->parent 指定
? ??顯然,整個樹狀目錄結構,都是通過kobj來構建的,只不過有些kobj嵌在Kset里,分析目錄結構時把kset當成一個普通的kobj會好理解很多。
那么kset 有何特殊之處呢?
? ? 我們可以看到 kset 結構中有一個鏈表,它目錄下的 一些相同類型的kobj會在創建時鏈入鏈表,也就是說Kset是一些kobj的集合。? ??
? ??干說還是比較抽象的,那么我們就來看看 /sys 目錄底下的這些東西,哪些是kset 哪些是kobj 結構又是怎樣的。
? ??看過代碼的應該知道,想要在/sys 目錄下創建 目錄,那就要 構造 kset 或者 kobj 設置并注冊。
? ??對于kobject:
??? ? ??kobject_create_and_add
??? ? ??kobject_init_and_add
? ??對于kset:
??? ? ??kset_create_and_add
??? 我在這3個函數中增加了prink打印語句,打印內核創建的每一個 kobj 或者 kset 的名字,以及父節點的名字,甚至它指向的kset的kobj的名字。
???
??? 原本我以為,較高層次的目錄會是kset,因為它是個集合嘛,然而并不全是。
??? ? ??the kset name is devices,no parent
??????? ? ??the kset name is system,parent's name is devices
??????? ? ??the kobject name is virtual,parent's name is devices???
??? ? ??the kset name is bus,no parent
??? ? ??the kset name is class,no parent
??? ? ??the kset name is module,no parent
??? ? ??the kobject name is fs,no parent
???? ?? the kobject name is dev,no parent
??????? ? ??the kobject name is block,parent's name is dev
??????? ? ??the kobject name is char,parent's name is dev???????
??? ? ??the kobject name is firmware,no parent
??? ? ??the kobject name is kernel,no parent
??????? ? ??the kset name is slab,parent's name is kernel
??? ? ??the kobject name is block,no parent
??? 寫著no parent的,在/sys/目錄下可以找到它們,對于devices、bus、class、module它們是kset
??????????????????????????????????????????????? ? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? ??對于fs、dev、firmware、kernel、block 它們是 kobj
而且,我們還可以發現
??? 1、??? kset 底下可以放 kset (但是無法鏈入鏈表,分析代碼時會知道)
????????the kset name is devices,no parent
??????????? ? ??the kset name is system,parent's name is devices
??? 2、??? kset 底下可以放 kobj (可以鏈入鏈表,也可以不鏈入)
??????? the kset name is devices,no parent
??????????? the kobject name is virtual,parent's name is devices
??? 3、 kobject 底下可以放 kset (顯然沒鏈表的概念了)
??????? the kobject name is kernel,no parent
??????????? the kset name is slab,parent's name is kernel
??? 4、 kobj 底下放 kobj (同樣沒有鏈表的概念)
??????? the kobject name is dev,no parent
??????????? the kobject name is block,parent's name is dev
???? 如下圖:黃色代表Kset 藍色代表Kobject
???????
? ??那么,至此我們對kset kobj它們之間的聯系就應該有一個比較淺顯的認識了。
------------------------------------------------------------------------------------------------------------------------------------------------------
下面來分析代碼,進一步摸索,先把圖貼上來,虛線表示可能的其它一些連接情況。
---------------------------------------------------------------------------------------------------------------------------------------------------------------
? ??struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
? ??? ??{
? ? ? ? ? ??? ??struct kobject *kobj;
? ? ? ? ? ? ? ? kobj = kobject_create();
? ? ? ? ? ? ? ? retval = kobject_add(kobj, parent, "%s", name);
? ? ? ? ? ? ? ? return kobj;
? ? ? ? }
?
? ??kobject_create_and_add
? ? ? ??kobject_create??????? // kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
????????? ??kobject_init ? ? ? ? ? ? ?// kobj->ktype = ktype;
?????????? ?kobject_init_internal??? // kref_init(&kobj->kref);
? ? ? ? kobject_add
? ? ? ? ? ? kobject_add_varg??? // retval = kobject_set_name_vargs(kobj, fmt, vargs); // kobj->parent = parent;
? ? ? ? ? ? kobject_add_internal
? ? ? ? ? ? if (kobj->kset) {??? // kobj->kset == NULL 不執行
? ? ? ? ? ? ? ??if (!parent)
? ? ? ? ? ? ? ? ? ??parent = kobject_get(&kobj->kset->kobj);
? ? ? ? ? ? ? ? ? ? kobj_kset_join(kobj);
? ? ? ? ? ? ? ? ? ? kobj->parent = parent;
? ? ? ? ? ? }
? ? ? ? ? ? create_dir
????????????????
? ??kobject_create_and_add 函數從 構建一個kobject到 在sysfs中創建路徑一氣呵成,其中沒有關于kset的設置,僅僅是設置了parent ktype
? ??如果 kobject_create_and_add 傳入的 parent 參數 是一個普通的kobject ,那么就與應于圖中的③與⑤的關系
? ??如果 kobject_create_and_add 傳入的 parent 參數 是一個kset->kobject,那么就與應于圖中的③與④的關系
---------------------------------------------------------------------------------------------------------------------------------------------------------------
? ??priv->kobj.kset = bus->p->drivers_kset;? // 設置它所屬的Kset
? ? ? ??? ??error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name);
?
? ??int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
???????????? struct kobject *parent, const char *fmt, ...)
? ? {
????? ??kobject_init(kobj, ktype);
? ? ? ? retval = kobject_add_varg(kobj, parent, fmt, args);
? ? }
? ? kobject_init_and_add???
????? ??kobject_init??? // kobj->ktype = ktype;
???????????? kobject_init_internal??? // kref_init(&kobj->kref);
? ? ? ? kobject_add_varg??? // retval = kobject_set_name_vargs(kobj, fmt, vargs); // kobj->parent = parent;
???????????? kobject_add_internal
?????????????? ??if (kobj->kset) {??? // 將kobject 添加到它所指向的kset->list中
?????????????????? ??if (!parent)
?????????????????????? ??parent = kobject_get(&kobj->kset->kobj);
? ? ? ? ? ? ? ? ? ? ? ? ?kobj_kset_join(kobj);
????????????????????????? kobj->parent = parent;? // 如果沒有parent 將它所屬的kset->kobj作為它的parent
??????????????????? }
????????????? create_dir
? ??與kobject_create_and_add 相比 就是少了構建kobkject,然而這樣給了我們設置kset的機會,同時往往不會設置parent
對應于圖中的①與④的關系
---------------------------------------------------------------------------------------------------------------------------------------------------------------
? ??struct kset *kset_create_and_add(const char *name,
???????????????? struct kset_uevent_ops *uevent_ops,
???????????????? struct kobject *parent_kobj)
?????
??? ? ??kset = kset_create(name, uevent_ops, parent_kobj);
??? ? ??error = kset_register(kset);
????? }
? ??kset_create_and_add
? ? ? ??kset_create
??????????? kset = kzalloc(sizeof(*kset), GFP_KERNEL);
??????????? retval = kobject_set_name(&kset->kobj, name);
??????????? kset->uevent_ops = uevent_ops;???????
??????????? kset->kobj.parent = parent_kobj;
??????????? kset->kobj.ktype = &kset_ktype;
??????????? kset->kobj.kset = NULL;
??????? kset_register
??????????? kset_init(k);
??????????????? err = kobject_add_internal(&k->kobj);
??????????????????? parent = kobject_get(kobj->parent);
??????????????????? if (kobj->kset) {??? // kobj->kset==NULL 不執行
?????????????????????? ....
?????????????????? }
??????????????????? error = create_dir(kobj);
??????? kset_create_and_add 無法將 創建kset->kobj.kset 指向任何kset
??????? 但是kset->kobj.parent 還是能和kobj.parent指向 普通的kobj 或者包含在kset里的kobj
? ??如果 kset_create_and_add 傳入的 parent 參數 是一個普通的kobject ,那么就與應于圖中的④與⑤的關系
? ??如果 kset_create_and_add 傳入的 parent 參數 是一個kset->kobject,那么就與應于圖中的②與④的關系
-------------------------------------------------------------------------------------------------------------------------------------------------------------
還有一種情況就是,創建一個 kset 并設置kset.kobject.kset
然后調用 kset_register
? ? ? ? kset_register
??????????? kset_init(k);
??????????????? err = kobject_add_internal(&k->kobj);
??????????????????? parent = kobject_get(kobj->parent);
???????????????????if (kobj->kset) {??? // 將kobject 添加到它所指向的kset->list中
?????????????????? ??if (!parent)
?????????????????????? ??parent = kobject_get(&kobj->kset->kobj);
? ? ? ? ? ? ? ? ? ? ? ? ?kobj_kset_join(kobj);
????????????????????????? kobj->parent = parent;? // 如果沒有parent 將它所屬的kset->kobj作為它的parent
??????????????????? }
??????????????????? error = create_dir(kobj);
? ? 對應于圖中④與⑥的關系。
-------------------------------------------------------------------------------------------------------------------------------------------------------------
? ??上面代碼的細節,比如如何在/sys/創建路徑請參考:http://blog.csdn.net/lizuobin2/article/details/51511336
到此,我們應該對 kobject kset sysfs 之間的目錄關系比較清楚了,但是我們至少還應該看看ktype,至于Kset中的熱插拔在第二條中分析好了。
? ??struct kobject {
??? ? ??const char??????? *name;
??? ? ??struct list_head??? entry;
??? ? ??struct kobject??????? *parent;
??? ? ??struct kset??????? *kset;
??? ? ??struct kobj_type??? *ktype;
???? ?? struct kref??????? kref;
? ??……
? ??};
? ??struct kobj_type {
??? ? ??void (*release)(struct kobject *kobj);
??? ? ??struct sysfs_ops *sysfs_ops;
??? ? ??struct attribute **default_attrs;? //struct attribute *default_attrs[]
? ??};
? ??ktype 由一個release函數、一個sysfs_ops、一個指針數組(二維指針)組成
? ??1、release 函數
??? ? ??每一個Kobject 都必須有一個release方法,有意思的是,release 函數并沒有包括在kobject自身內,而是包含在它的結構體成員Ktype內。而且kobject在調用release之前應該保持穩定(不明白抄自LDD3)。
? ??2、struct attribute **default_attrs
? ? ? ??struct attribute {
? ? ? ? ? ??const char??????? *name;
? ? ? ? ? ? struct module??????? *owner;
? ? ? ? ? ? mode_t??????????? mode;
? ? ? ? };
? ? ? ? default_attrs 指向的地方 是個指針數組,這些指針的類型為attribute ,那么這些attribute 就是該kobject的屬性了,name 是屬性的名字,在kobject目錄下 表現為 文件 ,owner 指向模塊的指針(如果有的話),那么該模塊負責實現這些屬性。mode 是保護位,通常是S_IRUGO,可寫的則用S_IWUSR 僅為root提供寫權限。default_attrs最后一個元素必須為0,要不然它找不著北~
? ??3、sysfs_opes? 實現屬性的方法
??? ? ??struct sysfs{
??????? ? ??ssize_t *show(struct kobject *kobject, struct attribute *attr,char *buf);
??????? ? ??ssize_t *store(struct kobject *kobject, struct attribute *attr,char *buf, size_t size);
??? ? ??}
??? 在內核里,一類設備往往使用相同的show , store函數。
附上一個例子:linux2.6.32.2 編譯通過
[cpp] view plaincopyprint?核心結論:
? ??1、sys 目錄下的層次結構依賴于 kobject.parent ,未指定parent時,默認使用 kobject.kset.kobject 作為 parent,如果都沒有,就出現在 /sys 目錄下。
? ??2、該 kobject 目錄下的屬性文件依賴于 kobject.ktype
總結
以上是生活随笔為你收集整理的Linux设备驱动之Kobject、Kset的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [svc]jdk+tomcat部署.jf
- 下一篇: Linux中对文件描述符的操作(FD_Z