作者:刘昊昱
博客:http://blog.csdn.net/liuhaoyutz
内核版本:2.6.36
上一篇博客我们分析了Linux设备模型中kobject的注册和使用,在这一篇文章中,我们来看一下kset的用法。
首先我们看一个使用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> MODULE_AUTHOR("haoyu"); MODULE_LICENSE("Dual BSD/GPL"); struct my_kobject { int value; struct kobject kobj; }; struct my_kobject my_kobj; void kobject_release(struct kobject *kobject); ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf); ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count); struct attribute kobject_attr1 = { .name = "name", .mode = S_IRWXUGO, }; struct attribute kobject_attr2 = { .name = "value", .mode = S_IRWXUGO, }; static struct attribute *kobject_def_attrs[] = { &kobject_attr1, &kobject_attr2, NULL, }; struct sysfs_ops kobject_sysfs_ops = { .show = kobject_attr_show, .store = kobject_attr_store, }; struct kobj_type ktype = { .release = kobject_release, .sysfs_ops = &kobject_sysfs_ops, .default_attrs = kobject_def_attrs, }; void kobject_release(struct kobject *kobject) { printk("kobject release.\n"); } ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf) { int count = 0; struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj); printk("kobject attribute show.\n"); if(strcmp(attr->name, "name") == 0) count = sprintf(buf, "%s\n", kobject->name); else if(strcmp(attr->name, "value") == 0) count = sprintf(buf, "%d\n", my_kobj->value); else printk("no this attribute.\n"); return count; } ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count) { int val; struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj); printk("kobject attribute store.\n"); if(strcmp(attr->name, "name") == 0) printk("Can not change name.\n"); else if(strcmp(attr->name, "value") == 0) { val = buf[0] - '0'; if(val == 0 || val == 1) my_kobj->value = val; else printk("value is '0' or '1'\n"); } else printk("no this attribute.\n"); return count; } int kset_filter(struct kset *kset, struct kobject *kobj) { printk("UEVENT: filter. kobj %s.\n",kobj->name); return 1; } const char *kset_name(struct kset *kset, struct kobject *kobj) { static char buf[20]; printk("UEVENT: name. kobj %s.\n",kobj->name); sprintf(buf,"%s","kset_test"); return buf; } int kset_uevent(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env) { int i = 0; printk("UEVENT: uevent. kobj %s.\n",kobj->name); while( i< env->envp_idx){ printk("%s.\n",env->envp[i]); i++; } return 0; } struct kset_uevent_ops uevent_ops = { .filter = kset_filter, .name = kset_name, .uevent = kset_uevent, }; struct kset *kset_parent; struct kset kset_child; static int kset_test_init(void) { printk("kboject test init.\n"); kset_parent = kset_create_and_add("kset_parent", &uevent_ops, NULL); my_kobj.kobj.kset = kset_parent; kobject_init_and_add(&my_kobj.kobj,&ktype,NULL,"kobject_test"); kobject_set_name(&kset_child.kobj,"kset_child"); kset_child.kobj.kset = kset_parent; kset_register(&kset_child); return 0; } static void kset_test_exit(void) { printk("kobject test exit.\n"); kobject_del(&my_kobj.kobj); kset_unregister(kset_parent); kset_unregister(&kset_child); } module_init(kset_test_init); module_exit(kset_test_exit);
该模块执行结果如下图所示:
kset的注册使用kset_create_and_add函数,该函数定义如下:
820/** 821 * kset_create_and_add - create a struct kset dynamically and add it to sysfs 822 * 823 * @name: the name for the kset 824 * @uevent_ops: a struct kset_uevent_ops for the kset 825 * @parent_kobj: the parent kobject of this kset, if any. 826 * 827 * This function creates a kset structure dynamically and registers it 828 * with sysfs. When you are finished with this structure, call 829 * kset_unregister() and the structure will be dynamically freed when it 830 * is no longer being used. 831 * 832 * If the kset was not able to be created, NULL will be returned. 833 */ 834struct kset *kset_create_and_add(const char *name, 835 const struct kset_uevent_ops *uevent_ops, 836 struct kobject *parent_kobj) 837{ 838 struct kset *kset; 839 int error; 840 841 kset = kset_create(name, uevent_ops, parent_kobj); 842 if (!kset) 843 return NULL; 844 error = kset_register(kset); 845 if (error) { 846 kfree(kset); 847 return NULL; 848 } 849 return kset; 850}
该函数首先调用kset_create创建kset,然后调用kset_register将kset注册到系统中。
先来看kset_create函数是如何创建kset的,该函数定义如下:
776/** 777 * kset_create - create a struct kset dynamically 778 * 779 * @name: the name for the kset 780 * @uevent_ops: a struct kset_uevent_ops for the kset 781 * @parent_kobj: the parent kobject of this kset, if any. 782 * 783 * This function creates a kset structure dynamically. This structure can 784 * then be registered with the system and show up in sysfs with a call to 785 * kset_register(). When you are finished with this structure, if 786 * kset_register() has been called, call kset_unregister() and the 787 * structure will be dynamically freed when it is no longer being used. 788 * 789 * If the kset was not able to be created, NULL will be returned. 790 */ 791static struct kset *kset_create(const char *name, 792 const struct kset_uevent_ops *uevent_ops, 793 struct kobject *parent_kobj) 794{ 795 struct kset *kset; 796 int retval; 797 798 kset = kzalloc(sizeof(*kset), GFP_KERNEL); 799 if (!kset) 800 return NULL; 801 retval = kobject_set_name(&kset->kobj, name); 802 if (retval) { 803 kfree(kset); 804 return NULL; 805 } 806 kset->uevent_ops = uevent_ops; 807 kset->kobj.parent = parent_kobj; 808 809 /* 810 * The kobject of this kset will have a type of kset_ktype and belong to 811 * no kset itself. That way we can properly free it when it is 812 * finished being used. 813 */ 814 kset->kobj.ktype = &kset_ktype; 815 kset->kobj.kset = NULL; 816 817 return kset; 818}
798行,为kset分配空间。
801行,设置kset->kobj的名字,代表该kset的名字。
806行,设置kset->uevent_ops。
807行,设置kset->kobj.parent。
814行,将kset->kobj.ktype设置为&kset_ktype。kset_ktype我们在下面介绍。
815行,将kset->kobj.kset设置为NULL,即该kset不属于任何kset。
kset_ktype的定义如下:
771static struct kobj_type kset_ktype = { 772 .sysfs_ops = &kobj_sysfs_ops, 773 .release = kset_release, 774};
为了分析方便,我们先来看kset_release的定义:
763static void kset_release(struct kobject *kobj) 764{ 765 struct kset *kset = container_of(kobj, struct kset, kobj); 766 pr_debug("kobject: '%s' (%p): %s\n", 767 kobject_name(kobj), kobj, __func__); 768 kfree(kset); 769}
这个函数取得kset空间指针并释放内存空间。
再来看kobj_sysfs_ops的定义,注意其作用,当用户读写kset->kobj的属性文件时,就会调用kset->kobj.ktype.sysfs_ops的show和store函数,即kobj_sysfs_ops的show和store函数:
703const struct sysfs_ops kobj_sysfs_ops = { 704 .show = kobj_attr_show, 705 .store = kobj_attr_store, 706};
kobj_attr_show函数定义如下:
678/* default kobject attribute operations */ 679static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr, 680 char *buf) 681{ 682 struct kobj_attribute *kattr; 683 ssize_t ret = -EIO; 684 685 kattr = container_of(attr, struct kobj_attribute, attr); 686 if (kattr->show) 687 ret = kattr->show(kobj, kattr, buf); 688 return ret; 689}
该函数首先通过container_of宏取得包含指定attribute的kobj_attribute,然后调用kobj_attribute的show函数。
kobj_attr_store函数定义如下:
691static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, 692 const char *buf, size_t count) 693{ 694 struct kobj_attribute *kattr; 695 ssize_t ret = -EIO; 696 697 kattr = container_of(attr, struct kobj_attribute, attr); 698 if (kattr->store) 699 ret = kattr->store(kobj, kattr, buf, count); 700 return ret; 701}
该函数首先通过container_of宏取得包含指定attribute的kobj_attribute,然后调用kobj_attribute的store函数。
至此,kset_create函数我们就分析完了,回到kset_create_and_add函数中,下面我们要分析的是kset_register函数,该函数定义如下:
708/** 709 * kset_register - initialize and add a kset. 710 * @k: kset. 711 */ 712int kset_register(struct kset *k) 713{ 714 int err; 715 716 if (!k) 717 return -EINVAL; 718 719 kset_init(k); 720 err = kobject_add_internal(&k->kobj); 721 if (err) 722 return err; 723 kobject_uevent(&k->kobj, KOBJ_ADD); 724 return 0; 725}
719行,调用kset_init初始化kset。
720行,调用kobject_add_internal将kobject注册到系统中,在/sys下建立目录结构和属性文件。该函数我们在前一篇博客<<Linux设备模型之kobject>>已经分析过,这里不再详细分析。
723行,调用kobject_uevent函数发送KOBJ_ADD事件。
667/** 668 * kset_init - initialize a kset for use 669 * @k: kset 670 */ 671void kset_init(struct kset *k) 672{ 673 kobject_init_internal(&k->kobj); 674 INIT_LIST_HEAD(&k->list); 675 spin_lock_init(&k->list_lock); 676}
673行,调用kobject_init_internal初始化kset->kobj。这个函数我们在上一篇博客<<Linux设备模型之kobject>>中已经分析过了。
kobject_uevent函数定义如下:
319/** 320 * kobject_uevent - notify userspace by sending an uevent 321 * 322 * @action: action that is happening 323 * @kobj: struct kobject that the action is happening to 324 * 325 * Returns 0 if kobject_uevent() is completed with success or the 326 * corresponding error when it fails. 327 */ 328int kobject_uevent(struct kobject *kobj, enum kobject_action action) 329{ 330 return kobject_uevent_env(kobj, action, NULL); 331}
这个函数直接调用了kobject_uevent_env函数,定义如下:
119/** 120 * kobject_uevent_env - send an uevent with environmental data 121 * 122 * @action: action that is happening 123 * @kobj: struct kobject that the action is happening to 124 * @envp_ext: pointer to environmental data 125 * 126 * Returns 0 if kobject_uevent_env() is completed with success or the 127 * corresponding error when it fails. 128 */ 129int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, 130 char *envp_ext[]) 131{ 132 struct kobj_uevent_env *env; 133 const char *action_string = kobject_actions[action]; 134 const char *devpath = NULL; 135 const char *subsystem; 136 struct kobject *top_kobj; 137 struct kset *kset; 138 const struct kset_uevent_ops *uevent_ops; 139 u64 seq; 140 int i = 0; 141 int retval = 0; 142#ifdef CONFIG_NET 143 struct uevent_sock *ue_sk; 144#endif 145 146 pr_debug("kobject: '%s' (%p): %s\n", 147 kobject_name(kobj), kobj, __func__); 148 149 /* search the kset we belong to */ 150 top_kobj = kobj; 151 while (!top_kobj->kset && top_kobj->parent) 152 top_kobj = top_kobj->parent; 153 154 if (!top_kobj->kset) { 155 pr_debug("kobject: '%s' (%p): %s: attempted to send uevent " 156 "without kset!\n", kobject_name(kobj), kobj, 157 __func__); 158 return -EINVAL; 159 } 160 161 kset = top_kobj->kset; 162 uevent_ops = kset->uevent_ops; 163 164 /* skip the event, if uevent_suppress is set*/ 165 if (kobj->uevent_suppress) { 166 pr_debug("kobject: '%s' (%p): %s: uevent_suppress " 167 "caused the event to drop!\n", 168 kobject_name(kobj), kobj, __func__); 169 return 0; 170 } 171 /* skip the event, if the filter returns zero. */ 172 if (uevent_ops && uevent_ops->filter) 173 if (!uevent_ops->filter(kset, kobj)) { 174 pr_debug("kobject: '%s' (%p): %s: filter function " 175 "caused the event to drop!\n", 176 kobject_name(kobj), kobj, __func__); 177 return 0; 178 } 179 180 /* originating subsystem */ 181 if (uevent_ops && uevent_ops->name) 182 subsystem = uevent_ops->name(kset, kobj); 183 else 184 subsystem = kobject_name(&kset->kobj); 185 if (!subsystem) { 186 pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the " 187 "event to drop!\n", kobject_name(kobj), kobj, 188 __func__); 189 return 0; 190 } 191 192 /* environment buffer */ 193 env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); 194 if (!env) 195 return -ENOMEM; 196 197 /* complete object path */ 198 devpath = kobject_get_path(kobj, GFP_KERNEL); 199 if (!devpath) { 200 retval = -ENOENT; 201 goto exit; 202 } 203 204 /* default keys */ 205 retval = add_uevent_var(env, "ACTION=%s", action_string); 206 if (retval) 207 goto exit; 208 retval = add_uevent_var(env, "DEVPATH=%s", devpath); 209 if (retval) 210 goto exit; 211 retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); 212 if (retval) 213 goto exit; 214 215 /* keys passed in from the caller */ 216 if (envp_ext) { 217 for (i = 0; envp_ext[i]; i++) { 218 retval = add_uevent_var(env, "%s", envp_ext[i]); 219 if (retval) 220 goto exit; 221 } 222 } 223 224 /* let the kset specific function add its stuff */ 225 if (uevent_ops && uevent_ops->uevent) { 226 retval = uevent_ops->uevent(kset, kobj, env); 227 if (retval) { 228 pr_debug("kobject: '%s' (%p): %s: uevent() returned " 229 "%d\n", kobject_name(kobj), kobj, 230 __func__, retval); 231 goto exit; 232 } 233 } 234 235 /* 236 * Mark "add" and "remove" events in the object to ensure proper 237 * events to userspace during automatic cleanup. If the object did 238 * send an "add" event, "remove" will automatically generated by 239 * the core, if not already done by the caller. 240 */ 241 if (action == KOBJ_ADD) 242 kobj->state_add_uevent_sent = 1; 243 else if (action == KOBJ_REMOVE) 244 kobj->state_remove_uevent_sent = 1; 245 246 /* we will send an event, so request a new sequence number */ 247 spin_lock(&sequence_lock); 248 seq = ++uevent_seqnum; 249 spin_unlock(&sequence_lock); 250 retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq); 251 if (retval) 252 goto exit; 253 254#if defined(CONFIG_NET) 255 /* send netlink message */ 256 mutex_lock(&uevent_sock_mutex); 257 list_for_each_entry(ue_sk, &uevent_sock_list, list) { 258 struct sock *uevent_sock = ue_sk->sk; 259 struct sk_buff *skb; 260 size_t len; 261 262 /* allocate message with the maximum possible size */ 263 len = strlen(action_string) + strlen(devpath) + 2; 264 skb = alloc_skb(len + env->buflen, GFP_KERNEL); 265 if (skb) { 266 char *scratch; 267 268 /* add header */ 269 scratch = skb_put(skb, len); 270 sprintf(scratch, "%s@%s", action_string, devpath); 271 272 /* copy keys to our continuous event payload buffer */ 273 for (i = 0; i < env->envp_idx; i++) { 274 len = strlen(env->envp[i]) + 1; 275 scratch = skb_put(skb, len); 276 strcpy(scratch, env->envp[i]); 277 } 278 279 NETLINK_CB(skb).dst_group = 1; 280 retval = netlink_broadcast_filtered(uevent_sock, skb, 281 0, 1, GFP_KERNEL, 282 kobj_bcast_filter, 283 kobj); 284 /* ENOBUFS should be handled in userspace */ 285 if (retval == -ENOBUFS) 286 retval = 0; 287 } else 288 retval = -ENOMEM; 289 } 290 mutex_unlock(&uevent_sock_mutex); 291#endif 292 293 /* call uevent_helper, usually only enabled during early boot */ 294 if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { 295 char *argv [3]; 296 297 argv [0] = uevent_helper; 298 argv [1] = (char *)subsystem; 299 argv [2] = NULL; 300 retval = add_uevent_var(env, "HOME=/"); 301 if (retval) 302 goto exit; 303 retval = add_uevent_var(env, 304 "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); 305 if (retval) 306 goto exit; 307 308 retval = call_usermodehelper(argv[0], argv, 309 env->envp, UMH_WAIT_EXEC); 310 } 311 312exit: 313 kfree(devpath); 314 kfree(env); 315 return retval; 316}
133由参数action取得代表事件类型的字符串。kobject_actions定义如下:
40/* 41 * The actions here must match the index to the string array 42 * in lib/kobject_uevent.c 43 * 44 * Do not add new actions here without checking with the driver-core 45 * maintainers. Action strings are not meant to express subsystem 46 * or device specific properties. In most cases you want to send a 47 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event 48 * specific variables added to the event environment. 49 */ 50enum kobject_action { 51 KOBJ_ADD, 52 KOBJ_REMOVE, 53 KOBJ_CHANGE, 54 KOBJ_MOVE, 55 KOBJ_ONLINE, 56 KOBJ_OFFLINE, 57 KOBJ_MAX 58}; 42/* the strings here must match the enum in include/linux/kobject.h */ 43static const char *kobject_actions[] = { 44 [KOBJ_ADD] = "add", 45 [KOBJ_REMOVE] = "remove", 46 [KOBJ_CHANGE] = "change", 47 [KOBJ_MOVE] = "move", 48 [KOBJ_ONLINE] = "online", 49 [KOBJ_OFFLINE] = "offline", 50};
149 - 162行,因为只有kset才包含处理uevent的函数,即kset.uevent_ops,所以这里查找kobj所属的kset,如果kobj->kset不存在,就沿着kobj->parent向上查找,直到找到一个不为空的kset为止。如果确实没有找到kset,则退出。
165 - 170行,如果kobj->uevent_suppress的值为1,表示禁止发出uevent事件,退出。
172 - 178行,如果uevent_ops不为空,并且实现了uevent_ops->filter,则执行uevent_ops->filter,如果uevent_ops->filter返回值为0,表示这个uevent被过滤了,退出。
181 - 190行,如果uevent_ops不为空,并且实现了uevent_ops->name,则通过uevent_ops->name获得子系统名,如果uevent_ops为空,或者没有实现uevent_ops->name,则以kset->kobj的名字作为子系统名。
193行,创建kobj_uevent_env结构体变量env,用来保存环境变量。
198行,通过调用kobject_get_path函数取得kobj在/sys系统中的路径,保存在devpath变量中。
205 - 213行,通过调用add_uevent_var函数将事件名,kobj路径和子系统名加入到环境变量env中。
216 - 222行,如果有通过参数传递的环境变量,也调用add_uevent_var函数加入到环境变量env中。
225 - 233行,如果uevent_ops不为空,并且实现了uevent_ops->uevent函数,则调用uevent_ops->uevent。
241 - 244行,如果要发送的事件是KOBJ_ADD或KOBJ_REMOVE,则相应将kobj->state_add_uevent_sent或kobj->state_remove_uevent_sent置为1。
247 - 252行,将发送事件序列数加1,添加到环境变量env中。
254 - 291行,条件编译部分我们不分析。
294行,先来看uevent_helper的定义:
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
#define UEVENT_HELPER_PATH_LEN 256
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
所以uevent_helper就是"/sbin/hotplug"。
300 - 306行,将HOME和PATH加入环境变量env中。
308 - 309行,执行用户空间的/sbin/hotplug程序,传递环境变量为env。
至此, kobject_uevent_env -> kobject_uevent -> kset_register -> kset_create_and_add函数就分析完了,kset被创建和注册到系统中。