一、kobject结构定义
kobject是Linux设备模型的最底层数据结构,它代表一个内核对象。
kobject结构体定义在include/linux/kobject.h文件中:
[cpp] view plaincopy
  1. 60struct kobject {
  2. 61    const char      *name;
  3. 62    struct list_head    entry;
  4. 63    struct kobject      *parent;
  5. 64    struct kset     *kset;
  6. 65    struct kobj_type    *ktype;
  7. 66    struct sysfs_dirent *sd;
  8. 67    struct kref     kref;
  9. 68    unsigned int state_initialized:1;
  10. 69    unsigned int state_in_sysfs:1;
  11. 70    unsigned int state_add_uevent_sent:1;
  12. 71    unsigned int state_remove_uevent_sent:1;
  13. 72    unsigned int uevent_suppress:1;
  14. 73};
name是这个内核对象的名字,在sysfs文件系统中,name将以一个目录的形式出现。
entry用于将该内核对象链接进其所属的kset的内核对象链表。
parent代表该内核对象的父对象,用于构建内核对象的层次结构。
kset是该内核对象所属的“内核对象集合”。
ktype是该内核对象的sysfs文件系统相关的操作函数和属性。
sd表示该内核对象对应的sysfs目录项。
kref的核心数据是一个原子型变量,用于表示该内核对象的引用计数。
state_initialized表示该内核对象是否已经进行过了初始化,1表示已经初始化过了。
state_in_sysfs表示该内核对象是否已经在sysfs文件系统中建立一个入口点。
state_add_uevent_sent表示加入内核对象时是否发送uevent事件。
state_remove_uevent_sent表示删除内核对象时是否发送uevent事件。
uevent_suppress表示内核对象状态发生变化时,是否发送uevent事件。
 
二、kobject初始化分析
分析kobject,我们从kobject_init_and_add函数开始看,该函数完成对kobject的初始化,建立kobject的层次结构,并将kobject添加到sysfs文件系统中,该函数定义在lib/kobject.c文件中,其内容如下:
[cpp] view plaincopy
  1. 360/**
  2. 361 * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
  3. 362 * @kobj: pointer to the kobject to initialize
  4. 363 * @ktype: pointer to the ktype for this kobject.
  5. 364 * @parent: pointer to the parent of this kobject.
  6. 365 * @fmt: the name of the kobject.
  7. 366 *
  8. 367 * This function combines the call to kobject_init() and
  9. 368 * kobject_add().  The same type of error handling after a call to
  10. 369 * kobject_add() and kobject lifetime rules are the same here.
  11. 370 */
  12. 371int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
  13. 372             struct kobject *parent, const char *fmt, ...)
  14. 373{
  15. 374    va_list args;
  16. 375    int retval;
  17. 376
  18. 377    kobject_init(kobj, ktype);
  19. 378
  20. 379    va_start(args, fmt);
  21. 380    retval = kobject_add_varg(kobj, parent, fmt, args);
  22. 381    va_end(args);
  23. 382
  24. 383    return retval;
  25. 384}
从注释中可以看出,kobject_init_and_add函数可以分为两部分,一个是kobject_init函数,对kobject进行初始化,另一个是kobject_add_varg函数,将kobject添加到kobject层次结构中。
先来看kobject_init函数,其定义如下:
[cpp] view plaincopy
  1. 256/**
  2. 257 * kobject_init - initialize a kobject structure
  3. 258 * @kobj: pointer to the kobject to initialize
  4. 259 * @ktype: pointer to the ktype for this kobject.
  5. 260 *
  6. 261 * This function will properly initialize a kobject such that it can then
  7. 262 * be passed to the kobject_add() call.
  8. 263 *
  9. 264 * After this function is called, the kobject MUST be cleaned up by a call
  10. 265 * to kobject_put(), not by a call to kfree directly to ensure that all of
  11. 266 * the memory is cleaned up properly.
  12. 267 */
  13. 268void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
  14. 269{
  15. 270    char *err_str;
  16. 271
  17. 272    if (!kobj) {
  18. 273        err_str = "invalid kobject pointer!";
  19. 274        goto error;
  20. 275    }
  21. 276    if (!ktype) {
  22. 277        err_str = "must have a ktype to be initialized properly!\n";
  23. 278        goto error;
  24. 279    }
  25. 280    if (kobj->state_initialized) {
  26. 281        /* do not error out as sometimes we can recover */
  27. 282        printk(KERN_ERR "kobject (%p): tried to init an initialized "
  28. 283               "object, something is seriously wrong.\n", kobj);
  29. 284        dump_stack();
  30. 285    }
  31. 286
  32. 287    kobject_init_internal(kobj);
  33. 288    kobj->ktype = ktype;
  34. 289    return;
  35. 290
  36. 291error:
  37. 292    printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
  38. 293    dump_stack();
  39. 294}
276-279行,如果ktype为空,则返回一个错误,所以从kobject_init_and_add函数中必须传递一个非空的ktype过来。
280-285行,如果kobject已经被初始化过,则打印错误信息。
288行,将传递过来的ktype赋值给kobj->ktype。
287行,调用kobject_init_internal函数,该函数定义在lib/kobject.c文件中,其定义如下:
[cpp] view plaincopy
  1. 143static void kobject_init_internal(struct kobject *kobj)
  2. 144{
  3. 145    if (!kobj)
  4. 146        return;
  5. 147    kref_init(&kobj->kref);
  6. 148    INIT_LIST_HEAD(&kobj->entry);
  7. 149    kobj->state_in_sysfs = 0;
  8. 150    kobj->state_add_uevent_sent = 0;
  9. 151    kobj->state_remove_uevent_sent = 0;
  10. 152    kobj->state_initialized = 1;
  11. 153}
该函数完成对kobject成员变量的初始化,唯一值得一看的是对kobj->kref即引用计数的初始化,这是通过kref_init函数完成的,该函数定义在include/linux/kref.h文件中,其定义如下:
[cpp] view plaincopy
  1. 24struct kref {
  2. 25    atomic_t refcount;
  3. 26};
  4. 27
  5. 28/**
  6. 29 * kref_init - initialize object.
  7. 30 * @kref: object in question.
  8. 31 */
  9. 32static inline void kref_init(struct kref *kref)
  10. 33{
  11. 34    atomic_set(&kref->refcount, 1);
  12. 35}
引用计数的核心变量是一个原子变量,初始化为1。
至此,kobject_init函数我们就分析完了。
回到kobject_init_and_add函数,
379行,va_start用于处理可变参数,这里不再详细解释。
380行,调用kobject_add_varg函数,该函数定义在lib/kobject.c文件中,其内容如下:
[cpp] view plaincopy
  1. 297static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
  2. 298                const char *fmt, va_list vargs)
  3. 299{
  4. 300    int retval;
  5. 301
  6. 302    retval = kobject_set_name_vargs(kobj, fmt, vargs);
  7. 303    if (retval) {
  8. 304        printk(KERN_ERR "kobject: can not set name properly!\n");
  9. 305        return retval;
  10. 306    }
  11. 307    kobj->parent = parent;
  12. 308    return kobject_add_internal(kobj);
  13. 309}
302行,调用kobject_set_name_vargs解析可变参数,设置kobject.name。
307行,设置kobject.parent为parent。
308行,调用kobject_add_internal函数,该函数定义在lib/kobject.c文件中,其内容如下:
[cpp] view plaincopy
  1. 156static int kobject_add_internal(struct kobject *kobj)
  2. 157{
  3. 158    int error = 0;
  4. 159    struct kobject *parent;
  5. 160
  6. 161    if (!kobj)
  7. 162        return -ENOENT;
  8. 163
  9. 164    if (!kobj->name || !kobj->name[0]) {
  10. 165        WARN(1, "kobject: (%p): attempted to be registered with empty "
  11. 166             "name!\n", kobj);
  12. 167        return -EINVAL;
  13. 168    }
  14. 169
  15. 170    parent = kobject_get(kobj->parent);
  16. 171
  17. 172    /* join kset if set, use it as parent if we do not already have one */
  18. 173    if (kobj->kset) {
  19. 174        if (!parent)
  20. 175            parent = kobject_get(&kobj->kset->kobj);
  21. 176        kobj_kset_join(kobj);
  22. 177        kobj->parent = parent;
  23. 178    }
  24. 179
  25. 180    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
  26. 181         kobject_name(kobj), kobj, __func__,
  27. 182         parent ? kobject_name(parent) : "<NULL>",
  28. 183         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
  29. 184
  30. 185    error = create_dir(kobj);
  31. 186    if (error) {
  32. 187        kobj_kset_leave(kobj);
  33. 188        kobject_put(parent);
  34. 189        kobj->parent = NULL;
  35. 190
  36. 191        /* be noisy on error issues */
  37. 192        if (error == -EEXIST)
  38. 193            WARN(1, "%s failed for %s with "
  39. 194                 "-EEXIST, don't try to register things with "
  40. 195                 "the same name in the same directory.\n",
  41. 196                 __func__, kobject_name(kobj));
  42. 197        else
  43. 198            WARN(1, "%s failed for %s (error: %d parent: %s)\n",
  44. 199                 __func__, kobject_name(kobj), error,
  45. 200                 parent ? kobject_name(parent) : "'none'");
  46. 201    } else
  47. 202        kobj->state_in_sysfs = 1;
  48. 203
  49. 204    return error;
  50. 205}
164-168行,检查是否已经设置kobject.name,如果没有设置,则返回错误。所以前面必须已经设置好kobject.name。
170行,对过kobject_get函数取得kobject.parent,该函数定义在lib/kobject.c文件中,其内容如下:
[cpp] view plaincopy
  1. 521/**
  2. 522 * kobject_get - increment refcount for object.
  3. 523 * @kobj: object.
  4. 524 */
  5. 525struct kobject *kobject_get(struct kobject *kobj)
  6. 526{
  7. 527    if (kobj)
  8. 528        kref_get(&kobj->kref);
  9. 529    return kobj;
  10. 530}
注意,该函数除了返回对应的kobject,还通过调用kref_get函数,增加该kobject的引用计数。
173-178行,如果kobject.kset不为空,则调用kobj_kset_join函数,将kobject.entry链接进kobject.kset.list中。另外,如果parent为空,则将kset.kobject设置为kobject.parent。
185行,调用create_dir函数创建kobject在sysfs文件系统中对应的目录结构,该函数定义在lib/kobject.c文件中,其内容如下:
[cpp] view plaincopy
  1. 47static int create_dir(struct kobject *kobj)
  2. 48{
  3. 49    int error = 0;
  4. 50    error = sysfs_create_dir(kobj);
  5. 51    if (!error) {
  6. 52        error = populate_dir(kobj);
  7. 53        if (error)
  8. 54            sysfs_remove_dir(kobj);
  9. 55    }
  10. 56    return error;
  11. 57}
通过sysfs_create_dir函数创建sysfs文件系统目录结构,这里就不再继续追踪了,后面在分析sysfs文件系统时我们会分析这个函数。
202行,如果在sysfs文件系统中创建目录结构成功,则将 kobj->state_in_sysfs设置为1。
至此,kobject_add_internal函数我们就分析完了;相应的kobject_add_varg函数也就分析完了;相应的kobject_init_and_add函数也就分析完了。可以看到,kobject_init_and_add函数完成了对kobject初始化,建立了kobject的层次结构,并将kobject添加到sysfs文件系统中。
 
三、kobject的属性
kobject.ktype代表这个kobject的类型属性,它是struct kobj_type类型,该结构体定义在include/linux/kobject.h文件中,如下:
[cpp] view plaincopy
  1. 108struct kobj_type {
  2. 109    void (*release)(struct kobject *kobj);
  3. 110    const struct sysfs_ops *sysfs_ops;
  4. 111    struct attribute **default_attrs;
  5. 112    const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
  6. 113    const void *(*namespace)(struct kobject *kobj);
  7. 114};
109行,release函数用于在释放kobject对象时进行一些清理工作。
110行,sysfs_ops是struct sysfs_ops类型的指针,该结构体定义在include/linux/sysfs.h文件中,其定义如下:
[cpp] view plaincopy
  1. 124struct sysfs_ops {
  2. 125    ssize_t (*show)(struct kobject *, struct attribute *,char *);
  3. 126    ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
  4. 127    const void *(*namespace)(struct kobject *, const struct attribute *);
  5. 128};
sysfs_ops定义了对struct attribute进行操作的函数,其中,show用于将要显示的内容填充到第三个参数指定的内存空间中,并最终显示给用户空间。store用于设置attribute内容。
111行,default_attrs是一个struct attribute数组,其中保存了kobject的默认attribute。struct attribute定义在include/linux/sysfs.h文件中,其内容如下:
[cpp] view plaincopy
  1. 26struct attribute {
  2. 27    const char      *name;
  3. 28    umode_t         mode;
  4. 29#ifdef CONFIG_DEBUG_LOCK_ALLOC
  5. 30    bool            ignore_lockdep:1;
  6. 31    struct lock_class_key   *key;
  7. 32    struct lock_class_key   skey;
  8. 33#endif
  9. 34};
在将kobject加入到sysfs文件系统后,在该kobject对应的目录下,会创建kobject的属性文件,default_attrs数组中指定了几个属性,就会创建几个对应的属性文件,那么sysfs_ops->show在读属性文件时被调用,sysfs_ops->store在写属性文件时被调用,下面我们就来分析一下这两个函数是怎样被调用的。
当用户空间的程序要对属性文件进行读写操作时,首先要通过open函数打开该属性文件,通过一系列的函数调用,会调用到sysfs_open_file函数,该函数定义在fs/sysfs/file.c文件中,其内容如下:
[cpp] view plaincopy
  1. 326static int sysfs_open_file(struct inode *inode, struct file *file)
  2. 327{
  3. 328    struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  4. 329    struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
  5. 330    struct sysfs_buffer *buffer;
  6. 331    const struct sysfs_ops *ops;
  7. 332    int error = -EACCES;
  8. 333
  9. 334    /* need attr_sd for attr and ops, its parent for kobj */
  10. 335    if (!sysfs_get_active(attr_sd))
  11. 336        return -ENODEV;
  12. 337
  13. 338    /* every kobject with an attribute needs a ktype assigned */
  14. 339    if (kobj->ktype && kobj->ktype->sysfs_ops)
  15. 340        ops = kobj->ktype->sysfs_ops;
  16. 341    else {
  17. 342        WARN(1, KERN_ERR "missing sysfs attribute operations for "
  18. 343               "kobject: %s\n", kobject_name(kobj));
  19. 344        goto err_out;
  20. 345    }
  21. 346
  22. 347    /* File needs write support.
  23. 348     * The inode's perms must say it's ok,
  24. 349     * and we must have a store method.
  25. 350     */
  26. 351    if (file->f_mode & FMODE_WRITE) {
  27. 352        if (!(inode->i_mode & S_IWUGO) || !ops->store)
  28. 353            goto err_out;
  29. 354    }
  30. 355
  31. 356    /* File needs read support.
  32. 357     * The inode's perms must say it's ok, and we there
  33. 358     * must be a show method for it.
  34. 359     */
  35. 360    if (file->f_mode & FMODE_READ) {
  36. 361        if (!(inode->i_mode & S_IRUGO) || !ops->show)
  37. 362            goto err_out;
  38. 363    }
  39. 364
  40. 365    /* No error? Great, allocate a buffer for the file, and store it
  41. 366     * it in file->private_data for easy access.
  42. 367     */
  43. 368    error = -ENOMEM;
  44. 369    buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
  45. 370    if (!buffer)
  46. 371        goto err_out;
  47. 372
  48. 373    mutex_init(&buffer->mutex);
  49. 374    buffer->needs_read_fill = 1;
  50. 375    buffer->ops = ops;
  51. 376    file->private_data = buffer;
  52. 377
  53. 378    /* make sure we have open dirent struct */
  54. 379    error = sysfs_get_open_dirent(attr_sd, buffer);
  55. 380    if (error)
  56. 381        goto err_free;
  57. 382
  58. 383    /* open succeeded, put active references */
  59. 384    sysfs_put_active(attr_sd);
  60. 385    return 0;
  61. 386
  62. 387 err_free:
  63. 388    kfree(buffer);
  64. 389 err_out:
  65. 390    sysfs_put_active(attr_sd);
  66. 391    return error;
  67. 392}
340行,将kobj->ktype->sysfs_ops赋值给ops,这样就取得了sysfs_ops结构体,也就取得了sysfs_ops.show和sysfs_ops.store函数。
374行,将buffer->needs_read_fill设置为1,后面在执行读操作时会用到这个值。
375行,将buffer->ops设置为ops。
376行,将buffer保存在file->private_data中,方便其它函数使用。
如果用户空间程序要对属性文件进行读取操作,最终会调用到sysfs_read_file函数,该函数定义在fs/sysfs/file.c文件中,其内容如下:
[cpp] view plaincopy
  1. 108/**
  2. 109 *  sysfs_read_file - read an attribute.
  3. 110 *  @file:  file pointer.
  4. 111 *  @buf:   buffer to fill.
  5. 112 *  @count: number of bytes to read.
  6. 113 *  @ppos:  starting offset in file.
  7. 114 *
  8. 115 *  Userspace wants to read an attribute file. The attribute descriptor
  9. 116 *  is in the file's ->d_fsdata. The target object is in the directory's
  10. 117 *  ->d_fsdata.
  11. 118 *
  12. 119 *  We call fill_read_buffer() to allocate and fill the buffer from the
  13. 120 *  object's show() method exactly once (if the read is happening from
  14. 121 *  the beginning of the file). That should fill the entire buffer with
  15. 122 *  all the data the object has to offer for that attribute.
  16. 123 *  We then call flush_read_buffer() to copy the buffer to userspace
  17. 124 *  in the increments specified.
  18. 125 */
  19. 126
  20. 127static ssize_t
  21. 128sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  22. 129{
  23. 130    struct sysfs_buffer * buffer = file->private_data;
  24. 131    ssize_t retval = 0;
  25. 132
  26. 133    mutex_lock(&buffer->mutex);
  27. 134    if (buffer->needs_read_fill || *ppos == 0) {
  28. 135        retval = fill_read_buffer(file->f_path.dentry,buffer);
  29. 136        if (retval)
  30. 137            goto out;
  31. 138    }
  32. 139    pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
  33. 140         __func__, count, *ppos, buffer->page);
  34. 141    retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
  35. 142                     buffer->count);
  36. 143out:
  37. 144    mutex_unlock(&buffer->mutex);
  38. 145    return retval;
  39. 146}
134行,因为我们在sysfs_open_file函数中将buffer->needs_read_fill赋值为1,所以135行fill_read_buffer函数会被调用,它会调用sysfs_ops.show函数填充要显示给用户的数据。fill_read_buffer函数同样定义在fs/sysfs/file.c文件中,其内容如下:
[cpp] view plaincopy
  1. 56/**
  2. 57 *  fill_read_buffer - allocate and fill buffer from object.
  3. 58 *  @dentry:    dentry pointer.
  4. 59 *  @buffer:    data buffer for file.
  5. 60 *
  6. 61 *  Allocate @buffer->page, if it hasn't been already, then call the
  7. 62 *  kobject's show() method to fill the buffer with this attribute's
  8. 63 *  data.
  9. 64 *  This is called only once, on the file's first read unless an error
  10. 65 *  is returned.
  11. 66 */
  12. 67static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
  13. 68{
  14. 69    struct sysfs_dirent *attr_sd = dentry->d_fsdata;
  15. 70    struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
  16. 71    const struct sysfs_ops * ops = buffer->ops;
  17. 72    int ret = 0;
  18. 73    ssize_t count;
  19. 74
  20. 75    if (!buffer->page)
  21. 76        buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
  22. 77    if (!buffer->page)
  23. 78        return -ENOMEM;
  24. 79
  25. 80    /* need attr_sd for attr and ops, its parent for kobj */
  26. 81    if (!sysfs_get_active(attr_sd))
  27. 82        return -ENODEV;
  28. 83
  29. 84    buffer->event = atomic_read(&attr_sd->s_attr.open->event);
  30. 85    count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
  31. 86
  32. 87    sysfs_put_active(attr_sd);
  33. 88
  34. 89    /*
  35. 90     * The code works fine with PAGE_SIZE return but it's likely to
  36. 91     * indicate truncated result or overflow in normal use cases.
  37. 92     */
  38. 93    if (count >= (ssize_t)PAGE_SIZE) {
  39. 94        print_symbol("fill_read_buffer: %s returned bad count\n",
  40. 95            (unsigned long)ops->show);
  41. 96        /* Try to struggle along */
  42. 97        count = PAGE_SIZE - 1;
  43. 98    }
  44. 99    if (count >= 0) {
  45. 100        buffer->needs_read_fill = 0;
  46. 101        buffer->count = count;
  47. 102    } else {
  48. 103        ret = count;
  49. 104    }
  50. 105    return ret;
  51. 106}
75-78行,如果buffer->page为空,即以前没有为buffer->page分配过内存,就调用get_zeroed_page为它分配一页内存。
85行,调用ops->show(kobj, attr_sd->s_attr.attr, buffer->page)函数,注意ops->show即sysfs_ops.show函数的参数,第三个参数是刚分配的buffer->page,而buffer->page最终是要拷贝并显示给用户空间的内容,到这里,我们就可以明白sysfs_ops.show函数的作用是将要显示给用户空间的内容填充到第三个参数指定的内存空间中(默认是一页的内存空间)。
回到sysfs_read_file函数,执行完135行fill_read_buffer函数后,下面来到141行,调用simple_read_from_buffer(buf, count, ppos, buffer->page, buffer->count),该函数用于将要显示的数据拷贝到用户空间,注意第一个参数buf是用户空间传递进来的缓冲区地址,第三个参数buffer->page是由sysfs_ops.show填充的那一页内存空间。该函数定义在fs/libfs.c文件中,其内容如下:
[cpp] view plaincopy
  1. 568/**
  2. 569 * simple_read_from_buffer - copy data from the buffer to user space
  3. 570 * @to: the user space buffer to read to
  4. 571 * @count: the maximum number of bytes to read
  5. 572 * @ppos: the current position in the buffer
  6. 573 * @from: the buffer to read from
  7. 574 * @available: the size of the buffer
  8. 575 *
  9. 576 * The simple_read_from_buffer() function reads up to @count bytes from the
  10. 577 * buffer @from at offset @ppos into the user space address starting at @to.
  11. 578 *
  12. 579 * On success, the number of bytes read is returned and the offset @ppos is
  13. 580 * advanced by this number, or negative value is returned on error.
  14. 581 **/
  15. 582ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos,
  16. 583                const void *from, size_t available)
  17. 584{
  18. 585    loff_t pos = *ppos;
  19. 586    size_t ret;
  20. 587
  21. 588    if (pos < 0)
  22. 589        return -EINVAL;
  23. 590    if (pos >= available || !count)
  24. 591        return 0;
  25. 592    if (count > available - pos)
  26. 593        count = available - pos;
  27. 594    ret = copy_to_user(to, from + pos, count);
  28. 595    if (ret == count)
  29. 596        return -EFAULT;
  30. 597    count -= ret;
  31. 598    *ppos = pos + count;
  32. 599    return count;
  33. 600}
可以看到,该函数就是将buffer->page拷贝到用户指定的缓冲区中,这样用户空间就得到了想要的数据。
至此,我们就可以明白sysfs_ops.show的作用及其被调用的流程了。
同样的道理,我们再来看sysfs_ops.store的调用流程:
对属性文件的写操作,最终会调用到sysfs_write_file函数,该函数定义在fs/sysfs/file.c文件中,其内容如下:
[cpp] view plaincopy
  1. 210/**
  2. 211 *  sysfs_write_file - write an attribute.
  3. 212 *  @file:  file pointer
  4. 213 *  @buf:   data to write
  5. 214 *  @count: number of bytes
  6. 215 *  @ppos:  starting offset
  7. 216 *
  8. 217 *  Similar to sysfs_read_file(), though working in the opposite direction.
  9. 218 *  We allocate and fill the data from the user in fill_write_buffer(),
  10. 219 *  then push it to the kobject in flush_write_buffer().
  11. 220 *  There is no easy way for us to know if userspace is only doing a partial
  12. 221 *  write, so we don't support them. We expect the entire buffer to come
  13. 222 *  on the first write.
  14. 223 *  Hint: if you're writing a value, first read the file, modify only the
  15. 224 *  the value you're changing, then write entire buffer back.
  16. 225 */
  17. 226
  18. 227static ssize_t
  19. 228sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  20. 229{
  21. 230    struct sysfs_buffer * buffer = file->private_data;
  22. 231    ssize_t len;
  23. 232
  24. 233    mutex_lock(&buffer->mutex);
  25. 234    len = fill_write_buffer(buffer, buf, count);
  26. 235    if (len > 0)
  27. 236        len = flush_write_buffer(file->f_path.dentry, buffer, len);
  28. 237    if (len > 0)
  29. 238        *ppos += len;
  30. 239    mutex_unlock(&buffer->mutex);
  31. 240    return len;
  32. 241}
234行,调用fill_write_buffer(buffer, buf, count)函数将用户空间传递进来的数据保存到buffer->page中,该函数定义在fs/sysfs/file.c文件中,其内容如下:
[cpp] view plaincopy
  1. 148/**
  2. 149 *  fill_write_buffer - copy buffer from userspace.
  3. 150 *  @buffer:    data buffer for file.
  4. 151 *  @buf:       data from user.
  5. 152 *  @count:     number of bytes in @userbuf.
  6. 153 *
  7. 154 *  Allocate @buffer->page if it hasn't been already, then
  8. 155 *  copy the user-supplied buffer into it.
  9. 156 */
  10. 157
  11. 158static int
  12. 159fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t count)
  13. 160{
  14. 161    int error;
  15. 162
  16. 163    if (!buffer->page)
  17. 164        buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
  18. 165    if (!buffer->page)
  19. 166        return -ENOMEM;
  20. 167
  21. 168    if (count >= PAGE_SIZE)
  22. 169        count = PAGE_SIZE - 1;
  23. 170    error = copy_from_user(buffer->page,buf,count);
  24. 171    buffer->needs_read_fill = 1;
  25. 172    /* if buf is assumed to contain a string, terminate it by \0,
  26. 173       so e.g. sscanf() can scan the string easily */
  27. 174    buffer->page[count] = 0;
  28. 175    return error ? -EFAULT : count;
  29. 176}
236行,调用flush_write_buffer函数,该函数就会调用sysfs_ops.store函数将用户空间传递进来的数据写到kobject中。flush_write_buffer函数定义在fs/sysfs/file.c文件中,其内容如下:
[cpp] view plaincopy
  1. 179/**
  2. 180 *  flush_write_buffer - push buffer to kobject.
  3. 181 *  @dentry:    dentry to the attribute
  4. 182 *  @buffer:    data buffer for file.
  5. 183 *  @count:     number of bytes
  6. 184 *
  7. 185 *  Get the correct pointers for the kobject and the attribute we're
  8. 186 *  dealing with, then call the store() method for the attribute,
  9. 187 *  passing the buffer that we acquired in fill_write_buffer().
  10. 188 */
  11. 189
  12. 190static int
  13. 191flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
  14. 192{
  15. 193    struct sysfs_dirent *attr_sd = dentry->d_fsdata;
  16. 194    struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
  17. 195    const struct sysfs_ops * ops = buffer->ops;
  18. 196    int rc;
  19. 197
  20. 198    /* need attr_sd for attr and ops, its parent for kobj */
  21. 199    if (!sysfs_get_active(attr_sd))
  22. 200        return -ENODEV;
  23. 201
  24. 202    rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count);
  25. 203
  26. 204    sysfs_put_active(attr_sd);
  27. 205
  28. 206    return rc;
  29. 207}

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

  1. Linux设备模型分析之kobject

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

  2. Linux设备模型分析之kset

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

  3. Linux 设备模型之 (kobject、kset 和 Subsystem)(二)

    1.kobject 结构 在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录.从面向对象的角度来说,kobject可以看作是所有设备对象的基 ...

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

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

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

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

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

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

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

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

  8. linux设备模型:devtmpfs虚拟文件系统分析

    devtmpfs是一个设备文件系统,它将其所有文件保存在虚拟内存中. devtmpfs中的所有内容都是临时的,因为不会在您的硬盘驱动器上创建任何文件.如果卸载devtmpfs实例,其中存储的所有内容都 ...

  9. linux设备模型:pci驱动程序注册过程

    一个具有正常探测功能的pci驱动程序应具有基本的pci_driver结构实现,如: static struct pci_driver driver_ops = {.name = "drive ...

最新文章

  1. 通知 | 首届中国心电智能大赛复赛开启
  2. HDU-1316 How Many Fibs? Java
  3. pandas 补充笔记:转换提取类型
  4. mysql 远程用户授权_mysql创建远程用户并授权
  5. 如何定义开发完成?(Definition of Done)
  6. 老司机做VR视频,需要什么样的全景相机?
  7. Direct2D (37) : 使用不同画刷绘制文本
  8. 桌面无法显示计算机,win10 桌面计算机无法显示
  9. 中国大学生计算机设计大赛 历史作品博物馆
  10. 字节跳动python面试题校招_字节跳动校招----编程题(Python)
  11. 无线网络信号测试软件WirelessMon 免费赠送
  12. tsm ANS0326E问题处理
  13. 怎样制作传奇私服服务器,新手传奇gm必须学会如何制作传奇私服小地图
  14. iOS 关于自定义转场动画,以UITabBarController为例
  15. 论文写作各种图片格式转成eps格式(inkscape)
  16. 下载自媒体内容素材,帮你快速创造内容
  17. MySQL 出现数据库表被锁解决方案
  18. 在Vue中使用Echarts来实现(数据可视化)
  19. 计算机输入法设计大赛,搜狗输入法皮肤设计大赛获奖作品
  20. 简单理解二进制的左移和右移(通俗易懂)

热门文章

  1. 实战:Gateway API-2022.2.13
  2. 洛谷P5804 [SEERC2019]Absolute Game
  3. 【CSDN 2020年度征文】江湖路远,不说再见,不负韶光
  4. 纳瓦尔宝典 健康、爱和使命,以此为序,其他的都不重要 不把自己太当回事
  5. 2019年给Java编程初学者的建议(附学习大纲)
  6. C#连接达梦数据库基础功公共类
  7. 经典非局部均值滤波(NLM)算法python实现(2)
  8. 如何科学有效地根治肾虚——下篇(如何有效治疗肾虚?)
  9. JVM内存模型和垃圾回收机制
  10. python招聘广州黄埔_小案例:用Pandas分析招聘网Python岗位信息