LDD3的第14章《Linux设备模型》一章节把Linux内核中的很多结构体串讲了一遍,满满的干货,非常值得一看,这里简单的笔记下代码注释吧。作者的语文实在太差,很多阅读心得不知道怎么笔记出来,还请各位高手勿喷~
kobject时Linux整个设备模型的基本结构体,其他更复杂的结构体通过包含kobject结构体的方式来使用kobject。由于Linux的设备模型基于树形结构,因此kobject也可以组成树形结构,这样,外部复杂的结构体也就可以组成树形结构了。另一方面,kobject又可以属于某个kset中,组成链表结构。
CONTENTS
\linux-2.6.11\include\linux\kobject.h
#define KOBJ_NAME_LEN 20 /* counter to tag the hotplug event, read only except for the kobject core */ extern u64 hotplug_seqnum; /* Linux驱动中的绝大多数结构体变量都是基于kobject,kobject类似于C++的基类, 但是Linux不用C++,因此,大多数结构体变量都是包含一个kobject,然后使用 containof方式来获取包围变量的指针。 */ struct kobject { char * k_name;/* k_name 指向kobject的名字,一般指向name, 但是如果名字的长度太长,超过name[]的存储,k_name会指向新申请的内存,而不是name*/ char name[KOBJ_NAME_LEN]; struct kref kref; /* 代表kobject的引用计数 */ struct list_head entry; /* kobject一般放在kset中,这里entry组成链表,放在kset下面 */ struct kobject * parent;/* kobject的父节点 */ struct kset * kset; /* kobject所属的kset */ struct kobj_type * ktype; /* kobject关联的kobj_type,存放了kobject的属性和释放方法 */ struct dentry * dentry; /* fs用 */ }; /* 设置kobject的名字*/ extern int kobject_set_name(struct kobject *, const char *, ...) __attribute__((format(printf,2,3))); /* 返回kobject的名字,注意这里返回的是【k_name 】,不是name[]*/ static inline char * kobject_name(struct kobject * kobj) { return kobj->k_name; } extern void kobject_init(struct kobject *); extern void kobject_cleanup(struct kobject *); extern int kobject_add(struct kobject *); extern void kobject_del(struct kobject *); extern int kobject_rename(struct kobject *, char *new_name); extern int kobject_register(struct kobject *); extern void kobject_unregister(struct kobject *); extern struct kobject * kobject_get(struct kobject *); extern void kobject_put(struct kobject *); extern char * kobject_get_path(struct kobject *, int); struct kobj_type { void (*release)(struct kobject *); struct sysfs_ops * sysfs_ops; struct attribute ** default_attrs; };
\linux-2.6.11\lib\kobject.c
/* * kobject.c - library routines for handling generic kernel objects * * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org> * * This file is released under the GPLv2. * * * Please see the file Documentation/kobject.txt for critical information * about using the kobject interface. */ #include <linux/kobject.h> #include <linux/string.h> #include <linux/module.h> #include <linux/stat.h> /** * populate_dir - populate directory with attributes. * @kobj: object we're working on. * * Most subsystems have a set of default attributes that * are associated with an object that registers with them. * This is a helper called during object registration that * loops through the default attributes of the subsystem * and creates attributes files for them in sysfs. * */ /* 根据kobj_type中包括的属性来在fs中生成文件 */ static int populate_dir(struct kobject * kobj) { /* 根据kobject获取其对应的kobj_type */ struct kobj_type * t = get_ktype(kobj); struct attribute * attr; int error = 0; int i; /* 遍历属性数组,然后在fs中创建对应的文件 */ /* 根据LDD3,default_atts[]的最后一个元素是NULL */ if (t && t->default_attrs) { for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) { if ((error = sysfs_create_file(kobj,attr))) break; } } return error; } /* 根据kobject的名称在fs里生成一个文件夹 */ static int create_dir(struct kobject * kobj) { int error = 0; if (kobject_name(kobj)) { error = sysfs_create_dir(kobj);/* 先生成一个文件夹 */ if (!error) { if ((error = populate_dir(kobj))) /* 然后根据属性生成文件 */ sysfs_remove_dir(kobj); } } return error; } /* 根据链表头返回对应的kobject */ static inline struct kobject * to_kobj(struct list_head * entry) { return container_of(entry,struct kobject,entry); } /* kobject可以组成树形关系,这里获取kobject到根的路径下的所有kobject的名字的长度。*/ static int get_kobj_path_length(struct kobject *kobj) { int length = 1; struct kobject * parent = kobj; /* walk up the ancestors until we hit the one pointing to the * root. * Add 1 to strlen for leading '/' of each level. */ do { length += strlen(kobject_name(parent)) + 1; parent = parent->parent;/* 不断向上遍历,直到顶部,即parent==null */ } while (parent); return length; } /* 和上面的函数一样,都是工具函数,都是用来帮助获取kobject到根的路径上的 所有的kobject的名字组成的字符串。 */ static void fill_kobj_path(struct kobject *kobj, char *path, int length) { struct kobject * parent; --length;/* 注意这里length是减小的 */ for (parent = kobj; parent; parent = parent->parent) { int cur = strlen(kobject_name(parent)); /* back up enough to print this name with '/' */ length -= cur;/* 注意这里length是减小的,即字符串拷贝是从后往前填充path的,这样也符合parent是向上遍历的逻辑 */ strncpy (path + length, kobject_name(parent), cur); *(path + --length) = '/'; } pr_debug("%s: path = '%s'\n",__FUNCTION__,path); } /** * kobject_get_path - generate and return the path associated with a given kobj * and kset pair. The result must be freed by the caller with kfree(). * * @kobj: kobject in question, with which to build the path * @gfp_mask: the allocation type used to allocate the path */ /* 获取kobject到根的路径上的所有的kobject的名字组成的字符串。 */ char *kobject_get_path(struct kobject *kobj, int gfp_mask) { char *path; int len; /* 先调用上面的工具函数获取字符串长度, 然后申请对应的内存*/ len = get_kobj_path_length(kobj); path = kmalloc(len, gfp_mask); if (!path) return NULL; memset(path, 0x00, len); fill_kobj_path(kobj, path, len); return path; } /** * kobject_init - initialize object. * @kobj: object in question. */ /* 初始化一个kobject */ void kobject_init(struct kobject * kobj) { kref_init(&kobj->kref);/* 初始化kobject的引用计数 */ INIT_LIST_HEAD(&kobj->entry);/* 初始化链表头 */ /* 如果传入的kobject 已经赋值了kset,那么就把对应的kset的做一次引用增加, 即表明kset被引用,防止kset引用计数减小时被过早的释放。 */ kobj->kset = kset_get(kobj->kset); } /** * unlink - remove kobject from kset list. * @kobj: kobject. * * Remove the kobject from the kset list and decrement * its parent's refcount. * This is separated out, so we can use it in both * kobject_del() and kobject_add() on error. */ /* 对kobject进行解除kset的连接 */ static void unlink(struct kobject * kobj) { /* 如果kobject之前放在了kset下面,那么就把它从链表中解除 */ if (kobj->kset) { down_write(&kobj->kset->subsys->rwsem); list_del_init(&kobj->entry); up_write(&kobj->kset->subsys->rwsem); /* 注意,这里并没有对kset清空,说明kobject还是保持着kset,作者感觉比较奇怪 */ } /* 对kobject进行引用计数减少,个人也感觉比较奇怪 */ kobject_put(kobj); } /** * kobject_add - add an object to the hierarchy. * @kobj: object. */ /* 讲kobject加入到某个树形中,注意这里的关系在调用函数之前已经设置了。 即kobject的kset和parent已经被赋值了。 */ int kobject_add(struct kobject * kobj) { int error = 0; struct kobject * parent; if (!(kobj = kobject_get(kobj)))/* 首先对kobject进行一次引用增加 */ return -ENOENT; if (!kobj->k_name) kobj->k_name = kobj->name; /* 更改下k_name */ parent = kobject_get(kobj->parent); /* 对kobject的parent进行一次引用增加 */ pr_debug("kobject %s: registering. parent: %s, set: %s\n", kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>", kobj->kset ? kobj->kset->kobj.name : "<NULL>" ); if (kobj->kset) { down_write(&kobj->kset->subsys->rwsem); /* 额外处理,如果kset被设置,parent没有被设置,那么kset就成为了看object的parent */ if (!parent) parent = kobject_get(&kobj->kset->kobj); list_add_tail(&kobj->entry,&kobj->kset->list);/* 如果设置了kset,就把kobject加入到kset的链表的末尾 */ up_write(&kobj->kset->subsys->rwsem); } kobj->parent = parent; /* 讲kobject的kset和parent设置好之后,就在fs里面创建目录 */ error = create_dir(kobj); if (error) { /* unlink does the kobject_put() for us */ unlink(kobj); if (parent) kobject_put(parent); } else { kobject_hotplug(kobj, KOBJ_ADD); } return error; } /** * kobject_register - initialize and add an object. * @kobj: object in question. */ /* 注册一个kobject。 */ int kobject_register(struct kobject * kobj) { int error = 0; if (kobj) { kobject_init(kobj); error = kobject_add(kobj); if (error) { printk("kobject_register failed for %s (%d)\n", kobject_name(kobj),error); dump_stack(); } } else error = -EINVAL; return error; } /** * kobject_set_name - Set the name of an object * @kobj: object. * @name: name. * * If strlen(name) >= KOBJ_NAME_LEN, then use a dynamically allocated * string that @kobj->k_name points to. Otherwise, use the static * @kobj->name array. */ /* 设置一个kobject的名称 ,如果名称长度大于KOBJ_NAME_LE, 就会额外的申请新的内存。 */ int kobject_set_name(struct kobject * kobj, const char * fmt, ...) { int error = 0; int limit = KOBJ_NAME_LEN; int need; va_list args; char * name; /* * First, try the static array */ va_start(args,fmt); need = vsnprintf(kobj->name,limit,fmt,args); va_end(args); if (need < limit) name = kobj->name; else { /* * Need more space? Allocate it and try again */ limit = need + 1; name = kmalloc(limit,GFP_KERNEL); if (!name) { error = -ENOMEM; goto Done; } va_start(args,fmt); need = vsnprintf(name,limit,fmt,args); va_end(args); /* Still? Give up. */ if (need >= limit) { kfree(name); error = -EFAULT; goto Done; } } /* Free the old name, if necessary. */ if (kobj->k_name && kobj->k_name != kobj->name) kfree(kobj->k_name); /* Now, set the new name */ kobj->k_name = name; Done: /* 函数结束时,k_name指向了kobject的名称,无论是内部存储还是申请的新的内存 */ return error; } EXPORT_SYMBOL(kobject_set_name); /** * kobject_rename - change the name of an object * @kobj: object in question. * @new_name: object's new name */ /* 重命名一个kobject,作者感觉这里有点问题,可能是特殊需求的定制的函数吧 */ int kobject_rename(struct kobject * kobj, char *new_name) { int error = 0; kobj = kobject_get(kobj); if (!kobj) return -EINVAL; error = sysfs_rename_dir(kobj, new_name); kobject_put(kobj); return error; } /** * kobject_del - unlink kobject from hierarchy. * @kobj: object. */ /* 删除一个kobject */ void kobject_del(struct kobject * kobj) { kobject_hotplug(kobj, KOBJ_REMOVE); sysfs_remove_dir(kobj);/* 从fs中删除 */ unlink(kobj); /* 解除kset的连接 */ } /** * kobject_unregister - remove object from hierarchy and decrement refcount. * @kobj: object going away. */ void kobject_unregister(struct kobject * kobj) { pr_debug("kobject %s: unregistering\n",kobject_name(kobj)); kobject_del(kobj); /* 先删除,在解除引用 */ kobject_put(kobj); /* 减少引用计数 */ } /** * kobject_get - increment refcount for object. * @kobj: object. */ /* 增加引用计数 */ struct kobject * kobject_get(struct kobject * kobj) { if (kobj) kref_get(&kobj->kref); return kobj; } /** * kobject_cleanup - free kobject resources. * @kobj: object. */ /*清除一个kobject ,这里是引用计数的清除函数*/ void kobject_cleanup(struct kobject * kobj) { struct kobj_type * t = get_ktype(kobj); struct kset * s = kobj->kset; struct kobject * parent = kobj->parent; pr_debug("kobject %s: cleaning up\n",kobject_name(kobj)); if (kobj->k_name != kobj->name) kfree(kobj->k_name); kobj->k_name = NULL; if (t && t->release) t->release(kobj); if (s) kset_put(s); if (parent) kobject_put(parent); } /* 同上,不过这里参数是kref,里面使用containof */ static void kobject_release(struct kref *kref) { kobject_cleanup(container_of(kref, struct kobject, kref)); } /** * kobject_put - decrement refcount for object. * @kobj: object. * * Decrement the refcount, and if 0, call kobject_cleanup(). */ /* 减少引用计数 */ void kobject_put(struct kobject * kobj) { if (kobj) kref_put(&kobj->kref, kobject_release); }
发表评论