- 此文写作过程参考了几个大牛的博客,他们分别是
- Tekkaman:http://blog.chinaunix.net/space.php?uid=20543672&do=blog&id=94312
- 《Linux那些事儿 之 我是Sysfs》:http://blog.csdn.net/fudan_abc/article/details/1768277
- http://hi.baidu.com/csdeny/blog/item/5a4f14f342d30dca0a46e038.html
- 还有国嵌的实验代码,对我理解kobject帮助很大,一并表示感谢
![](http://blog.chinaunix.net/blog/image/editor/hou/15.gif)
- # ls /sys
- block class firmware vendor
- bus devices kernel module
- #
- struct kobject {
- const char * k_name;/*kobject 的名字数组(sysfs 入口使用的名字)指针;如果名字数组大小小于KOBJ_NAME_LEN,它指向本数组的name,否则指向另外分配的一个名字数组空间 */
- char name[KOBJ_NAME_LEN];/*kobject 的名字数组,若名字数组大小不小于KOBJ_NAME_LEN,只储存前KOBJ_NAME_LEN个字符*/
- struct kref kref;/*kobject 的引用计数*/
- struct list_head entry;/*kobject 之间的双向链表,与所属的kset形成环形链表*/
- struct kobject * parent;/*在sysfs分层结构中定位对象,指向上一级kset中的struct kobject kobj*/
- struct kset * kset;/*指向所属的kset*/
- struct kobj_type * ktype;/*负责对该kobject类型进行跟踪的struct kobj_type的指针*/
- struct dentry * dentry;/*sysfs文件系统中与该对象对应的文件节点路径指针*/
- wait_queue_head_t poll;/*等待队列头*/
- };
- void kobject_init(struct kobject *kobj, struct kobj_type *ktype)/*初始化kobject结构*/
- int kobject_add(struct kobject *kobj, struct kobject *parent,const char *fmt, ...)//将kobject对象注册到Linux系统
- int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,struct kobject *parent, const char *fmt, ...)
- /*初始化kobject,并将其注册到Linux系统,手头实验平台是2.6.10的代码,注册用kobject_register(),基本过程是一样的*/
- int kobject_set_name(struct kobject *kobj, const char *fmt, ...)//设置kobject目录名字
- void kobject_del(struct kobject *kobj)/*从Linux系统中删除kobj对象*/
- struct kobject *kobject_get(struct kobject *kobj)
- //将kobject对象的引用计数加1,同时返回该对象指针
- void kobject_put(struct kobject *kobj)
- //将kobject对象的引用计数减1,如果引用计数为0,则调用release方法释放该kobject对象。
- struct kobj_type {
- void (*release)(struct kobject *kobj);
- struct sysfs_ops *sysfs_ops;
- struct attribute **default_attrs;
- };
- struct attribute {
- const char *name;
- struct module *owner;
- mode_t mode;
- };
- struct sysfs_ops {
- ssize_t (*show)(struct kobject *, struct attribute *,char *buf);
- ssize_t (*store)(struct kobject *,struct attribute *,const char *buf, size_t);
- };
![](/blog/image/attachicons/rar.gif)
- struct kset {
- struct kobj_type * ktype; /*指向该kset对象类型的指针*/
- struct list_head list;/*用于连接该kset中所有kobject以形成环形链表的链表头*/
- spinlock_t list_lock;/*用于避免竞态的自旋锁*/
- struct kobject kobj; /*嵌入的kobject*/
- struct kset_uevent_ops * uevent_ops;
- /*处理热插拔时间的集合*/
- };
- void kset_init(struct kset *kset);
- int kset_add(struct kset *kset);
- int kset_register(struct kset *kset);
- void kset_unregister(struct kset *kset);
-
- /*管理 ksets 的引用计数:*/
- struct kset *kset_get(struct kset *kset);
- void kset_put(struct kset *kset);
-
- /* kset 也有一个名字,存储于嵌入的 kobject,因此设置它的名字用:*/
- kobject_set_name(&my_set->kobj, "The name");
struct kset_uevent_ops { |
可以在 kset 结构的uevent_ops 成员中找到指向kset_uevent_ops结构的指针。
若在 kobject 中不包含指定的 kset , 内核将通过 parent 指针在分层结构中进行搜索,直到发现一个包含有kset的 kobject ; 接着使用这个 kset 的热插拔操作。当kset管理的kobject和kset发生变化时,这三个方法被调用。
(1) filter 函数让 kset 代码决定是否将事件传递给用户空间。如果 filter 返回 0,将不产生事件。以磁盘的 filter 函数为例,它只允许kobject产生磁盘和分区的事件,源码如下:
static int block_hotplug_filter(struct kset *kset, struct kobject *kobj) |
(2) 当调用用户空间的热插拔程序时,相关子系统的名字将作为唯一的参数传递给它。name 函数负责返回合适的字符串传递给用户空间的热插拔程序。
(3)热插拔脚本想得到的任何其他参数都通过环境变量传递。uevent 函数的作用是在调用热插拔脚本之前将参数添加到环境变量中。函数原型:
int (*uevent)(struct kset *kset, struct kobject *kobj, /*产生事件的目标对象*/ |
- #include <linux/device.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/string.h>
- #include <linux/sysfs.h>
- #include <linux/stat.h>
- #include <linux/kobject.h>
-
- MODULE_AUTHOR("David Xie");
- MODULE_LICENSE("Dual BSD/GPL");
-
- struct kset * kset_p;
- struct kset * kset_c;
-
- int kset_filter(struct kset *kset, struct kobject *kobj)
- {
- printk("Filter: kobj %s.\n",kobj->name);
- return 1;
- }
-
- const char *kset_name(struct kset *kset, struct kobject *kobj)
- {
- static char buf[20];
- printk("Name: kobj %s.\n",kobj->name);
- sprintf(buf,"%s","kset_name");
- return buf;
- }
-
- int kset_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
- {
- //int i = 0;
- printk("uevent: kobj %s.\n",kobj->name);
- #if 0
- while( i < env->envp_idx){
- printk("%s.\n",env->envp[i]);
- i++;
- }
- #endif
- return 0;
- }
-
- struct kset_uevent_ops uevent_ops =
- {
- .filter = kset_filter,
- .name = kset_name,
- .uevent = kset_uevent,
- };
-
- int kset_test_init()
- {
- printk("kset test init.\n");
- kset_p = kzalloc(sizeof(struct kset), GFP_KERNEL);
- kset_c = kzalloc(sizeof(struct kset), GFP_KERNEL);
-
- kobject_set_name(&kset_p->kobj,"kset_p");
- kset_p->uevent_ops = &uevent_ops;
- kset_register(kset_p);
-
- kobject_set_name(&kset_c->kobj,"kset_c");
- kset_c->kobj.kset = kset_p;
- kset_register(kset_c);
- return 0;
- }
-
- int kset_test_exit()
- {
- printk("kset test exit.\n");
- kset_unregister(&kset_p);
- kset_unregister(&kset_c);
-
- kfree(kset_p);
- kfree(kset_c);
- return 0;
- }
-
- module_init(kset_test_init);
- module_exit(kset_test_exit);