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

时间:2022-02-25 21:51:03

内核对象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的原则。

如上图所示的关系:内核对象kobject和sysfs(4)——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。这样,关系就变成了下图:内核对象kobject和sysfs(4)——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分析的更多相关文章

  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. 通过form上传文件(php)

    前段代码 <html> <head> <meta http-equiv="Content-Type" content="text/html; ...

  2. 2-2&period; Initializing Objects with Initializer Lists

    Using Uniform Initialization to Construct a vector #include <iostream> #include <vector> ...

  3. am等adb命令小总结

    本文的am部分参考了:http://www.cnblogs.com/dyllove98/archive/2013/07/08/3178094.html 的博客 今天研究adb的时候发现在pc端也可以启 ...

  4. AsyncTask源码分析

    在Android中,主线程是UI线程,当需要根据其他数据进行更新UI时,如果获取数据的操作比较耗时的话,会触发ANR,所以我们应该讲耗时的操作进行异步操作,尤其是请求网络数据的操作应该放在后台线程进行 ...

  5. SQL对字符串数组的处理详解

    原文地址:SQL字符串数组操作文章出处:DIY部落(http://www.diybl.com/course/7_databases/sql/sqlServer/2007106/76999.html) ...

  6. mysql 理解 int&lpar;11&rpar;

    1.这里的int(11) 与int的大小和存储字节,没有一毛钱关系,int的存储字节是4个字节,最大值为 65536*65536 = 40多亿,对于有符号的int,是20多亿.2.那么这里的(11) ...

  7. 添加和删除节点(HTML 元素)。

    JavaScript HTML DOM 元素(节点)   添加和删除节点(HTML 元素). 创建新的 HTML 元素 如需向 HTML DOM 添加新元素,您必须首先创建该元素(元素节点),然后向一 ...

  8. pyhton读取json格式的气象数据

    原文关于读取pm25.in气象数据的pyhton方法,以及浅析python json的应用 以pm25.in网站数据为例. 1.方法介绍 首先感谢pm25.in提供了优质的空气污染数据,为他们的辛勤劳 ...

  9. 【图片处理】cocos2dx png图片压缩处理

    一.介绍 美术用photoshop出图有时候会包含一些无用的信息,这时候image magick可以把这些信息裁掉. 二.使用方法 1.下载并安装Image Magick 2.将脚本里的目录名改成Im ...

  10. &lbrack;基础&rsqb; 重载的时候什么时候用引用&amp&semi;

    一般返回值还要继续被处理,而不仅仅是得到其值的时候,返回引用& 一般有[], =, ++, --, 还有输入输出运算符<<, >> Classtype &ope ...