作者:劉昊昱
博客: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);
*************************************************************************************
函數的關係圖是tynew所加,個人喜歡從宏觀上把握函數的實現,如果想看詳細的實現,請繼續瀏覽
*************************************************************************************
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的,該函數定義如下:
- 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}
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};
- 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}
再來看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};
- 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}
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}
至此,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}
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}
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}
- 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}
- 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};
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被創建和註冊到系統中。