一、重要知識(shí)點(diǎn)
1.Sysfs文件系統(tǒng)
Sysfs文件系統(tǒng)是一種類似于proc文件系統(tǒng)的特殊文件系統(tǒng),它存在于內(nèi)存當(dāng)中,當(dāng)系統(tǒng)啟動(dòng)時(shí)由內(nèi)核掛載于內(nèi)存當(dāng)中。用于將系統(tǒng)中的設(shè)備組織成層次結(jié)構(gòu),并向用戶模式程序提供詳細(xì)的數(shù)據(jù)結(jié)構(gòu)信息。
2.Linux設(shè)備底層模型
1)為什么要使用設(shè)備模型
隨著系統(tǒng)的拓?fù)浣Y(jié)構(gòu)越來越復(fù)雜,以及要支持諸如電源管理等新特性的要求,于是在2.6的內(nèi)核中出現(xiàn)了設(shè)備模型。設(shè)備模型其實(shí)就是一套數(shù)據(jù)結(jié)構(gòu)建立起來的模型。內(nèi)核使用該模型支持了多種不同的任務(wù),包括:
a.電源管理和系統(tǒng)關(guān)機(jī)
設(shè)備模型使操作系統(tǒng)能夠以正確的順序遍歷系統(tǒng)硬件。
b.與用戶空間通信
Sysfs文件系統(tǒng)向用戶空間提供系統(tǒng)信息以及改變操作參數(shù)的結(jié)構(gòu)。
c.熱插拔事件
d.設(shè)備類型
系統(tǒng)中許多部分對(duì)設(shè)備如何連接不感興趣,但是他們需要知道哪些類型設(shè)備時(shí)可用的。設(shè)備模型提供了將設(shè)備分類的機(jī)制。
e.對(duì)象的生命周期
上述的許多功能,包括熱插拔支持和sysfs,使得內(nèi)核中管理對(duì)象的工作更為復(fù)雜。設(shè)備模型需要?jiǎng)?chuàng)造一套機(jī)制管理對(duì)象的生命周期。
2)Kobject
如果說設(shè)備模型是一套房子的話,Kobject就是構(gòu)造房子的磚塊。每個(gè)注冊(cè)的Kobject的都對(duì)應(yīng)與Sysfs文件系統(tǒng)中的一個(gè)目錄。Kobject是組成設(shè)備模型的基本結(jié)構(gòu)。類似于C++的基類,它潛入于更大的對(duì)象中——所謂的容器,用來描述設(shè)備模型的組件。如bus,device,drivers都是典型的容器。這些容器就是通過kobject連接起來,形成一個(gè)樹狀結(jié)構(gòu)。這個(gè)樹狀結(jié)構(gòu)就與/sys文件系統(tǒng)對(duì)應(yīng)。不過kobject只能建立單層結(jié)構(gòu),也就是只能建立一級(jí)目錄,要建立多級(jí)目錄,還要使用后面要介紹的Kset。
Kobject結(jié)構(gòu)定義為:
struct kobject {
char * k name; 指向設(shè)備名稱的指針
char name[KOBJ NAME LEN]; 設(shè)備名稱
struct kref kref; 對(duì)象引用計(jì)數(shù)
struct list head entry; 掛接到所在kset中去的單元
struct kobject * parent; 指向父對(duì)象的指針
struct kset * kset; 所屬kset的指針
struct kobj type * ktype; 指向其對(duì)象類型描述符的指針
struct dentry * dentry; sysfs文件系統(tǒng)中與該對(duì)象對(duì)應(yīng)的文件節(jié)點(diǎn)路徑指針
};
相關(guān)操作函數(shù):
void kobjet_init(struct kobject*kobj)
初始化Kobject
int kobject_add(struct kobject*kobj)
將Kobject對(duì)象注冊(cè)到linux系統(tǒng),如果失敗則返回一個(gè)錯(cuò)誤碼.
int kobject_init_and_add(structkobject *kobj, kobj_type *ktype, struct kobject *parent, const *fmt…)
初始化并注冊(cè)kobject,kobject傳入要初始化的Kobject對(duì)象,ktype將在后面介紹到,parent指向上級(jí)的kobject對(duì)象,如果指定位NULL,將在/sys的頂層創(chuàng)建一個(gè)目錄。*fmt為kobject對(duì)象的名字。
kobject的ktype對(duì)象是一個(gè)指向kobject_type結(jié)構(gòu)的指針,該結(jié)構(gòu)記錄了kobject對(duì)象的一些屬性。每個(gè)kobject都需要對(duì)應(yīng)一個(gè)相應(yīng)的kobject結(jié)構(gòu)。
struct kobj_type{
void?(*release)(struct kobject *kobj);
structsysfs_ops *sysfs_ops;
structattribute **default_attrs;
};
release方法用于釋放kobject占用的資源,當(dāng)kobject引用計(jì)數(shù)為0時(shí)被調(diào)用。
kobje_type的attribute成員:
struct attribute{
char*name;//屬性文件名
structmodule *owner;
mode_tmode;
}
struct attribute(屬性):對(duì)應(yīng)于kobject的目錄下一個(gè)文件,name就是文件名。
kobje_type的struct sysfs_ops成員:
struct sysfs_ops
{
ssize_t (*show)(structkobejct *, ?struct attribute *,? char ?*name);
ssize_t (*store)(structkobejct *, ?struct attribute *,? char ?*name);
}
show:當(dāng)用戶讀屬性文件時(shí),該函數(shù)被調(diào)用,該函數(shù)將屬性值存入buffer中返回給用戶態(tài);
store:當(dāng)用戶寫屬性文件時(shí),該函數(shù)被調(diào)用,用于存儲(chǔ)用戶存入的屬性值。
Kobject測試模塊:
#include?
#include?
#include?
#include?
#include?
#include?
#include?
MODULE_AUTHOR("David?Xie");??
MODULE_LICENSE("Dual?BSD/GPL");??
void?obj_test_release(struct?kobject?*kobject);??
ssize_t?kobj_test_show(struct?kobject?*kobject,?struct?attribute?*attr,char?*buf);??
ssize_t?kobj_test_store(struct?kobject?*kobject,struct?attribute?*attr,const?char?*buf,?size_t?count);??
struct?attribute?test_attr?=?{??
.name?=?"kobj_config",??
.mode?=?S_IRWXUGO,??
};??
static?struct?attribute?*def_attrs[]?=?{??
&test_attr,??
NULL,??
};??
struct?sysfs_ops?obj_test_sysops?=??
{??
.show?=?kobj_test_show,??
.store?=?kobj_test_store,??
};??
struct?kobj_type?ktype?=???
{??
.release?=?obj_test_release,??
.sysfs_ops=&obj_test_sysops,??
.default_attrs=def_attrs,??
};??
void?obj_test_release(struct?kobject?*kobject)??
{??
printk("eric_test:?release?.\n");??
}??
ssize_t?kobj_test_show(struct?kobject?*kobject,?struct?attribute?*attr,char?*buf)??
{??
printk("have?show.\n");??
printk("attrname:%s.\n",?attr->name);??
sprintf(buf,"%s\n",attr->name);??
return?strlen(attr->name)+2;??
}??
ssize_t?kobj_test_store(struct?kobject?*kobject,struct?attribute?*attr,const?char?*buf,?size_t?count)??
{??
printk("havestore\n");??
printk("write:?%s\n",buf);??
return?count;??
}??
struct?kobject?kobj;??
static?int?kobj_test_init()??
{??
printk("kboject?test?init.\n");??
kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");??
return?0;??
}??
static?int?kobj_test_exit()??
{??
printk("kobject?test?exit.\n");??
kobject_del(&kobj);??
return?0;??
}??
module_init(kobj_test_init);??
module_exit(kobj_test_exit);??
#include #include #include #include #include #include #include MODULE_AUTHOR("David Xie");MODULE_LICENSE("Dual BSD/GPL");void obj_test_release(struct kobject *kobject);ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);struct attribute test_attr = {.name = "kobj_config",.mode = S_IRWXUGO,};static struct attribute *def_attrs[] = {&test_attr,NULL,};struct sysfs_ops obj_test_sysops ={.show = kobj_test_show,.store = kobj_test_store,};struct kobj_type ktype ={.release = obj_test_release,.sysfs_ops=&obj_test_sysops,.default_attrs=def_attrs,};void obj_test_release(struct kobject *kobject){printk("eric_test: release .\n");}ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf){printk("have show.\n");printk("attrname:%s.\n", attr->name);sprintf(buf,"%s\n",attr->name);return strlen(attr->name)+2;}ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count){printk("havestore\n");printk("write: %s\n",buf);return count;}struct kobject kobj;static int kobj_test_init(){printk("kboject test init.\n");kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");return 0;}static int kobj_test_exit(){printk("kobject test exit.\n");kobject_del(&kobj);return 0;}module_init(kobj_test_init);module_exit(kobj_test_exit);
測試結(jié)果:
在/sys目錄下創(chuàng)建了kobject_test目錄
在kobject_test目錄下有kobj_config文件
讀kobject_config文件則調(diào)用了show函數(shù)。并在用戶空間顯示了show返回的kobject對(duì)象名字。
寫kobject_config文件調(diào)用了store函數(shù)。
3)Kset
kset的主要功能是包容;我們可以認(rèn)為他他是kobject的頂層容器。實(shí)際上,在每個(gè)kset對(duì)象的內(nèi)部,包含了自己的kobject,并且可以用多種處理kobject的方法處理kset。如果說kobject是基類的話,那么kset就是派送類。kobject通過kset組織成層次化的結(jié)構(gòu),kset是相同類型的組合。通俗的講,kobject建立一級(jí)的子目錄,kset可以為kobject建立多級(jí)的層次性的父目錄。
struct kset {
struct subsystem * subsys; 所在的subsystem的指針
struct kobj type * ktype; 指向該kset對(duì)象類型描述符的指針
struct list head list; 用于連接該kset中所有kobject的鏈表頭
struct kobject kobj; 嵌入的kobject
struct ?kset_uevent_ops * uevent_ops; 指向熱插拔操作表的指針
};
包含在kset中的所有kobject被組織成一個(gè)雙向循環(huán)鏈表,list域正是該鏈表的頭。Ktype域指向一個(gè)kobj type結(jié)構(gòu),被該kset中的所有kobject共享,表示這些對(duì)象的類型。Kset數(shù)據(jù)結(jié)構(gòu)還內(nèi)嵌了一個(gè)kobject對(duì)象(由kobj域表示),所有屬于這個(gè)kset 的kobject對(duì)象的parent域均指向這個(gè)內(nèi)嵌的對(duì)象。此外,kset還依賴于kobj維護(hù)引用計(jì)數(shù):kset的引用計(jì)數(shù)實(shí)際上就是內(nèi)嵌的kobject對(duì)象的引用計(jì)數(shù)。
kset與kobject的關(guān)系圖
Kset操作:
int kset_register(struct kset*kset)
注冊(cè)kset
void kset_unregister(struct kset*kset)
注銷kset
熱插拔事件:在linux系統(tǒng)中,當(dāng)系統(tǒng)配置發(fā)生變化時(shí),如添加kset到系統(tǒng)或移動(dòng)kobject,一個(gè)通知會(huì)從內(nèi)核空間發(fā)送到用戶空間,這就是熱插拔事件。熱插拔事件會(huì)導(dǎo)致用戶空間中的處理程序(如udev,mdev)被調(diào)用,這些處理程序會(huì)通過加載驅(qū)動(dòng)程序,創(chuàng)建設(shè)備節(jié)點(diǎn)等來響應(yīng)熱插拔事件。
對(duì)熱插拔事件的實(shí)際控制是由struct kset_uevent_ops結(jié)構(gòu)中的函數(shù)完成的。
struct kset_uevnt_ops{
int (*filter)(struct kset *kset,struct ?kobject *kobj);
const char *(*name)(struct kset *kset, struct?kobject *kobj );
int (*uevent)(struct kset *kset,struct ?kobject *kobj,struct kobj_uevent *env);
}
filter決定是否產(chǎn)生事件,如果返回0,將不產(chǎn)生事件。
name向用戶空間傳遞一個(gè)合適的字符串
uevent通過環(huán)境變量傳遞任何熱插拔腳本需要的信息,他會(huì)在(udev或mdev)調(diào)用之前,提供添加環(huán)境變量的機(jī)會(huì)。
kset測試模塊:
#include?
#include?
#include?
#include?
#include?
#include?
#include?
#include?
MODULE_AUTHOR("David?Xie");??
MODULE_LICENSE("Dual?BSD/GPL");??
struct?kset?kset_p;??
struct?kset?kset_c;??
int?kset_filter(struct?kset?*kset,?struct?kobject?*kobj)??
{??
printk("Filter:?kobj?%s.\n",kobj->name);??
return?1;??
}??
const?char?*kset_name(struct?kset?*kset,?struct?kobject?*kobj)??
{??
static?char?buf[20];??
printk("Name:?kobj?%s.\n",kobj->name);??
sprintf(buf,"%s","kset_name");??
return?buf;??
}??
int?kset_uevent(struct?kset?*kset,?struct?kobject?*kobj,struct?kobj_uevent_env?*env)??
{??
int?i?=?0;??
printk("uevent:?kobj?%s.\n",kobj->name);??
while(?i?envp_idx){??
printk("%s.\n",env->envp[i]);??
i++;??
}??
return?0;??
}??
struct?kset_uevent_ops?uevent_ops?=???
{??
.filter?=?kset_filter,??
.name???=?kset_name,??
.uevent?=?kset_uevent,??
};??
int?kset_test_init()??
{??
printk("kset?test?init.\n");??
kobject_set_name(&kset_p.kobj,"kset_p");??
kset_p.uevent_ops?=?&uevent_ops;??
kset_register(&kset_p);??
kobject_set_name(&kset_c.kobj,"kset_c");??
kset_c.kobj.kset?=?&kset_p;??
kset_register(&kset_c);??
return?0;??
}??
int?kset_test_exit()??
{??
printk("kset?test?exit.\n");??
kset_unregister(&kset_p);??
kset_unregister(&kset_c);??
return?0;??
}??
module_init(kset_test_init);??
module_exit(kset_test_exit);??
#include #include #include #include #include #include #include #include MODULE_AUTHOR("David Xie");MODULE_LICENSE("Dual BSD/GPL");struct kset kset_p;struct kset kset_c;int kset_filter(struct kset *kset, struct kobject *kobj){printk("Filter: kobj %s.\n",kobj->name);return 1;}const char *kset_name(struct kset *kset, struct kobject *kobj){static char buf[20];printk("Name: kobj %s.\n",kobj->name);sprintf(buf,"%s","kset_name");return buf;}int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env){int i = 0;printk("uevent: kobj %s.\n",kobj->name);while( i < env->envp_idx){printk("%s.\n",env->envp[i]);i++;}return 0;}struct kset_uevent_ops uevent_ops ={.filter = kset_filter,.name = kset_name,.uevent = kset_uevent,};int kset_test_init(){printk("kset test init.\n");kobject_set_name(&kset_p.kobj,"kset_p");kset_p.uevent_ops = &uevent_ops;kset_register(&kset_p);kobject_set_name(&kset_c.kobj,"kset_c");kset_c.kobj.kset = &kset_p;kset_register(&kset_c);return 0;}int kset_test_exit(){printk("kset test exit.\n");kset_unregister(&kset_p);kset_unregister(&kset_c);return 0;}module_init(kset_test_init);module_exit(kset_test_exit);
測試結(jié)果:
可以看出當(dāng)kset加載時(shí),在/sys下創(chuàng)建了一個(gè)kset_p,在kset_p下面創(chuàng)建了kset_c,當(dāng)kset模塊被加載和卸載時(shí)都產(chǎn)生了熱插拔事件。
?
評(píng)論
查看更多