内核对象kobject和sysfs(4)——kset分析


从狭义上来说,kset就是kobj的一个再封装而已。在封装之后,提供了针对kset之下所有kobj统一管理的一些方法。

我们还是从结构说起:

  1. 168 struct kset {
  2. 169 struct list_head list;
  3. 170 spinlock_t list_lock;
  4. 171 struct kobject kobj;
  5. 172 const struct kset_uevent_ops *uevent_ops;
  6. 173 };

由结构体看见,kset不过是内嵌了一个kobj,在此基础上额外提供了别的操作。在后面统一设备模型中,会讲到类设备就是采用这种方式进行操作的。

由于kset内嵌kobj,那么其操作方法必然和kobj类似。kset的初始化和注册函数合并成了一个函数:

  1. 810 int kset_register(struct kset *k)
  2. 811 {
  3. 812 int err;
  4. 813
  5. 814 if (!k)
  6. 815 return -EINVAL;
  7. 816
  8. 817 kset_init(k);
  9. 818 err = kobject_add_internal(&k->kobj);
  10. 819 if (err)
  11. 820 return err;
  12. 821 kobject_uevent(&k->kobj, KOBJ_ADD);
  13. 822 return 0;
  14. 823 }
  15. 824 EXPORT_SYMBOL(kset_register);
  16. 767 void kset_init(struct kset *k)
  17. 768 {
  18. 769 kobject_init_internal(&k->kobj);
  19. 770 INIT_LIST_HEAD(&k->list);
  20. 771 spin_lock_init(&k->list_lock);
  21. 772 }

可以看出来,在821行之前,kset的行为和kobj一模一样。kobj相关内容在上一篇有过详细分析,这里重点就变成了分析kset的额外部分。kobject_uevent最终调用kobject_uevent_env,这个函数旨在通过环境变量发送一个uevent事件。下面展开这个函数:

  1. 164 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
  2. 165 char *envp_ext[])
  3. 166 {
  4. 167 struct kobj_uevent_env *env;
  5. 168 const char *action_string = kobject_actions[action];
  6. 169 const char *devpath = NULL;
  7. 170 const char *subsystem;
  8. 171 struct kobject *top_kobj;
  9. 172 struct kset *kset;
  10. 173 const struct kset_uevent_ops *uevent_ops;
  11. 174 int i = 0;
  12. 175 int retval = 0;
  13. 176 #ifdef CONFIG_NET
  14. 177 struct uevent_sock *ue_sk;
  15. 178 #endif
  16. 179
  17. 180 pr_debug("kobject: '%s' (%p): %s\n",
  18. 181 kobject_name(kobj), kobj, __func__);
  19. 182
  20. 183 /* search the kset we belong to */
  21. 184 top_kobj = kobj;
  22. 185 while (!top_kobj->kset && top_kobj->parent)
  23. 186 top_kobj = top_kobj->parent;
  24. 187
  25. 188 if (!top_kobj->kset) {
  26. 189 pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
  27. 190 "without kset!\n", kobject_name(kobj), kobj,
  28. 191 __func__);
  29. 192 return -EINVAL;
  30. 193 }
  31. 194
  32. 195 kset = top_kobj->kset;
  33. 196 uevent_ops = kset->uevent_ops;
  34. 197
  35. 198 /* skip the event, if uevent_suppress is set*/
  36. 199 if (kobj->uevent_suppress) {
  37. 200 pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
  38. 201 "caused the event to drop!\n",
  39. 202 kobject_name(kobj), kobj, __func__);
  40. 203 return 0;
  41. 204 }
  42. 205 /* skip the event, if the filter returns zero. */
  43. 206 if (uevent_ops && uevent_ops->filter)
  44. 207 if (!uevent_ops->filter(kset, kobj)) {
  45. 208 pr_debug("kobject: '%s' (%p): %s: filter function "
  46. 209 "caused the event to drop!\n",
  47. 210 kobject_name(kobj), kobj, __func__);
  48. 211 return 0;
  49. 212 }
  50. 213
  51. 214 /* originating subsystem */
  52. 215 if (uevent_ops && uevent_ops->name)
  53. 216 subsystem = uevent_ops->name(kset, kobj);
  54. 217 else
  55. 218 subsystem = kobject_name(&kset->kobj);
  56. 219 if (!subsystem) {
  57. 220 pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
  58. 221 "event to drop!\n", kobject_name(kobj), kobj,
  59. 222 __func__);
  60. 223 return 0;
  61. 224 }
  62. 225
  63. 226 /* environment buffer */
  64. 227 env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
  65. 228 if (!env)
  66. 229 return -ENOMEM;
  67. 230
  68. 231 /* complete object path */
  69. 232 devpath = kobject_get_path(kobj, GFP_KERNEL);
  70. 233 if (!devpath) {
  71. 234 retval = -ENOENT;
  72. 235 goto exit;
  73. 236 }
  74. 237
  75. 238 /* default keys */
  76. 239 retval = add_uevent_var(env, "ACTION=%s", action_string);
  77. 240 if (retval)
  78. 241 goto exit;
  79. 242 retval = add_uevent_var(env, "DEVPATH=%s", devpath);
  80. 243 if (retval)
  81. 244 goto exit;
  82. 245 retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  83. 246 if (retval)
  84. 247 goto exit;
  85. 248
  86. 249 /* keys passed in from the caller */
  87. 250 if (envp_ext) {
  88. 251 for (i = 0; envp_ext[i]; i++) {
  89. 252 retval = add_uevent_var(env, "%s", envp_ext[i]);
  90. 253 if (retval)
  91. 254 goto exit;
  92. 255 }
  93. 256 }
  94. 257
  95. 258 /* let the kset specific function add its stuff */
  96. 259 if (uevent_ops && uevent_ops->uevent) {
  97. 260 retval = uevent_ops->uevent(kset, kobj, env);
  98. 261 if (retval) {
  99. 262 pr_debug("kobject: '%s' (%p): %s: uevent() returned "
  100. 263 "%d\n", kobject_name(kobj), kobj,
  101. 264 __func__, retval);
  102. 265 goto exit;
  103. 266 }
  104. 267 }
  105. 268
  106. 269 /*
  107. 270 * Mark "add" and "remove" events in the object to ensure proper
  108. 271 * events to userspace during automatic cleanup. If the object did
  109. 272 * send an "add" event, "remove" will automatically generated by
  110. 273 * the core, if not already done by the caller.
  111. 274 */
  112. 275 if (action == KOBJ_ADD)
  113. 276 kobj->state_add_uevent_sent = 1;
  114. 277 else if (action == KOBJ_REMOVE)
  115. 278 kobj->state_remove_uevent_sent = 1;
  116. 279
  117. 280 mutex_lock(&uevent_sock_mutex);
  118. 281 /* we will send an event, so request a new sequence number */
  119. 282 retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
  120. 283 if (retval) {
  121. 284 mutex_unlock(&uevent_sock_mutex);
  122. 285 goto exit;
  123. 286 }
  124. 355
  125. 356 exit:
  126. 357 kfree(devpath);
  127. 358 kfree(env);
  128. 359 return retval;
  129. 360 }

函数中删除了部分由宏定义控制的非关键代码。

185行的循环表示从当前的对象,一直向根查找,直到查找到某个内核对象包含有kset为止。我们先忽略kset内部嵌入的kobj,把kset和kobj看成是两个独立的类型。那么情况就变得简单了。即该代码假定,需要发送uevent事件,必须依赖于kset,如果本对象没有kset,那么就向上查找kset为止,这样的循环把kset下的所有内核模块,包括该内核模块下的内核模块也都包括在一个集合内。这种模型,也遵循就近选择kset的原则。

如上图所示的关系:

如果寻找kobj5的kset,将会找到kset2,如果寻找kobj3的kset,将会找到kset1.

简单的把kobj和kset看成两个独立的概念,问题迎刃而解。但是实际情况却是kset内嵌一个kobj,这又怎么理解呢?这就回到文章开始提到的,把kset当做是一种特殊的kobj。kset有自己的功能去实现,但是需要借用kobj与sysfs交互的功能以及kobj的层次关系建立起自己的下属成员。

在上述的循环里,还有一个问题。那就是,我们的这次发送uevent事件是在注册的时候发送的,那kset内部的kobj向上找,又能找到什么kset呢?其实,这个就开发者自己去赋值了。在调用kset_register之前,一定要对内嵌的内嵌的kobj的kset指向相应的kset。这样,关系就变成了下图:

在内核中,kset1一般指的是顶层的kset,没有kset类的父类,即不受管制,例如class、pci下的devices。因此,开发人员开发也是从kset2开始开发。当然,如果你希望开发出1个直接在sysfs目录下的kset,当然也可以。但是这时候,while循环将找不到对应的kset,将导致无法发送事件。发送事件错误在注册kset的过程中,不是致命的。毕竟,第一个kset无法向上发送事件,这很好理解。

而如果某个kobj的kset域不为空,将在kobject_add的时候,将自身的连接件链入kset中的head域。kset也是通过该头找到它所管理的所有的kobj,包括自身内嵌的那个kobj。

如果创建的是kset2。那么196行我们看到,kset2将继承kset1的操作方法。该数据结构展开如下:

  1. 132 struct kset_uevent_ops {
  2. 133 int (* const filter)(struct kset *kset, struct kobject *kobj);
  3. 134 const char *(* const name)(struct kset *kset, struct kobject *kobj);
  4. 135 int (* const uevent)(struct kset *kset, struct kobject *kobj,
  5. 136 struct kobj_uevent_env *env);
  6. 137 };
  7. 138

由此也可以推断,一个kset内实现的方法,是由其下级的内核模块或kset使用的。在之后,就由具体的上级实现的操作集合里的方法,辅助加以处理逻辑,这里不再赘述。

总结一下:kobj通过parent的逻辑关系,形成了sysfs内的层级分明的目录。kset利用内嵌的kobj也形成了自己在sysfs内的层级分明的目录。但是这并不是kset本身的父子关系。kset的作用是对集合内的其他kobj有统一管理的能力。于是,kset就通过内嵌的kobj内的kset指针指向来确定自己的父亲。如果为NULL,表示自己不受管理。

内核对象kobject和sysfs(4)——kset分析的更多相关文章

  1. 内核对象kobject和sysfs(3)——kobj分析

    内核对象kobject和sysfs(3)--kobj分析 在分析kobj之前,先总结下kobj的功能: 实现结构的动态管理: 实现内核对象到sysfs的映射: 实现自定义属性的管理. 关注一下kobj ...

  2. 内核对象kobject和sysfs(2)——kref分析

    内核对象kobject和sysfs(2)--kref分析 在介绍ref之前,先贴上kref的结构: struct kref { atomic_t refcount; }; 可以看到,kref只是包含一 ...

  3. 内核对象kobject和sysfs(1)——概述

    内核对象kobject和sysfs(1)--概述 问题: 在走读驱动代码时,经常看见kref,kobj,sysfs这些结构,这些结构到底有什么作用?如何理解并使用这些结构呢?这将在接下来的这一系列文章 ...

  4. sysfs - 用于导出内核对象(kobject)的文件系统

    sysfs - _The_ filesystem for exporting kernel objects.sysfs - 用于导出内核对象(kobject)的文件系统Patrick Mochel & ...

  5. [4]Windows内核情景分析---内核对象

    写过Windows应用程序的朋友都常常听说"内核对象"."句柄"等术语却无从得知他们的内核实现到底是怎样的, 本篇文章就揭开这些技术的神秘面纱. 常见的内核对象 ...

  6. linux设备驱动模型之Kobject、kobj_type、kset【转】

    本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74838165 版权声明:本文为博主原创文章,转载请注明http://blog.c ...

  7. Linux 内核文档翻译 - kobject.txt

    原文地址:Linux 内核文档翻译 - kobject.txt 作者:qh997 Everything you never wanted to know about kobjects, ksets, ...

  8. Linux内核文档翻译——kobject.txt

    ==================================================================== Everything you never wanted to ...

  9. 第9章 用内核对象进行线程同步(4)_死锁(DeadLock)及其他

    9.7 线程同步对象速查表 对象 何时处于未触发状态 何时处于触发状态 成功等待的副作用 进程 进程仍在运行的时候 进程终止的时(ExitProcess.TerminateProcess) 没有 线程 ...

随机推荐

  1. java面试笔试大汇总

    java面试笔试题大汇总5 JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象:2.继承:3.封装:4. 多态性: 2.String是最基本的数据类型吗? 基本数据类型包括byte.int. ...

  2. 总结·CSS3中定位模型之position属性的使用方法

    一.position元素介绍 position属性规定了元素的定位类型,通过定位,可准确地定义元素相对于其正常位置而应该出现的位置,或者是相对于父元素.另一元素和浏览器窗口等的位置. position ...

  3. SICP-Elements of program

    编程语言=组合简单形成复杂的工具 简单的声明和表达式 简单元素之间的组合方式 组合后元素的抽象方式 程序=数据+函数 数据是我们要处理的内容 函数是我们处理数据的方式 函数式与中缀式 函数式不会出现歧 ...

  4. vue中数据双向绑定注意点

    最近一个vue和element的项目中遇到了一个问题: 动态生成的对象进行双向绑定是失败 直接贴代码: <el-form :model="addClass" :rules=& ...

  5. memcache基础

    一.Memcache是一种缓存技术(内存),你可以把它想像成一张巨大的内存表,形式如下[它就是一个服务] key value key值(字符串) 可以放(字符串[二进制数据[视频.音频.图片]],数值 ...

  6. select onchagnge 弹出自己的文本值

    select onchagnge 弹出自己的文本值onchange='alert($("option:selected",this).text())'

  7. FFT/NTT 多项式学习笔记

    FFT(快速傅立叶变换)和NTT(快速数论变换)看上去很高端,真正搞懂了就很simple了辣. 首先给出多项式的一些定义(初中数学内容): 形如Σaixi的式子就是多项式! 多项式中每个单项式叫做多项 ...

  8. Android Shape Divider

    安卓框架提供了一种LinearLayout 内部布局元素分割线的实现,建立一个指定长宽的矩形Shape: <?xml version="1.0" encoding=" ...

  9. Dagger2在Android开发中的应用

    世界是普遍联系的,任何事物和个体都直接或间接相互依赖,在时空长河中共同发展.在面向对象的世界中,更是如此,类与类之间的依赖,关联关系,模块(亦或是分层架构中的层)之间的耦合关系,都是我们在软件开发实践 ...

  10. 最全的CSS浏览器兼容问题(转至http://68design.net/Web-Guide/HTMLCSS/37154-1.html)

    最全的CSS浏览器兼容问题   CSS对浏览器的兼容性有时让人很头疼,或许当你了解当中的技巧跟原理,就会觉得也不是难事,从网上收集了IE7,6与Fireofx的兼容性处理方法并整理了一下.对于web2 ...