kobject

来源:互联网 发布:罗马2 兵种数据修改 编辑:程序博客网 时间:2024/06/10 01:34

核心结论:

    1、sys 目录下的层次结构依赖于 kobject.parent ,未指定parent时,默认使用 kobject.kset.kobject 作为 parent,如果都没有,就出现在 /sys 目录下。

    2、该 kobject 目录下的属性文件依赖于 kobject.ktype


    在Linux的驱动表示中,主要有三个基本的结构,分别是kobject,kset,ktype.Kobject,kset,kypte这三个结构是设备模型中的下层架构。模型中的每一个元素都对应一个kobject.kset和ktype可以看成是kobject在层次结构与属性结构方面的扩充。将三者之间的关系用图的方示描述如下:


    如上图所示:我们知道。在sysfs中每一个目录都对应一个kobject.这些kobject都有自己的parent。在没有指定parent的情况下,都会指向它所属的kset->object。其次,kset也内嵌了kobject.这个kobject又可以指它上一级的parent。就这样。构成了一个空间上面的层次关系。
    其实,每个对象都有属性。例如,电源管理,执插拨事性管理等等。因为大部份的同类设备都有相同的属性,因此将这个属性隔离开来,存放在ktype中。这样就可以灵活的管理了.记得在分析sysfs的时候。对于sysfs中的普通文件读写操作都是由kobject->ktype->sysfs_ops来完成的.

kobject

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. truct kobject {    
  2.     const char      *name;         //名字    
  3.     struct list_head    entry;         //连接到kset建立层次结构    
  4.     struct kobject      *parent;       //指向父节点,面向对象的层次架构    
  5.     struct kset     *kset;             //指向所属的kset    
  6.     struct kobj_type    *ktype;        //属性文件    
  7.     struct sysfs_dirent *sd;    
  8.     struct kref     kref;          //引用计数    
  9.     unsigned int state_initialized:1;      //初始化状态...    
  10.     unsigned int state_in_sysfs:1;    
  11.     unsigned int state_add_uevent_sent:1;    
  12.     unsigned int state_remove_uevent_sent:1;    
  13.     unsigned int uevent_suppress:1;    
  14. };  

    在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录。从面向对象的角度来说,kobject可以看作是所有设备对象的基类,因为C语言并没有面向对象的语法,所以一般是把kobject内嵌到其他结构体里来实现类似的作用,这里的其他结构体可以看作是kobject的派生类。Kobject为Linux设备模型提供了很多有用的功能,比如引用计数,接口抽象,父子关系等等,所以,在内核中,没有用kobject直接定义的变量,kobject只是作为一个抽象的基类而存在。一般都是将kobject嵌入到另一个结构,这个结构就可以看做是kobject的一个子类。而kobject的子类会比较关心kobject的属性和方法。
    内核里的设备之间是以树状形式组织的,在这种组织架构里比较靠上层的节点可以看作是下层节点的父节点,反映到sysfs里就是上级目录和下级目录之间的关系,在内核里,正是kobject帮助我们实现这种父子关系。在kobject的定义里,name表示的是kobject在sysfs中的名字;指针parent用来指向kobject的父对象;Kref大家应该比较熟悉了,kobject通过它来实现引用计数;Kset指针用来指向这个kobject所属的kset;对于ktype,如果只是望文生义的话,应该是用来描述kobject的类型信息。

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. struct kref//引用计数    
  2. {    
  3.     atomic_t refcount;    
  4. }  
kobject的作用:

    1、sysfs 表述:在 sysfs 中出现的每个对象都对应一个 kobject, 它和内核交互来创建它的可见表述。
    2、数据结构关联:整体来看, 设备模型是一个极端复杂的数据结构,通过其间的大量链接而构成一个多层次的体系结构。kobject 实现了该结构并将其聚合在一起。
    3、热插拔事件处理 :kobject 子系统将产生的热插拔事件通知用户空间。

    一个kobject对自身并不感兴趣,它存在的意义在于把高级对象连接到设备模型上。因此内核代码很少(甚至不知道)创建一个单独的 kobject;而kobject 被用来控制对大型域(domain)相关对象的访问,所以kobject 被嵌入到其他结构中。kobject 可被看作一个最顶层的基类,其他类都它的派生产物。 kobject 实现了一系列方法,对自身并没有特殊作用,而对其他对象却非常有效。

    对于给定的kobject指针,可使用container_of宏得到包含它的结构体的指针

kobject相关操作函数:

1、初始化---kobject_init

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)    
  2. {    
  3.     char *err_str;    
  4.     
  5.     if (!kobj) {    
  6.         err_str = "invalid kobject pointer!";    
  7.         goto error;    
  8.     }    
  9.     if (!ktype) {    
  10.         err_str = "must have a ktype to be initialized properly!\n";    
  11.         goto error;    
  12.     }    
  13.     if (kobj->state_initialized) {    
  14.         /* do not error out as sometimes we can recover */    
  15.         printk(KERN_ERR "kobject (%p): tried to init an initialized "    
  16.                "object, something is seriously wrong.\n", kobj);    
  17.         dump_stack();    
  18.     }    
  19.     
  20.     kobject_init_internal(kobj);//进行主要的成员变量初始化    
  21.     kobj->ktype = ktype;  //<span style="color: rgb(0, 130, 0); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; text-align: left; background-color: rgb(248, 248, 248); ">关联</span>这个kobject类型    
  22.     return;    
  23.     
  24. error:    
  25.     printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);    
  26.     dump_stack();    
  27. }   
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static void kobject_init_internal(struct kobject *kobj)    
  2. {    
  3.     if (!kobj)    
  4.         return;    
  5.     kref_init(&kobj->kref);//初始化引用计数为1    
  6.     INIT_LIST_HEAD(&kobj->entry);//prev和next都指向自己     
  7.     kobj->state_in_sysfs = 0;    
  8.     kobj->state_add_uevent_sent = 0;    
  9.     kobj->state_remove_uevent_sent = 0;    
  10.     kobj->state_initialized = 1;    
  11. }   
2、将kobject加入到分层结构-----kobject_add
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. int kobject_add(struct kobject *kobj, struct kobject *parent,    
  2.     const char *fmt, ...)    
  3.     
  4. va_list args;    
  5. int retval;    
  6.     
  7. if (!kobj)    
  8.     return -EINVAL;    
  9.     
  10. if (!kobj->state_initialized) {    
  11.     printk(KERN_ERR "kobject '%s' (%p): tried to add an "    
  12.            "uninitialized object, something is seriously wrong.\n",    
  13.            kobject_name(kobj), kobj);    
  14.     dump_stack();    
  15.     return -EINVAL;    
  16. }    
  17. va_start(args, fmt);    
  18. retval = kobject_add_varg(kobj, parent, fmt, args);//主要的add操作    
  19. va_end(args);    
  20.     
  21. return retval; </span>  
kobject_add_varg():
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,    
  2.                 const char *fmt, va_list vargs)    
  3. {    
  4.     int retval;    
  5.     
  6.     retval = kobject_set_name_vargs(kobj, fmt, vargs);//设置kobject的名字。即kobject的name成员    
  7.     if (retval) {    
  8.         printk(KERN_ERR "kobject: can not set name properly!\n");    
  9.         return retval;    
  10.     }    
  11.     kobj->parent = parent;  //设置kobject的parent    
  12.     return kobject_add_internal(kobj);//在sysfs中添加kobjcet信息    
  13. }  </span>  
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static int kobject_add_internal(struct kobject *kobj)    
  2. {    
  3.     int error = 0;    
  4.     struct kobject *parent;    
  5.     
  6.     if (!kobj)    
  7.         return -ENOENT;    
  8.     
  9.     if (!kobj->name || !kobj->name[0]) { //如果kobject的名字为空.退出    
  10.         WARN(1, "kobject: (%p): attempted to be registered with empty "    
  11.              "name!\n", kobj);    
  12.         return -EINVAL;    
  13.     }    
  14.     
  15.     parent = kobject_get(kobj->parent);//如果parent为真,则增加kobj->kref计数,也就是父节点的引用计数      
  16.     
  17.     /* join kset if set, use it as parent if we do not already have one */    
  18.     if (kobj->kset) {     
  19.         if (!parent)    
  20.             parent = kobject_get(&kobj->kset->kobj);//如果kobj-parent父节点为NULL那么就用kobj->kset->kobj作其父节点,并增加其引用计数      
  21.         kobj_kset_join(kobj);//把kobj的entry成员添加到kobj->kset>list的尾部,现在的层次就是/kobj->kset->list指向kobj->parent ->parent 指向kset->kobj     
  22.         kobj->parent = parent;    
  23.     }    
  24.     
  25.     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",    
  26.          kobject_name(kobj), kobj, __func__,    
  27.          parent ? kobject_name(parent) : "<NULL>",    
  28.          kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");    
  29.     
  30.     error = create_dir(kobj); //利用kobj创建目录和属性文件,其中会判断,如果parent为NULL那么就在sysfs_root下创建     
  31.     if (error) {  //如果创建失败。减少相关的引用计数    
  32.         kobj_kset_leave(kobj);    
  33.         kobject_put(parent);    
  34.         kobj->parent = NULL;    
  35.     
  36.         /* be noisy on error issues */    
  37.         if (error == -EEXIST)    
  38.             printk(KERN_ERR "%s failed for %s with "    
  39.                    "-EEXIST, don't try to register things with "    
  40.                    "the same name in the same directory.\n",    
  41.                    __func__, kobject_name(kobj));    
  42.         else    
  43.             printk(KERN_ERR "%s failed for %s (%d)\n",    
  44.                    __func__, kobject_name(kobj), error);    
  45.         dump_stack();    
  46.     } else    
  47.         kobj->state_in_sysfs = 1; //如果创建成功。将state_in_sysfs建为1。表示该object已经在sysfs中了    
  48.     
  49.     return error;    
  50. }   
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static int create_dir(struct kobject *kobj)    
  2. {    
  3.     int error = 0;    
  4.     if (kobject_name(kobj)) {    
  5.         error = sysfs_create_dir(kobj);//为kobject创建目录    
  6.         if (!error) {    
  7.             error = populate_dir(kobj);  //为kobject->ktype中的属性创建文件    
  8.             if (error)    
  9.                 sysfs_remove_dir(kobj);    
  10.         }    
  11.     }    
  12.     return error;    
  13. }  </span>  
我们先看一下kobject所表示的目录创建过程。这是在sysfs_create_dir()中完成的
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. int sysfs_create_dir(struct kobject * kobj)    
  2. {    
  3.     enum kobj_ns_type type;    
  4.     struct sysfs_dirent *parent_sd, *sd;    
  5.     const void *ns = NULL;    
  6.     int error = 0;    
  7.     
  8.     BUG_ON(!kobj);    
  9.     
  10.     /*  
  11.     如果kobject的parnet存在。就在目录点的目录下创建这个目录。  
  12.     如果没有父结点不存在,就在/sys下面创建结点  
  13.     */    
  14.     if (kobj->parent)    
  15.         parent_sd = kobj->parent->sd;    
  16.     else    
  17.         parent_sd = &sysfs_root;    
  18.     
  19.     if (sysfs_ns_type(parent_sd))    
  20.         ns = kobj->ktype->namespace(kobj);    
  21.     type = sysfs_read_ns_type(kobj);    
  22.     
  23.      //在sysfs中创建目录    
  24.     error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);    
  25.     if (!error)    
  26.         kobj->sd = sd;    
  27.     return error;    
  28. } </span>  
接着看为kobject->ktype中的属性创建文件。这是在populate_dir()中完成的
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static int populate_dir(struct kobject *kobj)    
  2. {    
  3.     struct kobj_type *t = get_ktype(kobj);    
  4.     struct attribute *attr;    
  5.     int error = 0;    
  6.     int i;    
  7.     
  8.     if (t && t->default_attrs) {    
  9.         for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {//遍历ktype中的属性,为其建立文    
  10.             error = sysfs_create_file(kobj, attr); //注意:文件的操作最后都会回溯到ktype->sysfs_ops的show和store这两个函数中.     
  11.             if (error)    
  12.                 break;    
  13.         }    
  14.     }    
  15.     return error;    
  16. }  
另外一个常用的函数就是kobject_init_and_add,直接初始化并进行添加操作

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,    
  2.              struct kobject *parent, const char *fmt, ...)    
  3. {    
  4.     va_list args;    
  5.     int retval;    
  6.     
  7.     kobject_init(kobj, ktype);    
  8.     
  9.     va_start(args, fmt);    
  10.     retval = kobject_add_varg(kobj, parent, fmt, args);    
  11.     va_end(args);    
  12.     
  13.     return retval;    
  14. }  
这里面调用的也就是init和add操作了。

还有一个kobj的删除函数:

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. void kobject_del(struct kobject *kobj)    
  2. {    
  3.     if (!kobj)    
  4.         return;    
  5.     
  6.     sysfs_remove_dir(kobj);//删除sys目录相关文件    
  7.     kobj->state_in_sysfs = 0;    
  8.     kobj_kset_leave(kobj);//kset链表中删除kobj成员    
  9.     kobject_put(kobj->parent);//减少parent计数    
  10.     kobj->parent = NULL;    
  11. }   


基于 linux2.6.32.2 的驱动

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include <linux/device.h>   
  2. #include <linux/module.h>   
  3. #include <linux/kernel.h>   
  4. #include <linux/init.h>   
  5. #include <linux/string.h>   
  6. #include <linux/sysfs.h>   
  7. #include <linux/stat.h>   
  8.     
  9. MODULE_AUTHOR("David Xie");   
  10. MODULE_LICENSE("Dual BSD/GPL");  
  11.   
  12. /*声明release、show、store函数*/  
  13.   
  14. void obj_test_release(struct kobject *kobject);   
  15. ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);  
  16. ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);  
  17.   
  18. /*对应于kobject的目录下的一个文件,Name成员就是文件名*/    
  19. struct attribute test_attr = {   
  20.     .name = "kobj_config",   
  21.     .mode = S_IRWXUGO,   
  22. };   
  23.     
  24. static struct attribute *def_attrs[] = {   
  25.     &test_attr,   
  26.     NULL,   
  27. };   
  28.     
  29. //kobject对象的操作   
  30. struct sysfs_ops obj_test_sysops =   
  31. {   
  32.     .show = kobj_test_show,   
  33.     .store = kobj_test_store,   
  34. };   
  35.    
  36. /*定义kobject对象的一些属性及对应的操作*/   
  37. struct kobj_type ktype =    
  38. {   
  39.     .release = obj_test_release,   
  40.     .sysfs_ops=&obj_test_sysops,   
  41.     .default_attrs=def_attrs,   
  42. };  
  43.   
  44. /*release方法释放该kobject对象*/    
  45. void obj_test_release(struct kobject *kobject)   
  46. {   
  47.     printk("eric_test: release .\n");   
  48. }  
  49.   
  50. /*当读文件时执行的操作*/   
  51. ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)  
  52. {   
  53.     printk("have show.\n");   
  54.     printk("attrname:%s.\n", attr->name);   
  55.     sprintf(buf,"%s\n",attr->name);   
  56.     return strlen(attr->name)+2;   
  57. }  
  58.   
  59. /*当写文件时执行的操作*/    
  60. ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)  
  61. {   
  62.     printk("havestore\n");   
  63.     printk("write: %s\n",buf);   
  64.     return count;   
  65. }   
  66.     
  67. struct kobject kobj;//声明kobject对象  
  68.    
  69. static int kobj_test_init(void)   
  70. {   
  71.     printk("kboject test init.\n");   
  72.     kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");//初始化kobject对象kobj,并将其注册到linux系统  
  73.     //kobject_init(&kobj);  
  74.     //kobj.ktype = &ktype;  
  75.     //kobj.parent = NULL;  
  76.     //kobject_set_name(&kobj, "kobject_test");  
  77.     //err = kobject_add(&kobj);  
  78.     return 0;   
  79. }   
  80.     
  81. static void kobj_test_exit(void)   
  82. {   
  83.     printk("kobject test exit.\n");   
  84.     kobject_del(&kobj);   
  85. }   
  86.     
  87. module_init(kobj_test_init);  
  88. module_exit(kobj_test_exit);  



原创粉丝点击