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

首先,先看一下kobjectkset的定义:

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->kobjrelease函数

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_addkobject初始化操作的集大成者,对于kset的初始化也有一个类似的函数kset_create_and_add,但其实,它更像kobject_create_and_add,现在对其进行分析:

Linux设备模型第二篇之kobject与kset之间的关系_第1张图片

1kset_create_and_add调用流程

1)、kset_create_and_add创建了一个名为namekset,然后调用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的内容还是比较丰富的,调用了父目录ksetuevent_opsfilter判断事件是否过滤掉,当filter返回0则表示该事件过滤掉,然后调用uevent_ops->name获取子系统的名字。接着有add_uevent_var添加一系列环境变量。

Linux设备模型第二篇之kobject与kset之间的关系_第2张图片

2kobjectkset之间关系

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

Linux设备模型第二篇之kobject与kset之间的关系_第3张图片

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.第二个ksetkobj->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

简而言之,正如2kobjectkset之间关系所展示的那样,kset封装了同类型kobject的共性,在kset->kobjectkset->kobj_type中实现共性操作,并且通过以下两种方式构成具有一定梯度关系的层次化结构,第一种是kobject->parentkset->kobj->parent指向上一层kobject或者kset->kobj ,第二种是kobject->kset指向上一层的kset当然,单独的kobject也可以组成层次化结构,那就是直接使用kobject->parent指向上一层此的kobject

 

创建于201192

第一次修改20111025星期二


你可能感兴趣的:(Linux设备模型第二篇之kobject与kset之间的关系)