内核对象kobject和sysfs(4)——kset分析
内核对象kobject和sysfs(4)——kset分析
从狭义上来说,kset就是kobj的一个再封装而已。在封装之后,提供了针对kset之下所有kobj统一管理的一些方法。
我们还是从结构说起:
168 struct kset {
169 struct list_head list;
170 spinlock_t list_lock;
171 struct kobject kobj;
172 const struct kset_uevent_ops *uevent_ops;
173 };
由结构体看见,kset不过是内嵌了一个kobj,在此基础上额外提供了别的操作。在后面统一设备模型中,会讲到类设备就是采用这种方式进行操作的。
由于kset内嵌kobj,那么其操作方法必然和kobj类似。kset的初始化和注册函数合并成了一个函数:
810 int kset_register(struct kset *k)
811 {
812 int err;
813
814 if (!k)
815 return -EINVAL;
816
817 kset_init(k);
818 err = kobject_add_internal(&k->kobj);
819 if (err)
820 return err;
821 kobject_uevent(&k->kobj, KOBJ_ADD);
822 return 0;
823 }
824 EXPORT_SYMBOL(kset_register);
767 void kset_init(struct kset *k)
768 {
769 kobject_init_internal(&k->kobj);
770 INIT_LIST_HEAD(&k->list);
771 spin_lock_init(&k->list_lock);
772 }
可以看出来,在821行之前,kset的行为和kobj一模一样。kobj相关内容在上一篇有过详细分析,这里重点就变成了分析kset的额外部分。kobject_uevent最终调用kobject_uevent_env,这个函数旨在通过环境变量发送一个uevent事件。下面展开这个函数:
164 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
165 char *envp_ext[])
166 {
167 struct kobj_uevent_env *env;
168 const char *action_string = kobject_actions[action];
169 const char *devpath = NULL;
170 const char *subsystem;
171 struct kobject *top_kobj;
172 struct kset *kset;
173 const struct kset_uevent_ops *uevent_ops;
174 int i = 0;
175 int retval = 0;
176 #ifdef CONFIG_NET
177 struct uevent_sock *ue_sk;
178 #endif
179
180 pr_debug("kobject: '%s' (%p): %s\n",
181 kobject_name(kobj), kobj, __func__);
182
183 /* search the kset we belong to */
184 top_kobj = kobj;
185 while (!top_kobj->kset && top_kobj->parent)
186 top_kobj = top_kobj->parent;
187
188 if (!top_kobj->kset) {
189 pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
190 "without kset!\n", kobject_name(kobj), kobj,
191 __func__);
192 return -EINVAL;
193 }
194
195 kset = top_kobj->kset;
196 uevent_ops = kset->uevent_ops;
197
198 /* skip the event, if uevent_suppress is set*/
199 if (kobj->uevent_suppress) {
200 pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
201 "caused the event to drop!\n",
202 kobject_name(kobj), kobj, __func__);
203 return 0;
204 }
205 /* skip the event, if the filter returns zero. */
206 if (uevent_ops && uevent_ops->filter)
207 if (!uevent_ops->filter(kset, kobj)) {
208 pr_debug("kobject: '%s' (%p): %s: filter function "
209 "caused the event to drop!\n",
210 kobject_name(kobj), kobj, __func__);
211 return 0;
212 }
213
214 /* originating subsystem */
215 if (uevent_ops && uevent_ops->name)
216 subsystem = uevent_ops->name(kset, kobj);
217 else
218 subsystem = kobject_name(&kset->kobj);
219 if (!subsystem) {
220 pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
221 "event to drop!\n", kobject_name(kobj), kobj,
222 __func__);
223 return 0;
224 }
225
226 /* environment buffer */
227 env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
228 if (!env)
229 return -ENOMEM;
230
231 /* complete object path */
232 devpath = kobject_get_path(kobj, GFP_KERNEL);
233 if (!devpath) {
234 retval = -ENOENT;
235 goto exit;
236 }
237
238 /* default keys */
239 retval = add_uevent_var(env, "ACTION=%s", action_string);
240 if (retval)
241 goto exit;
242 retval = add_uevent_var(env, "DEVPATH=%s", devpath);
243 if (retval)
244 goto exit;
245 retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
246 if (retval)
247 goto exit;
248
249 /* keys passed in from the caller */
250 if (envp_ext) {
251 for (i = 0; envp_ext[i]; i++) {
252 retval = add_uevent_var(env, "%s", envp_ext[i]);
253 if (retval)
254 goto exit;
255 }
256 }
257
258 /* let the kset specific function add its stuff */
259 if (uevent_ops && uevent_ops->uevent) {
260 retval = uevent_ops->uevent(kset, kobj, env);
261 if (retval) {
262 pr_debug("kobject: '%s' (%p): %s: uevent() returned "
263 "%d\n", kobject_name(kobj), kobj,
264 __func__, retval);
265 goto exit;
266 }
267 }
268
269 /*
270 * Mark "add" and "remove" events in the object to ensure proper
271 * events to userspace during automatic cleanup. If the object did
272 * send an "add" event, "remove" will automatically generated by
273 * the core, if not already done by the caller.
274 */
275 if (action == KOBJ_ADD)
276 kobj->state_add_uevent_sent = 1;
277 else if (action == KOBJ_REMOVE)
278 kobj->state_remove_uevent_sent = 1;
279
280 mutex_lock(&uevent_sock_mutex);
281 /* we will send an event, so request a new sequence number */
282 retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
283 if (retval) {
284 mutex_unlock(&uevent_sock_mutex);
285 goto exit;
286 }
355
356 exit:
357 kfree(devpath);
358 kfree(env);
359 return retval;
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的操作方法。该数据结构展开如下:
132 struct kset_uevent_ops {
133 int (* const filter)(struct kset *kset, struct kobject *kobj);
134 const char *(* const name)(struct kset *kset, struct kobject *kobj);
135 int (* const uevent)(struct kset *kset, struct kobject *kobj,
136 struct kobj_uevent_env *env);
137 };
138
由此也可以推断,一个kset内实现的方法,是由其下级的内核模块或kset使用的。在之后,就由具体的上级实现的操作集合里的方法,辅助加以处理逻辑,这里不再赘述。
总结一下:kobj通过parent的逻辑关系,形成了sysfs内的层级分明的目录。kset利用内嵌的kobj也形成了自己在sysfs内的层级分明的目录。但是这并不是kset本身的父子关系。kset的作用是对集合内的其他kobj有统一管理的能力。于是,kset就通过内嵌的kobj内的kset指针指向来确定自己的父亲。如果为NULL,表示自己不受管理。
内核对象kobject和sysfs(4)——kset分析的更多相关文章
- 内核对象kobject和sysfs(3)——kobj分析
内核对象kobject和sysfs(3)--kobj分析 在分析kobj之前,先总结下kobj的功能: 实现结构的动态管理: 实现内核对象到sysfs的映射: 实现自定义属性的管理. 关注一下kobj ...
- 内核对象kobject和sysfs(2)——kref分析
内核对象kobject和sysfs(2)--kref分析 在介绍ref之前,先贴上kref的结构: struct kref { atomic_t refcount; }; 可以看到,kref只是包含一 ...
- 内核对象kobject和sysfs(1)——概述
内核对象kobject和sysfs(1)--概述 问题: 在走读驱动代码时,经常看见kref,kobj,sysfs这些结构,这些结构到底有什么作用?如何理解并使用这些结构呢?这将在接下来的这一系列文章 ...
- sysfs - 用于导出内核对象(kobject)的文件系统
sysfs - _The_ filesystem for exporting kernel objects.sysfs - 用于导出内核对象(kobject)的文件系统Patrick Mochel & ...
- [4]Windows内核情景分析---内核对象
写过Windows应用程序的朋友都常常听说"内核对象"."句柄"等术语却无从得知他们的内核实现到底是怎样的, 本篇文章就揭开这些技术的神秘面纱. 常见的内核对象 ...
- linux设备驱动模型之Kobject、kobj_type、kset【转】
本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74838165 版权声明:本文为博主原创文章,转载请注明http://blog.c ...
- Linux 内核文档翻译 - kobject.txt
原文地址:Linux 内核文档翻译 - kobject.txt 作者:qh997 Everything you never wanted to know about kobjects, ksets, ...
- Linux内核文档翻译——kobject.txt
==================================================================== Everything you never wanted to ...
- 第9章 用内核对象进行线程同步(4)_死锁(DeadLock)及其他
9.7 线程同步对象速查表 对象 何时处于未触发状态 何时处于触发状态 成功等待的副作用 进程 进程仍在运行的时候 进程终止的时(ExitProcess.TerminateProcess) 没有 线程 ...
随机推荐
- java面试笔试大汇总
java面试笔试题大汇总5 JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象:2.继承:3.封装:4. 多态性: 2.String是最基本的数据类型吗? 基本数据类型包括byte.int. ...
- 总结·CSS3中定位模型之position属性的使用方法
一.position元素介绍 position属性规定了元素的定位类型,通过定位,可准确地定义元素相对于其正常位置而应该出现的位置,或者是相对于父元素.另一元素和浏览器窗口等的位置. position ...
- SICP-Elements of program
编程语言=组合简单形成复杂的工具 简单的声明和表达式 简单元素之间的组合方式 组合后元素的抽象方式 程序=数据+函数 数据是我们要处理的内容 函数是我们处理数据的方式 函数式与中缀式 函数式不会出现歧 ...
- vue中数据双向绑定注意点
最近一个vue和element的项目中遇到了一个问题: 动态生成的对象进行双向绑定是失败 直接贴代码: <el-form :model="addClass" :rules=& ...
- memcache基础
一.Memcache是一种缓存技术(内存),你可以把它想像成一张巨大的内存表,形式如下[它就是一个服务] key value key值(字符串) 可以放(字符串[二进制数据[视频.音频.图片]],数值 ...
- select onchagnge 弹出自己的文本值
select onchagnge 弹出自己的文本值onchange='alert($("option:selected",this).text())'
- FFT/NTT 多项式学习笔记
FFT(快速傅立叶变换)和NTT(快速数论变换)看上去很高端,真正搞懂了就很simple了辣. 首先给出多项式的一些定义(初中数学内容): 形如Σaixi的式子就是多项式! 多项式中每个单项式叫做多项 ...
- Android Shape Divider
安卓框架提供了一种LinearLayout 内部布局元素分割线的实现,建立一个指定长宽的矩形Shape: <?xml version="1.0" encoding=" ...
- Dagger2在Android开发中的应用
世界是普遍联系的,任何事物和个体都直接或间接相互依赖,在时空长河中共同发展.在面向对象的世界中,更是如此,类与类之间的依赖,关联关系,模块(亦或是分层架构中的层)之间的耦合关系,都是我们在软件开发实践 ...
- 最全的CSS浏览器兼容问题(转至http://68design.net/Web-Guide/HTMLCSS/37154-1.html)
最全的CSS浏览器兼容问题 CSS对浏览器的兼容性有时让人很头疼,或许当你了解当中的技巧跟原理,就会觉得也不是难事,从网上收集了IE7,6与Fireofx的兼容性处理方法并整理了一下.对于web2 ...