1、 Kset
kset是具有相同类型的kobject的集合,在sysfs中体现成一个目录,在内核中用kset数据结构表示,定义为:
struct kset {
struct list_head list; //连接该kset中所有kobject的链表头
spinlock_t list_lock;
struct kobject kobj; //内嵌的kobject
struct kset_uevent_ops *uevent_ops; //处理热插拔事件的操作集合
}
2、 Kset操作
1)int kset_register(struct kset *kset)
在内核中注册一个kset
2)void kset_unregister(struct kset *kset)
从内核中注销一个kset
3、 热插拔事件
在Linux系统中,当系统配置发生变化时,如:添加kset到系统;移动kobject, 一个通知会从内核空间发送到用户空间,这就是热插拔事件。热插拔事件会导致用户空间中相应的处理程序(如udev,mdev)被调用, 这些处理程序会通过加载驱动程序, 创建设备节点等来响应热插拔事件。
4、热插拔事件操作集合
Struct kset_uevent_ops {
int (*filter)(struct kset *kset, struct kobject *kobj);
const char *(*name)(struct kset *kset, struct kobject *kobj);
int (*uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
}
kset_uevent_ops这三个函数什么时候调用?
当该kset所管理的kobject和kset状态发生变化时(如被加入,移动),这三个函数将被调用。(例:kobject_uevent调用)
这三个函数的功能是什么?
1)filter:决定是否将事件传递到用户空间。如果filter返回0,将不传递事件。(例: uevent_filter)
2)name:用于将字符串传递给用户空间的热插拔处理程序。
3)uevent:将用户空间需要的参数添加到环境变量中。(例:dev_uevent)
5、 kset实例分析
#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("yinjiabin"); MODULE_LICENSE("GPL"); struct kset *kset_p; struct kset kset_c; /* 函数声明 */ void obj_test_release(struct kobject *); ssize_t kobj_test_show(struct kobject *,struct attribute *,char *); ssize_t kobj_test_store(struct kobject *,struct attribute *,const char *,size_t); static struct attribute test_attr = { .name = "kobj_config", .mode = S_IRWXUGO, }; static struct attribute *def_attrs[] = { &test_attr, NULL, }; static struct sysfs_ops obj_test_sysops = { .show = kobj_test_show, .store = kobj_test_store, }; static struct kobj_type ktype = { .release = obj_test_release, .sysfs_ops = &obj_test_sysops, .default_attrs = def_attrs,}; void obj_test_release(struct kobject *kobject) { printk("[kobj_test: release!]\n"); } ssize_t kobj_test_show(struct kobject *kobject,struct attribute *attr,char *buf) { printk("Have show –>\n"); printk("attrname: %s.\n",attr->name); sprintf("buf,%s\n",attr->name); return strlen(attr->name) + 2; } ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr, const char *buf,size_t size) { printk("Have store –>\n"); printk("write: %s.\n",buf); return size; } static int kset_filter(struct kset *kset,struct kobject *kobj) { printk("Filter: kobj %s.\n",kobj->name); return 1; } static 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; } static int kset_uevent(struct kset *kset,struct kobject *kobj, struct kobj_uevent_env *env)
{ int i = 0; printk("uevent: kobj %s.\n",kobj->name); while(i < env->envp_idx) { printk("%s.\n",env->envp[i]); i ++; } return 0; } static struct kset_uevent_ops uevent_ops = { .filter = kset_filter, .name = kset_name, .uevent = kset_uevent, }; static int __init kset_test_init(void) { int ret = 0; printk("kset test init!\n"); /* 创建并注册 kset_p */ kset_p = kset_create_and_add("kset_p",&uevent_ops,NULL);
/* 添加 kset_c 到 kset_p */ kobject_set_name(&kset_c.kobj,"kset_c"); kset_c.kobj.kset = kset_p; /* 对于较新版本的内核,在注册 kset 之前,需要 * 填充 kset.kobj 的 ktype 成员,否则注册不会成功 */ kset_c.kobj.ktype = &ktype; ret = kset_register(&kset_c); if(ret) kset_unregister(kset_p); return 0; } static void __exit kset_test_exit(void) { printk("kset test exit!\n"); kset_unregister(kset_p); kset_unregister(&kset_c); } module_init(kset_test_init); module_exit(kset_test_exit);
人生,一场人喧鼓响的戏,我只是一个平凡的过客,