您的位置:首页 > 运维架构 > Linux

Linux设备模型第二篇之kobject与kset之间的关系

2015-01-23 10:10 513 查看
首先,先看一下kobject与kset的定义:

struct kobject {

const char *name; //名字

struct list_head entry; //作为父对象的链表节点

struct kobject *parent; //父对象

struct kset *kset; //属于哪个对象集合

struct kobj_type *ktype; //对象类型

struct sysfs_dirent *sd; //sysfs文件系统目录

struct kref kref; //引用

unsigned int state_initialized:1; //已经初始化

unsigned int state_in_sysfs:1; //已经加入sysfs文件系统

unsigned int state_add_uevent_sent:1;

unsigned int state_remove_uevent_sent:1;

unsigned int uevent_suppress:1;

};



struct kset {

struct list_head list; 同一kset的链表

spinlock_t list_lock;

struct kobject kobj; 自身的kobjects

struct kset_uevent_ops *uevent_ops;

};

与kobject 相似,kset也有一些类似的操作函数:

void kset_init(struct kset *kset); //完成kset初始化,主要是对双向链表list的初始化

int kset_register(struct kset *k);//kset注册,完成k->kobj的方法初始化、增加父目录的引用计数、创建sysfs文件系统下的目录和属性文件

kset_unregister(struct kset *kset);//注销,释放引用计数,当引用计数为0,调用k->kobj的release函数

struct kset * kset_create_and_add(const char *name, struct kset_uevent_ops *u, struct kobject *parent_kobj);//创建并注册一个kset对象

struct kset *kset_get(struct kset *k);//引用计数加1

inline void kset_put(struct kset *k);//引用计数减一,当引用计数为0时,调用release函数

struct kobj_type *get_ktype(struct kobject *kobj);//获取kobj的操作方法

正如kobject_init_and_add是kobject初始化操作的集大成者,对于kset的初始化也有一个类似的函数kset_create_and_add,但其实,它更像kobject_create_and_add,现在对其进行分析:





图1、kset_create_and_add调用流程

(1)、kset_create_and_add创建了一个名为name的kset,然后调用kset_register注册kset。

(2)、kset_register主要实现了两步操作,

一、调用kobject_add_internal(&k->kobj)增加父目录的引用计数、创建sysfs文件系统下的目录和属性文件等,这和上一篇分析kobject的情况是一致的,调用的函数也都是kobject_add_internal。

二、除了上面和kobject的共性外,这里还多了一步处理——kobject_uevent(&k->kobj, KOBJ_ADD),kobject_uevent调用了kobject_uevent_env(kobj,
action, NULL)处理事件。

(3)、kobject_uevent_env的内容还是比较丰富的,调用了父目录kset的uevent_ops的filter判断事件是否过滤掉,当filter返回0则表示该事件过滤掉,然后调用uevent_ops->name获取子系统的名字。接着有add_uevent_var添加一系列环境变量。



图2、kobject与kset之间关系

kobject与kset共同构成了Linux设备模型的底层层次结构,而kset封装了一个数据成员kobject,事实上对kset的许多操作也是集中在kset->kobject上。相同类型的kobject的parent指向同一个kset->kobj。

通过以下内核源码中的具体代码片段,可以看到实际kset的应用场合,然后理解:kset是包含了一类具有共性的kobject的集合。

片段1:(见函数kobject_add_internal(…))

/* join kset if set, use it as parent if we do not already have one */

if (kobj->kset) {

if (!parent)

parent = kobject_get(&kobj->kset->kobj);

kobj_kset_join(kobj); //将kobj加入kset的链表中

kobj->parent = parent;

}



片段2:(见函数kobject_uevent_env(…))

kset = top_kobj->kset;

uevent_ops = kset->uevent_ops;



/* skip the event, if the filter returns zero. */

if (uevent_ops && uevent_ops->filter)

if (!uevent_ops->filter(kset, kobj)) {

pr_debug("kobject: '%s' (%p): %s: filter function "

"caused the event to drop!\n",

kobject_name(kobj), kobj, __FUNCTION__);

return 0;

}

同时kset->kobject还可以在构成另一个更高层面的层次结构。用以下一个并无实际意义的例子说明这种关系:

kset_filter

kset_name

kset_uevent

struct kset_uevent_ops

struct kset kset_p

struct kset kset_c




图3、示例程序框架图

#include<linux/module.h>

#include<linux/fs.h>

#include<linux/kobject.h>



struct kset kset_Master,kset_Slave;

int uevent_ops_Filter(struct kset *kset, struct kobject *kobj) ;

const char* uevent_ops_Name(struct kset *kset, struct kobject *kobj) ;

int uevent_ops_uevent(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env) ;



struct kset_uevent_ops uevent_ops=//kset的事件操作方法

{

.filter=uevent_ops_Filter,

.name=uevent_ops_Name,

.uevent=uevent_ops_uevent,

};



int uevent_ops_Filter(struct kset *kset, struct kobject *kobj)//事件过滤

{

printk("%s..vs.\n",(kset->kobj).name) ;

printk("%s..",kobj->name) ;

printk("%s..",kobj->parent->name) ;

printk("UEVENT:filter,kobj %s.\n",kobj->name) ;



return 1 ;

}



const char* uevent_ops_Name(struct kset *kset, struct kobject *kobj)//获取子系统名称

{

static char buf[20];

printk("UEVENT:name,kobj %s.\n",kobj->name) ;

sprintf(buf,"%s","set_test") ;



return buf ;

}



int uevent_ops_uevent(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env)//事件处理

{

int i=0 ;



printk("UEVENT:uevent,kobj %s.\n",kobj->name) ;

while(i<env->envp_idx)

{

printk("%s.\n",env->envp[i]) ;

i++ ;

}

return 0 ;

}





int __init DEMO_init(void)//模块加载

{

int ret=0 ;



printk("kset test init.\n") ;

printk("kset master init.\n") ;

kobject_set_name(&kset_Master.kobj,"kset_Master") ;

kset_Master.uevent_ops=&uevent_ops ;

ret=kset_register(&kset_Master) ;

if(ret)

{

printk("kset_register error.\n") ;

}



printk("kset slave init.\n") ;

kobject_set_name(&kset_Slave.kobj,"kset_Slave") ;

kset_Slave.kobj.kset=&kset_Master ;

ret=kset_register(&kset_Slave) ;

if(ret)

{

printk("kset_register error.\n") ;

}



return 0 ;

}



void __exit DEMO_exit(void)//模块卸载

{

printk("kobject test exit.\n") ;

kset_unregister(&kset_Slave) ;

kset_unregister(&kset_Master) ;

}



module_init(DEMO_init) ;

module_exit(DEMO_exit) ;



MODULE_LICENSE("GPL") ;

在这里,定义并注册了二个kset.第二个kset的kobj->kset域指向第一个kset.这样,当第二个kset注册或者卸载的时候就会调用第一个kset中的uevent_ops的相关操作.

kset_p.uevent_ops->filter函数中,使其返回1.使其匹配成功。

在kset_p.uevent_ops->name中。使其返回的子系统名为引起事件的kobject的名称,即:kset_c.

最后在kset_p.uevent_ops->uevent中将环境变量全部打印出来。

通过最后的输出结果,还可以看到使用kset_register注册一个kset还会产生事件。

下面是dmesg的输出结果:

kset test init.

kset master init.

kset slave init.

kset_Slave..ksetMaster..UEVENT:filter,kobj kset_Slave

UEVENT: name. kobj kset_Slave.

UEVENT: uevent. kobj kset_Slave.

ACTION=add.

DEVPATH=/kset_Master/kset_Slave..

SUBSYSTEM=kset_test

简而言之,正如“图2、kobject与kset之间关系”所展示的那样,kset封装了同类型kobject的共性,在kset->kobject和kset->kobj_type中实现共性操作,并且通过以下两种方式构成具有一定梯度关系的层次化结构,第一种是kobject->parent或kset->kobj->parent指向上一层kobject或者kset->kobj ,第二种是kobject->kset指向上一层的kset。当然,单独的kobject也可以组成层次化结构,那就是直接使用kobject->parent指向上一层此的kobject。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: