一、kset结构定义
kset结构体定义在include/linux/kobject.h文件中,其内容如下:
 
[cpp] view plaincopy

  1. 142/**
  2. 143 * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  3. 144 *
  4. 145 * A kset defines a group of kobjects.  They can be individually
  5. 146 * different "types" but overall these kobjects all want to be grouped
  6. 147 * together and operated on in the same manner.  ksets are used to
  7. 148 * define the attribute callbacks and other common events that happen to
  8. 149 * a kobject.
  9. 150 *
  10. 151 * @list: the list of all kobjects for this kset
  11. 152 * @list_lock: a lock for iterating over the kobjects
  12. 153 * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
  13. 154 * @uevent_ops: the set of uevent operations for this kset.  These are
  14. 155 * called whenever a kobject has something happen to it so that the kset
  15. 156 * can add new environment variables, or filter out the uevents if so
  16. 157 * desired.
  17. 158 */
  18. 159struct kset {
  19. 160    structlist_head list;
  20. 161    spinlock_t list_lock;
  21. 162    structkobject kobj;
  22. 163    conststructkset_uevent_ops *uevent_ops;
  23. 164};
从注释可以看出,kset是一组kobject的集合,这些kobject可以具有不同的“types”,下面来看kset的成员变量:
list用于将该kset下的所有kobject链接成一个链表。
list_lock是一个自旋锁,在遍历该kset下的kobject时用来加锁。
kobj是代表该kset的一个kobject。
uevent_ops是一组函数指针,当kset中的某个kobject状态发生变化需要通知用户空间时,就通过这些函数来完成。uevent_ops是struct kset_uevent_ops类型,该结构体定义在include/linux/kobject.h文件中,其定义如下:
 
[cpp] view plaincopy

  1. 123struct kset_uevent_ops {
  2. 124    int(*constfilter)(structkset *kset,structkobject *kobj);
  3. 125    constchar*(*constname)(structkset *kset,structkobject *kobj);
  4. 126    int(*constuevent)(structkset *kset,structkobject *kobj,
  5. 127              structkobj_uevent_env *env);
  6. 128};
关于kset_uevent_ops结构体中的成员函数的作用,我们后面再分析。
 
二、kset的创建和注册
要创建并注册一个kset,使用的是kset_create_and_add函数,该函数定义在lib/kobject.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 827/**
  2. 828 * kset_create_and_add - create a struct kset dynamically and add it to sysfs
  3. 829 *
  4. 830 * @name: the name for the kset
  5. 831 * @uevent_ops: a struct kset_uevent_ops for the kset
  6. 832 * @parent_kobj: the parent kobject of this kset, if any.
  7. 833 *
  8. 834 * This function creates a kset structure dynamically and registers it
  9. 835 * with sysfs.  When you are finished with this structure, call
  10. 836 * kset_unregister() and the structure will be dynamically freed when it
  11. 837 * is no longer being used.
  12. 838 *
  13. 839 * If the kset was not able to be created, NULL will be returned.
  14. 840 */
  15. 841struct kset *kset_create_and_add(constchar*name,
  16. 842                 conststructkset_uevent_ops *uevent_ops,
  17. 843                 structkobject *parent_kobj)
  18. 844{
  19. 845    structkset *kset;
  20. 846    interror;
  21. 847
  22. 848    kset = kset_create(name, uevent_ops, parent_kobj);
  23. 849    if(!kset)
  24. 850        returnNULL;
  25. 851    error = kset_register(kset);
  26. 852    if(error) {
  27. 853        kfree(kset);
  28. 854        returnNULL;
  29. 855    }
  30. 856    returnkset;
  31. 857}
828行,从注释可以看出,kset_create_and_add函数的作用是动态创建一个kset结构并把它注册到sysfs文件系统中。注意该函数的三个参数:
name是kset的名字,它会被赋值给kset.kobj.name。
uevent_ops是struct kset_uevent_ops变量,它会被赋值给kset.uevent_ops。
parent_kobj是该kset的父kobject,它会被赋值给kset.kobj.parent。
848行,调用kset_create函数动态创建kset结构并对其进行初始化,该函数定义在lib/kobject.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 783/**
  2. 784 * kset_create - create a struct kset dynamically
  3. 785 *
  4. 786 * @name: the name for the kset
  5. 787 * @uevent_ops: a struct kset_uevent_ops for the kset
  6. 788 * @parent_kobj: the parent kobject of this kset, if any.
  7. 789 *
  8. 790 * This function creates a kset structure dynamically.  This structure can
  9. 791 * then be registered with the system and show up in sysfs with a call to
  10. 792 * kset_register().  When you are finished with this structure, if
  11. 793 * kset_register() has been called, call kset_unregister() and the
  12. 794 * structure will be dynamically freed when it is no longer being used.
  13. 795 *
  14. 796 * If the kset was not able to be created, NULL will be returned.
  15. 797 */
  16. 798static structkset *kset_create(constchar*name,
  17. 799                conststructkset_uevent_ops *uevent_ops,
  18. 800                structkobject *parent_kobj)
  19. 801{
  20. 802    structkset *kset;
  21. 803    intretval;
  22. 804
  23. 805    kset = kzalloc(sizeof(*kset), GFP_KERNEL);
  24. 806    if(!kset)
  25. 807        returnNULL;
  26. 808    retval = kobject_set_name(&kset->kobj, name);
  27. 809    if(retval) {
  28. 810        kfree(kset);
  29. 811        returnNULL;
  30. 812    }
  31. 813    kset->uevent_ops = uevent_ops;
  32. 814    kset->kobj.parent = parent_kobj;
  33. 815
  34. 816    /*
  35. 817     * The kobject of this kset will have a type of kset_ktype and belong to
  36. 818     * no kset itself.  That way we can properly free it when it is
  37. 819     * finished being used.
  38. 820     */
  39. 821    kset->kobj.ktype = &kset_ktype;
  40. 822    kset->kobj.kset = NULL;
  41. 823
  42. 824    returnkset;
  43. 825}
805行,为kset结构分配内存空间。
808行,将name参数赋值给kset.kobj.name。它对应kset在sysfs文件系统中的目录名。
813行,将uevent_ops赋值给kset->uevent_ops。
814行,将parent_kobj 赋值给kset->kobj.parent。
816-822行,由注释可以知道,kset.kobj.ktype被赋于一个kset_ktype类型,并且kset.kobj.kset为NULL,即该kset不属于任何其它kset。这样可以保证在不再继续使用该kset时可以正确的释放它。这里我们要来看一下kset_ktype的定义,它定义在lib/kobject.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 778staticstructkobj_type kset_ktype = {
  2. 779    .sysfs_ops  = &kobj_sysfs_ops,
  3. 780    .release = kset_release,
  4. 781};
kobj_sysfs_ops定义在lib/kobject.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 708conststructsysfs_ops kobj_sysfs_ops = {
  2. 709    .show   = kobj_attr_show,
  3. 710    .store  = kobj_attr_store,
  4. 711};
结合上篇文章中对kobject的分析,我们可以得出如下结论:
如果用户空间程序要对kset对应的sysfs文件系统下的属性文件进行读操作时,kobj_attr_show函数会被调用。
如果用户空间程序要对kset对应的sysfs文件系统下的属性文件进行写操作时,
kobj_attr_store函数会被调用。
下面我们来看kobj_attr_show函数,它定义在lib/kobject.c文件中:
 
[cpp] view plaincopy

  1. 683/* default kobject attribute operations */
  2. 684static ssize_t kobj_attr_show(structkobject *kobj,structattribute *attr,
  3. 685                  char*buf)
  4. 686{
  5. 687    structkobj_attribute *kattr;
  6. 688    ssize_t ret = -EIO;
  7. 689
  8. 690    kattr = container_of(attr, structkobj_attribute, attr);
  9. 691    if(kattr->show)
  10. 692        ret = kattr->show(kobj, kattr, buf);
  11. 693    returnret;
  12. 694}
注意683行的注释,这是默认的kobject attribute操作函数。在这函数中,通过container_of取得包含attr变量的struct kobj_attribute变量kattr,然后调用kattr->show()函数。
kobj_attr_store函数与kobj_attr_show函数类似,同样定义在lib/kobject.c文件中:
 
[cpp] view plaincopy

  1. 696static ssize_t kobj_attr_store(structkobject *kobj,structattribute *attr,
  2. 697                   constchar*buf,size_tcount)
  3. 698{
  4. 699    structkobj_attribute *kattr;
  5. 700    ssize_t ret = -EIO;
  6. 701
  7. 702    kattr = container_of(attr, structkobj_attribute, attr);
  8. 703    if(kattr->store)
  9. 704        ret = kattr->store(kobj, kattr, buf, count);
  10. 705    returnret;
  11. 706}
在该函数中,通过container_of取得包含attr变量的struct kobj_attribute变量kattr,然后调用kattr->store()函数。
这样,如果用户空间程序要对kset对应的sysfs文件系统下的属性文件进行读写操作时,就会转而调用包含相应attribute的kobj_attribute结构体的show/store函数。实际上这种用法是和宏__ATTR结合在一起使用的,后面我们会再分析。
到此,kobject_create函数我们就分析完了,回到kset_create_and_add函数,
851行,调用kset_register(kset)函数注册kset,该函数定义在lib/kobject.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 713/**
  2. 714 * kset_register - initialize and add a kset.
  3. 715 * @k: kset.
  4. 716 */
  5. 717int kset_register(structkset *k)
  6. 718{
  7. 719    interr;
  8. 720
  9. 721    if(!k)
  10. 722        return-EINVAL;
  11. 723
  12. 724    kset_init(k);
  13. 725    err = kobject_add_internal(&k->kobj);
  14. 726    if(err)
  15. 727        returnerr;
  16. 728    kobject_uevent(&k->kobj, KOBJ_ADD);
  17. 729    return0;
  18. 730}
724行,首先对kset进行初始化。kset的初始化是通过调用kset_init函数完成的,该函数定义在lib/kobject.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 672/**
  2. 673 * kset_init - initialize a kset for use
  3. 674 * @k: kset
  4. 675 */
  5. 676void kset_init(structkset *k)
  6. 677{
  7. 678    kobject_init_internal(&k->kobj);
  8. 679    INIT_LIST_HEAD(&k->list);
  9. 680    spin_lock_init(&k->list_lock);
  10. 681}
可见,只是简单初始化kset.kobj,kset.list,和kset.list_lock。
725行,将kset.kobj加入到kobject层次结构和sysfs文件系统中。
728行,调用kobject_uevent(&k->kobj, KOBJ_ADD),通知用户空间添加了一个kobject,即kset.kobj。kobject_uevent函数定义在lib/kobject_uevent.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 322/**
  2. 323 * kobject_uevent - notify userspace by sending an uevent
  3. 324 *
  4. 325 * @action: action that is happening
  5. 326 * @kobj: struct kobject that the action is happening to
  6. 327 *
  7. 328 * Returns 0 if kobject_uevent() is completed with success or the
  8. 329 * corresponding error when it fails.
  9. 330 */
  10. 331int kobject_uevent(structkobject *kobj,enumkobject_action action)
  11. 332{
  12. 333    returnkobject_uevent_env(kobj, action, NULL);
  13. 334}
从注释可以看出,kobject_uevent函数的作用是通过发送一个uevent通知用户空间内核中发生了某些事情。至于发生了什么事情,由第二个参数action指定,action是enum kobject_action类型变量,定义在include/linux/kobject.h文件中,其内容如下:
 
[cpp] view plaincopy

  1. 40/*
  2. 41 * The actions here must match the index to the string array
  3. 42 * in lib/kobject_uevent.c
  4. 43 *
  5. 44 * Do not add new actions here without checking with the driver-core
  6. 45 * maintainers. Action strings are not meant to express subsystem
  7. 46 * or device specific properties. In most cases you want to send a
  8. 47 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
  9. 48 * specific variables added to the event environment.
  10. 49 */
  11. 50enum kobject_action {
  12. 51    KOBJ_ADD,
  13. 52    KOBJ_REMOVE,
  14. 53    KOBJ_CHANGE,
  15. 54    KOBJ_MOVE,
  16. 55    KOBJ_ONLINE,
  17. 56    KOBJ_OFFLINE,
  18. 57    KOBJ_MAX
  19. 58};
可见,一共有这7种事件可以通知用户空间。
回到kobject_uevent函数,333行,调用kobject_uevent_env函数来发送uevent,该函数定义在lib/kobject_uevent.c文件中,其内容如下:
 
[cpp] view plaincopy

  1. 121/**
  2. 122 * kobject_uevent_env - send an uevent with environmental data
  3. 123 *
  4. 124 * @action: action that is happening
  5. 125 * @kobj: struct kobject that the action is happening to
  6. 126 * @envp_ext: pointer to environmental data
  7. 127 *
  8. 128 * Returns 0 if kobject_uevent_env() is completed with success or the
  9. 129 * corresponding error when it fails.
  10. 130 */
  11. 131int kobject_uevent_env(structkobject *kobj,enumkobject_action action,
  12. 132               char*envp_ext[])
  13. 133{
  14. 134    structkobj_uevent_env *env;
  15. 135    constchar*action_string = kobject_actions[action];
  16. 136    constchar*devpath = NULL;
  17. 137    constchar*subsystem;
  18. 138    structkobject *top_kobj;
  19. 139    structkset *kset;
  20. 140    conststructkset_uevent_ops *uevent_ops;
  21. 141    inti = 0;
  22. 142    intretval = 0;
  23. 143#ifdef CONFIG_NET
  24. 144    structuevent_sock *ue_sk;
  25. 145#endif
  26. 146
  27. 147    pr_debug("kobject: '%s' (%p): %s\n",
  28. 148         kobject_name(kobj), kobj, __func__);
  29. 149
  30. 150    /* search the kset we belong to */
  31. 151    top_kobj = kobj;
  32. 152    while(!top_kobj->kset && top_kobj->parent)
  33. 153        top_kobj = top_kobj->parent;
  34. 154
  35. 155    if(!top_kobj->kset) {
  36. 156        pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
  37. 157             "without kset!\n", kobject_name(kobj), kobj,
  38. 158             __func__);
  39. 159        return-EINVAL;
  40. 160    }
  41. 161
  42. 162    kset = top_kobj->kset;
  43. 163    uevent_ops = kset->uevent_ops;
  44. 164
  45. 165    /* skip the event, if uevent_suppress is set*/
  46. 166    if(kobj->uevent_suppress) {
  47. 167        pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
  48. 168                 "caused the event to drop!\n",
  49. 169                 kobject_name(kobj), kobj, __func__);
  50. 170        return0;
  51. 171    }
  52. 172    /* skip the event, if the filter returns zero. */
  53. 173    if(uevent_ops && uevent_ops->filter)
  54. 174        if(!uevent_ops->filter(kset, kobj)) {
  55. 175            pr_debug("kobject: '%s' (%p): %s: filter function "
  56. 176                 "caused the event to drop!\n",
  57. 177                 kobject_name(kobj), kobj, __func__);
  58. 178            return0;
  59. 179        }
  60. 180
  61. 181    /* originating subsystem */
  62. 182    if(uevent_ops && uevent_ops->name)
  63. 183        subsystem = uevent_ops->name(kset, kobj);
  64. 184    else
  65. 185        subsystem = kobject_name(&kset->kobj);
  66. 186    if(!subsystem) {
  67. 187        pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
  68. 188             "event to drop!\n", kobject_name(kobj), kobj,
  69. 189             __func__);
  70. 190        return0;
  71. 191    }
  72. 192
  73. 193    /* environment buffer */
  74. 194    env = kzalloc(sizeof(structkobj_uevent_env), GFP_KERNEL);
  75. 195    if(!env)
  76. 196        return-ENOMEM;
  77. 197
  78. 198    /* complete object path */
  79. 199    devpath = kobject_get_path(kobj, GFP_KERNEL);
  80. 200    if(!devpath) {
  81. 201        retval = -ENOENT;
  82. 202        gotoexit;
  83. 203    }
  84. 204
  85. 205    /* default keys */
  86. 206    retval = add_uevent_var(env, "ACTION=%s", action_string);
  87. 207    if(retval)
  88. 208        gotoexit;
  89. 209    retval = add_uevent_var(env, "DEVPATH=%s", devpath);
  90. 210    if(retval)
  91. 211        gotoexit;
  92. 212    retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  93. 213    if(retval)
  94. 214        gotoexit;
  95. 215
  96. 216    /* keys passed in from the caller */
  97. 217    if(envp_ext) {
  98. 218        for(i = 0; envp_ext[i]; i++) {
  99. 219            retval = add_uevent_var(env, "%s", envp_ext[i]);
  100. 220            if(retval)
  101. 221                gotoexit;
  102. 222        }
  103. 223    }
  104. 224
  105. 225    /* let the kset specific function add its stuff */
  106. 226    if(uevent_ops && uevent_ops->uevent) {
  107. 227        retval = uevent_ops->uevent(kset, kobj, env);
  108. 228        if(retval) {
  109. 229            pr_debug("kobject: '%s' (%p): %s: uevent() returned "
  110. 230                 "%d\n", kobject_name(kobj), kobj,
  111. 231                 __func__, retval);
  112. 232            gotoexit;
  113. 233        }
  114. 234    }
  115. 235
  116. 236    /*
  117. 237     * Mark "add" and "remove" events in the object to ensure proper
  118. 238     * events to userspace during automatic cleanup. If the object did
  119. 239     * send an "add" event, "remove" will automatically generated by
  120. 240     * the core, if not already done by the caller.
  121. 241     */
  122. 242    if(action == KOBJ_ADD)
  123. 243        kobj->state_add_uevent_sent = 1;
  124. 244    elseif(action == KOBJ_REMOVE)
  125. 245        kobj->state_remove_uevent_sent = 1;
  126. 246
  127. 247    mutex_lock(&uevent_sock_mutex);
  128. 248    /* we will send an event, so request a new sequence number */
  129. 249    retval = add_uevent_var(env, "SEQNUM=%llu", (unsignedlonglong)++uevent_seqnum);
  130. 250    if(retval) {
  131. 251        mutex_unlock(&uevent_sock_mutex);
  132. 252        gotoexit;
  133. 253    }
  134. 254
  135. 255#ifdefined(CONFIG_NET)
  136. 256    /* send netlink message */
  137. 257    list_for_each_entry(ue_sk, &uevent_sock_list, list) {
  138. 258        structsock *uevent_sock = ue_sk->sk;
  139. 259        structsk_buff *skb;
  140. 260        size_tlen;
  141. 261
  142. 262        if(!netlink_has_listeners(uevent_sock, 1))
  143. 263            continue;
  144. 264
  145. 265        /* allocate message with the maximum possible size */
  146. 266        len = strlen(action_string) + strlen(devpath) + 2;
  147. 267        skb = alloc_skb(len + env->buflen, GFP_KERNEL);
  148. 268        if(skb) {
  149. 269            char*scratch;
  150. 270
  151. 271            /* add header */
  152. 272            scratch = skb_put(skb, len);
  153. 273            sprintf(scratch, "%s@%s", action_string, devpath);
  154. 274
  155. 275            /* copy keys to our continuous event payload buffer */
  156. 276            for(i = 0; i < env->envp_idx; i++) {
  157. 277                len = strlen(env->envp[i]) + 1;
  158. 278                scratch = skb_put(skb, len);
  159. 279                strcpy(scratch, env->envp[i]);
  160. 280            }
  161. 281
  162. 282            NETLINK_CB(skb).dst_group = 1;
  163. 283            retval = netlink_broadcast_filtered(uevent_sock, skb,
  164. 284                                0, 1, GFP_KERNEL,
  165. 285                                kobj_bcast_filter,
  166. 286                                kobj);
  167. 287            /* ENOBUFS should be handled in userspace */
  168. 288            if(retval == -ENOBUFS || retval == -ESRCH)
  169. 289                retval = 0;
  170. 290        } else
  171. 291            retval = -ENOMEM;
  172. 292    }
  173. 293#endif
  174. 294    mutex_unlock(&uevent_sock_mutex);
  175. 295
  176. 296    /* call uevent_helper, usually only enabled during early boot */
  177. 297    if(uevent_helper[0] && !kobj_usermode_filter(kobj)) {
  178. 298        char*argv [3];
  179. 299
  180. 300        argv [0] = uevent_helper;
  181. 301        argv [1] = (char*)subsystem;
  182. 302        argv [2] = NULL;
  183. 303        retval = add_uevent_var(env, "HOME=/");
  184. 304        if(retval)
  185. 305            gotoexit;
  186. 306        retval = add_uevent_var(env,
  187. 307                    "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
  188. 308        if(retval)
  189. 309            gotoexit;
  190. 310
  191. 311        retval = call_usermodehelper(argv[0], argv,
  192. 312                         env->envp, UMH_WAIT_EXEC);
  193. 313    }
  194. 314
  195. 315exit:
  196. 316    kfree(devpath);
  197. 317    kfree(env);
  198. 318    returnretval;
  199. 319}
122行,从注释可以看出,kobject_uevent_env函数的作用是发送带有环境变量数据的uevent。
150-160行,查找kobject所属的kset,如果这个kobject没有所属的kset,则看这个kobject.parent有没有所属的kset,如果还没有,继续沿着kobject层次结构树向上查找,直到找到一个具有所属kset的祖先kobject,如果确实没有找到,则出错退出。所以当前kobject的层次结构树中,必须有一个具有所属的kset。因为对事件的处理函数包含在kobject.kset.uevent_ops中,要处理事件,就必须找到上层一个不为空的kset。
值得注意的是,在创建kset的过程中,kset_create_and_add->kset_create,在kset_create函数中,将kset.kobj.kset设置为NULL,所以kset.kobj本身没有所属的kset,但是同样在kset_create函数中,kset.kobj.parent设置为parent_kobj,所以kset.kobj必然通过其上层祖先查找kset。
162行,取得相应的kset。
163行,将kset.uevent_ops赋值给uevent_ops变量。
165-171行,如果kobj->uevent_suppress被设置为1,则不发送uevent,退出。
172-179行,如果uevent_ops->filter(kset, kobj)返回值为0,说明kobj希望发送的uevent被顶层kset过滤掉了,不再发送。
181-191行,通过uevent_ops->name函数取得子系统名,如果uevent_ops->name为NULL,则使用kset.kobj.name做为子系统名。事实上,一个kset就是一个所谓的“subsystem”。
194行,分配struct kobj_uevent_env变量空间给env,该结构体用来保存环境变量,它定义在include/linux/kobject.h文件中,其内容如下:
116struct kobj_uevent_env {
117    char *envp[UEVENT_NUM_ENVP];
118    int envp_idx;
119    char buf[UEVENT_BUFFER_SIZE];
120    int buflen;
121};
199行,调用kobject_get_path取得kobject的绝对路径。
205-214行,调用add_uevent_var函数将ACTION、DEVPATH、SUBSYSTEM三个默认环境变量添加到env中。add_uevent_var函数定义在lib/kobject_uevent.c文件中,其作用是“add key value string to the environment buffer”。
217-223行,如果调用kobject_uevent_env函数时,通过第三个参数envp_ext传递进来了其它相关环境变量,也通过add_uevent_var函数添加到env中。
225-234行,如果uevent_ops->uevent不为空,则调用uevent_ops->uevent,kset可以通过该函数完成自己特定的功能。
236-246行,如果action是KOBJ_ADD,则设置kobj->state_add_uevent_sent为1。如果action是KOBJ_REMOVE,则设置kobj->state_remove_uevent_sent为1。其作用注释中说的很清楚“Mark "add" and "remove" events in the object to ensure proper events to userspace during automatic cleanup. If the object did send an "add" event, "remove" will automatically generated by the core, if not already done by the caller.”。
249行,将SEQNUM环境变量添加到env中。
kobject_uevent_env函数剩下的部分,用来和用户空间进程进行交互(或者在内核空间启动执行一个用户空间程序)。在Linux中,有两种方式完成这种交互,一个是代码中由CONFIG_NET宏包含的部分,即255-293行,这部分代码通过udev的方式向用户空间广播当前kset对象中的uevent事件。另外一种方式是在内核空间启动一个用户空间进程/sbin/hotplug,通过给该进程传递内核设定的环境变量的方式来通知用户空间kset对象中的uevent事件,即代码中296-312行。
热插拔(hotplug)是指当有设备插入或拨出系统时,内核可以检测到这种状态变化,并通知用户空间加载或移除该设备对应的驱动程序模块。在Linux系统上内核有两种机制可以通知用户空间执行加载或移除操作,一种是udev,另一种是/sbin/hotplug,在Linux发展的早期,只有/sbin/hotplug,它的幕后推手是内核中的call_usermodehelper函数,它能从内核空间启动一个用户空间程序。随着内核的发展,出现了udev机制并逐渐取代了/sbin/hotplug。udev的实现基于内核中的网络机制,它通过创建标准的socket接口来监听来自内核的网络广播包,并对接收到的包进行分析处理。
至此,kobject_uevent_env函数我们就分析完了,同时,kobject_uevent、kset_register、kset_create_and_add函数也分析完了,我们了解了kset的创建和注册过程。

Linux设备模型分析之kset(基于3.10.1内核)相关推荐

  1. Linux设备模型分析之kset

    上一篇博客我们分析了Linux设备模型中kobject的注册和使用,在这一篇文章中,我们来看一下kset的用法. 首先我们看一个使用kset的例子,代码如下: [cpp] view plaincopy ...

  2. linux kset subsystem 3.10内核,Linux设备模型分析之kset(基于3.10.1内核)

    作者:刘昊昱 内核版本:3.10.1 一.kset结构定义 kset结构体定义在include/linux/kobject.h文件中,其内容如下: 142/** 143 * struct kset - ...

  3. Linux设备模型分析之kobject(基于3.10.1内核)

    一.kobject结构定义 kobject是Linux设备模型的最底层数据结构,它代表一个内核对象. kobject结构体定义在include/linux/kobject.h文件中: [cpp] vi ...

  4. Linux设备模型分析之kobject

    一.kobject应用举例 Linux设备模型最基本的组成元素是kobject,我们先来看一个kobject的应用例子,该程序在Ubuntu 10.10, 2.6.32-38-generic-pae内 ...

  5. Linux设备驱动程序架构分析之I2C架构(基于3.10.1内核)

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 内核版本:3.10.1 I2C体系架构的硬件实体包括两部分: 硬件I2C Adapter:硬件I2C Adapter ...

  6. linux设备模型——总线,驱动,设备间的关系

    设备模型之kobject,kset及其关系 关于linux设备模型kobject,kset,ktype 设备驱动基础0:设备模型之kobject,kset及其关系 设备模型之总线,驱动,设备 Linu ...

  7. linux设备模型之kset/kobj/ktype分析

    1. 概述 今天来聊一下Linux设备模型的基石:kset/kobject/ktype. sysfs文件系统提供了一种用户与内核数据结构进行交互的方式,可以通过mount -t sysfs sysfs ...

  8. linux设备模型:bus概念及pci_bus分析

    上一篇<<linux设备模型:kset及设备驱动抽象类(class)分析>>中分析了kset容器.class设备驱动抽象框架.class_kset用于类(class)的热插拔事 ...

  9. Linux设备模型:kset, kobj, ktype

    参照本站转载LWN文章:<kobject/kset/ktype documentation and example code updated> 本文转自:LoyenWang 目录 1. 概 ...

最新文章

  1. 淘宝海量数据库之二:一致性选择
  2. MySQL SQL优化
  3. Django MTV模型思想
  4. 基于 Spring Boot 的车牌识别系统(附项目地址)
  5. 计算机优化英语,英语对计算机专业的重要性及如何提高英语水平
  6. 积跬步-java任职要求
  7. min里所有的参数都不存在_高中生物所有的考点难点,其实都在你不仔细看的课本里,必修1-3超强记忆手册!...
  8. SoapUI 测试http接口实战
  9. spark 存入hbase_Spark DataFrame写入HBase的常用方式
  10. linux grub内核选择,UBUNTU GRUB没有内核选项,怎么回事啊?
  11. 让Flex程序全屏幕运行
  12. Labelme标注软件下载安装教程
  13. vue实现点击复制文本
  14. 项目进度相关计算总结
  15. KMeans 算法(一)
  16. OpenG 编程指南英文整理
  17. Python爬虫之爬取豆瓣图书TOP250
  18. MeteoInfoLab脚本示例:利用比湿、温度计算相对湿度
  19. vue项目报错:warning Disallow self-closing on HTML void elements (<img/>)
  20. 基于COMS技术,COMS工艺等,CMOS到底是个啥?

热门文章

  1. migrate-mongo实现对mongo数据库执行脚本版本控制
  2. java 本地剪切板_Java中剪切板的操作
  3. HiveSQL面试题18--腾讯面试用户连续签到天数及历史最大连续签到天数问题
  4. 每位开发者都该看:如何在四十岁后还能继续从事软件开发?
  5. 思科模拟器 --- 网络地址转换NAT配置
  6. 如何开始你的渗透测试之旅(新手必看)
  7. 关于音频采样率与码率
  8. SPU与SKU的简单理解
  9. 3月23日,Youtube又掛了。
  10. nginx Rewrite功能配置