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

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

2012-02-13 16:08 429 查看
首先,先看一下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。

创建于2011年9月2日

第一次修改2011年10月25日星期二
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: