Linux的kobject机制

https://blog.csdn.net/younger_china/article/details/11180385


作者:Younger Liu,本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。 

sysfs文件系统下的每个目录对应于一个kobjksetkobj的封装,内嵌了一个kobj,其代表kset自身,ktype代表属性操作集,但由于通用性,因此把ktype单独剥离出来,kobjksetktype成为了各个驱动模型最底层的关联元素,并由此形成了sys下的各种拓扑结构。

1          kobjectkset,子系统层次结构

内核通常用kobject结构将各个对象连接起来组成一个分层的结构体系。

 

一个 kset是嵌入到相同类型结构的 kobject的集合。

struct kobj_type 关注的是对象的类型,而struct kset关心的是对象的集合,可认为ksetkobjects的顶层容器类。每个 kset 在内部包含自己的 kobject,并可以用多种处理kobject的方法处理kset kset总是在 sysfs中出现;一旦设置了 kset并把它添加到系统中,将在 sysfs 中创建一个目录;kobjects不必在 sysfs中表示kset中的每一个 kobject成员都在sysfs中得到表述。

 

2          如何实现sysfs接口

kobject 是在 sysfs虚拟文件系统后的机制。对每个在 sysfs中的目录,在内核中都会有一个 kobject与之对应。每个 kobject都输出一个或多个属性,它在 kobject  sysfs目录中以文件的形式出现,其中的内容由内核产生。

当创建kobject ,每个 kobject都被给定一系列默认属性。这些属性保存在 kobj_type结构中:

  1. struct kobj_type {
  2. void (*release)(struct kobject *);
  3. struct sysfs_ops *sysfs_ops; /*提供实现以下属性的方法*/
  4. struct attribute **default_attrs; /*用于保存类型属性列表(指针的指针) */
  5. };
  6. struct attribute {
  7. char *name; /*属性的名字( 在 kobject 的 sysfs 目录中显示)*/
  8. struct module *owner; /*指向模块的指针(如果有), 此模块负责实现这个属性*/
  9. mode_t mode; /*属性的保护位,modes 的宏定义在 <linux/stat.h>:例如S_IRUGO 为只读属性等等*/
  10. }; /*default_attrs 列表中的最后一个元素必须用 0 填充*/

sysfs 读写这些属性是由 kobj_type->sysfs_ops成员中的函数完成的:

  1. struct sysfs_ops {
  2. ssize_t (*show)(struct kobject *, struct attribute *, char *);
  3. ssize_t (*store)(struct kobject *,struct attribute *, const char *, size_t);
  4. const void *(* namespace)(struct kobject *, const struct attribute *);
  5. };

当用户空间读取一个属性时,内核会使用指向 kobject的指针(kobj)和正确的属性结构(*attr)来调用show方法,该方法将给定属性值编码进缓冲(buffer)(注意不要越界( PAGE_SIZE字节)),并返回实际数据长度。sysfs的约定要求每个属性应当包含一个可读值;若返回大量信息,需将它分为多个属性.

也可对所有 kobject关联的属性使用同一个 show方法,用传递到函数的 attr指针来判断所请求的属性。有的 show方法包含对属性名字的检查。有的show方法会将属性结构嵌入另一个结构,这个结构包含需要返回属性值的信息,这时可用container_of获得上层结构的指针以返回属性值的信息。

store 方法将存在缓冲(buffer)的数据( size为数据的长度,不能超过 PAGE_SIZE )解码并保存新值到属性(*attr,返回实际解码的字节数。store方法只在拥有属性的写权限时才能被调用。此时注意:接收来自用户空间的数据一定要验证其合法性。如果到数据不匹配,返回一个负的错误值。

3          案例

  1. /**********************************************
  2. * Author: [email protected]
  3. * File name: kset_sample.c
  4. * Description: kset example
  5. * Date: 2011-12-10
  6. *********************************************/
  7. #include <linux/kobject.h>
  8. #include <linux/string.h>
  9. #include <linux/sysfs.h>
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. /*
  14. * 将要创建的文件foo对应的kobj.
  15. */
  16. struct foo_obj {
  17. struct kobject kobj;
  18. int foo;
  19. int baz;
  20. int bar;
  21. };
  22. /* 通过域成员返回结构体的指针 */
  23. #define to_foo_obj(x) container_of(x, struct foo_obj, kobj)
  24. /* 属性 */
  25. struct foo_attribute {
  26. struct attribute attr;
  27. ssize_t (*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf);
  28. ssize_t (*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf, size_t count);
  29. };
  30. #define to_foo_attr(x) container_of(x, struct foo_attribute, attr)
  31. /*
  32. * 属性foo信息显示函数 (涉及文件目录foo/)
  33. */
  34. static ssize_t foo_attr_show(struct kobject *kobj,
  35. struct attribute *attr,
  36. char *buf)
  37. {
  38. struct foo_attribute *attribute;
  39. struct foo_obj *foo;
  40. attribute = to_foo_attr(attr);
  41. foo = to_foo_obj(kobj);
  42. if (!attribute->show)
  43. return -EIO;
  44. return attribute->show(foo, attribute, buf);
  45. }
  46. /*
  47. * 属性foo存储函数(涉及文件目录foo/) (when a value is written to a file.)
  48. */
  49. static ssize_t foo_attr_store(struct kobject *kobj,
  50. struct attribute *attr,
  51. const char *buf, size_t len)
  52. {
  53. struct foo_attribute *attribute;
  54. struct foo_obj *foo;
  55. attribute = to_foo_attr(attr);
  56. foo = to_foo_obj(kobj);
  57. if (!attribute->store)
  58. return -EIO;
  59. return attribute->store(foo, attribute, buf, len);
  60. }
  61. /*
  62. * foo的show/store列表
  63. */
  64. static const struct sysfs_ops foo_sysfs_ops = {
  65. .show = foo_attr_show,
  66. .store = foo_attr_store,
  67. };
  68. /*
  69. * The release function for our object. This is REQUIRED by the kernel to
  70. * have. We free the memory held in our object here.
  71. */
  72. static void foo_release(struct kobject *kobj)
  73. {
  74. struct foo_obj *foo;
  75. foo = to_foo_obj(kobj);
  76. kfree(foo);
  77. }
  78. /*
  79. * 当需要从foo文件中读取信息时,调用此函数
  80. */
  81. static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr,
  82. char *buf)
  83. {
  84. return sprintf(buf, "%d\n", foo_obj->foo);
  85. }
  86. /*
  87. * 当往foo文件写入信息时,调用此函数
  88. */
  89. static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr,
  90. const char *buf, size_t count)
  91. {
  92. sscanf(buf, "%du", &foo_obj->foo);
  93. return count;
  94. }
  95. static struct foo_attribute foo_attribute =
  96. __ATTR(foo, 0666, foo_show, foo_store);
  97. /*
  98. * foo_ktype的属性列表
  99. */
  100. static struct attribute *foo_default_attrs[] = {
  101. &foo_attribute.attr,
  102. NULL, /* need to NULL terminate the list of attributes */
  103. };
  104. /*
  105. * 定义kobj_type结构体
  106. * 指定sysfs_ops,release函数, 属性列表foo_default_attrs
  107. */
  108. static struct kobj_type foo_ktype = {
  109. .sysfs_ops = &foo_sysfs_ops,
  110. .release = foo_release,
  111. .default_attrs = foo_default_attrs,
  112. };
  113. static struct kset *example_kset;
  114. static struct foo_obj *foo_obj;
  115. static struct foo_obj *create_foo_obj(const char *name)
  116. {
  117. struct foo_obj *foo;
  118. int retval;
  119. /* allocate the memory for the whole object */
  120. foo = kzalloc( sizeof(*foo), GFP_KERNEL);
  121. if (!foo)
  122. return NULL;
  123. foo->kobj.kset = example_kset;
  124. /*
  125. * 初始化kobject数据结结构foo->lobj,
  126. * 即 在foo->kobj的层次组织kset中创建个名为name的文件foo/foo
  127. * 成功返回0
  128. */
  129. retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name);
  130. if (retval) {
  131. /* 减小kobj的引用计数 */
  132. kobject_put(&foo->kobj);
  133. return NULL;
  134. }
  135. /*
  136. * 发送 KOBJ_ADD / KOBJ_REMOVE 等事件
  137. * We are always responsible for sending the uevent that the kobject
  138. * was added to the system.
  139. */
  140. kobject_uevent(&foo->kobj, KOBJ_ADD);
  141. return foo;
  142. }
  143. static void destroy_foo_obj(struct foo_obj *foo)
  144. {
  145. /* 减小kobj的引用计数 */
  146. kobject_put(&foo->kobj);
  147. }
  148. static int __ init example_init(void)
  149. {
  150. /*
  151. * 动态地在kernel_kobj所对应的目录/sys/kernel/下创建一个目录kset_example
  152. * 并返回kset_example对应的kset
  153. */
  154. example_kset = kset_create_and_add( "kset_example", NULL, kernel_kobj);
  155. if (!example_kset)
  156. return -ENOMEM;
  157. foo_obj = create_foo_obj( "foo");
  158. if (!foo_obj)
  159. goto foo_error;
  160. return 0;
  161. foo_error:
  162. return -EINVAL;
  163. }
  164. static void __ exit example_exit(void)
  165. {
  166. destroy_foo_obj(foo_obj);
  167. kset_unregister(example_kset);
  168. }
  169. module_init(example_init);
  170. module_exit(example_exit);
  171. MODULE_LICENSE( "GPL");
  172. MODULE_AUTHOR( "Younger Liu <[email protected]>");
4          参考资料:
sysfs文件系统详解:http://blog.chinaunix.net/u1/55599/showart_1089096.html
sysfs.h源码详析:http://blog.chinaunix.net/u1/55599/showart_1091002.html
http://www.diybl.com/course/6_system/linux/Linuxjs/2008727/134055.html

猜你喜欢

转载自blog.csdn.net/xiaodingqq/article/details/80873530