内核对象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,表示自己不受管理。

posted @ 2017-07-30 21:06  自然技术搬运工  阅读(462)  评论(0编辑  收藏  举报