本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。

内核版本:2.6.30

1. What is sysfs?

个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。

我们来看看sysfs的文件结构:

[root@yj423 /sys]#ls
block     class     devices   fs        module
bus       dev       firmware  kernel    power

block:块设备

bus:系统中的总线

class: 设备类型,比如输入设备

dev:系统中已注册的设备节点的视图,有两个子目录char和block。

devices:系统中所有设备拓扑结构视图

fireware:固件

fs:文件系统

kernel:内核配置选项和状态信息

module:模块

power:系统的电源管理数据

2. kobject ,kset和ktype

要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个东东来完成的。

2.1 kobject

kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。

kobject用struct kobject来描述。

  1. struct kobject {
  2. const char        *name;            /*在sysfs建立目录的名字*/
  3. struct list_head    entry;        /*用于连接到所属kset的链表中*/
  4. struct kobject        *parent;    /*父对象*/
  5. struct kset        *kset;            /*属于哪个kset*/
  6. struct kobj_type    *ktype;        /*类型*/
  7. struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/
  8. struct kref        kref;            /*对象的应用计数*/
  9. unsigned int state_initialized:1;
  10. unsigned int state_in_sysfs:1;
  11. unsigned int state_add_uevent_sent:1;
  12. unsigned int state_remove_uevent_sent:1;
  13. unsigned int uevent_suppress:1;
  14. };

2.2 kset

kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。

kset使用struct kset来描述。

  1. /**
  2. * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  3. *
  4. * A kset defines a group of kobjects.  They can be individually
  5. * different "types" but overall these kobjects all want to be grouped
  6. * together and operated on in the same manner.  ksets are used to
  7. * define the attribute callbacks and other common events that happen to
  8. * a kobject.
  9. *
  10. * @list: the list of all kobjects for this kset
  11. * @list_lock: a lock for iterating over the kobjects
  12. * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
  13. * @uevent_ops: the set of uevent operations for this kset.  These are
  14. * called whenever a kobject has something happen to it so that the kset
  15. * can add new environment variables, or filter out the uevents if so
  16. * desired.
  17. */
  18. struct kset {
  19. struct list_head list;      /*属于该kset的kobject链表*/
  20. spinlock_t list_lock;
  21. struct kobject kobj;    /*该kset内嵌的kobj*/
  22. struct kset_uevent_ops *uevent_ops;
  23. };

2.3 ktype

每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。

  1. struct kobj_type {
  2. void (*release)(struct kobject *kobj);
  3. struct sysfs_ops *sysfs_ops;
  4. struct attribute **default_attrs;
  5. };
  6. struct sysfs_ops {
  7. ssize_t    (*show)(struct kobject *, struct attribute *,char *);
  8. ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);
  9. };
  10. /* FIXME
  11. * The *owner field is no longer used.
  12. * x86 tree has been cleaned up. The owner
  13. * attribute is still left for other arches.
  14. */
  15. struct attribute {
  16. const char        *name;
  17. struct module        *owner;
  18. mode_t            mode;
  19. };

当kobject的引用计数为0时,通过release方法来释放相关的资源。

attribute为属性,每个属性在sysfs中都有对应的属性文件。

sysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。

2.4 kobject与kset的关系

下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。

从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。

3.举例

在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录。

下面代码位于drivers/base/bus.c

  1. int __init buses_init(void)
  2. {
  3. bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
  4. if (!bus_kset)
  5. return -ENOMEM;
  6. return 0;
  7. }
  8. static struct kset_uevent_ops bus_uevent_ops = {
  9. .filter = bus_uevent_filter,
  10. };
  11. static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
  12. {
  13. struct kobj_type *ktype = get_ktype(kobj);
  14. if (ktype == &bus_ktype)
  15. return 1;
  16. return 0;
  17. }

这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。

下面代码位于drivers/base/kobject.c

  1. /**
  2. * kset_create_and_add - create a struct kset dynamically and add it to sysfs
  3. *
  4. * @name: the name for the kset
  5. * @uevent_ops: a struct kset_uevent_ops for the kset
  6. * @parent_kobj: the parent kobject of this kset, if any.
  7. *
  8. * This function creates a kset structure dynamically and registers it
  9. * with sysfs.  When you are finished with this structure, call
  10. * kset_unregister() and the structure will be dynamically freed when it
  11. * is no longer being used.
  12. *
  13. * If the kset was not able to be created, NULL will be returned.
  14. */
  15. struct kset *kset_create_and_add(const char *name,
  16. struct kset_uevent_ops *uevent_ops,
  17. struct kobject *parent_kobj)
  18. {
  19. struct kset *kset;
  20. int error;
  21. kset = kset_create(name, uevent_ops, parent_kobj);  /*建立kset,设置某些字段*/
  22. if (!kset)
  23. return NULL;
  24. error = kset_register(kset);    /*添加kset到sysfs*/
  25. if (error) {
  26. kfree(kset);
  27. return NULL;
  28. }
  29. return kset;
  30. }

这里主要调用了两个函数,接下分别来看下。

3.1 kset_create函数

下面代码位于drivers/base/kobject.c

  1. /**
  2. * kset_create - create a struct kset dynamically
  3. *
  4. * @name: the name for the kset
  5. * @uevent_ops: a struct kset_uevent_ops for the kset
  6. * @parent_kobj: the parent kobject of this kset, if any.
  7. *
  8. * This function creates a kset structure dynamically.  This structure can
  9. * then be registered with the system and show up in sysfs with a call to
  10. * kset_register().  When you are finished with this structure, if
  11. * kset_register() has been called, call kset_unregister() and the
  12. * structure will be dynamically freed when it is no longer being used.
  13. *
  14. * If the kset was not able to be created, NULL will be returned.
  15. */
  16. static struct kset *kset_create(const char *name,
  17. struct kset_uevent_ops *uevent_ops,
  18. struct kobject *parent_kobj)
  19. {
  20. struct kset *kset;
  21. kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/
  22. if (!kset)
  23. return NULL;
  24. kobject_set_name(&kset->kobj, name);/*设置kobj->name*/
  25. kset->uevent_ops = uevent_ops;
  26. kset->kobj.parent = parent_kobj; /*设置父对象*/
  27. /*
  28. * The kobject of this kset will have a type of kset_ktype and belong to
  29. * no kset itself.  That way we can properly free it when it is
  30. * finished being used.
  31. */
  32. kset->kobj.ktype = &kset_ktype;
  33. kset->kobj.kset = NULL;          /*本keset不属于任何kset*/
  34. return kset;
  35. }

这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,

也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。

随后简要看下由kobject_set_name函数调用引发的一系列调用。

  1. /**
  2. * kobject_set_name - Set the name of a kobject
  3. * @kobj: struct kobject to set the name of
  4. * @fmt: format string used to build the name
  5. *
  6. * This sets the name of the kobject.  If you have already added the
  7. * kobject to the system, you must call kobject_rename() in order to
  8. * change the name of the kobject.
  9. */
  10. int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
  11. {
  12. va_list vargs;
  13. int retval;
  14. va_start(vargs, fmt);
  15. retval = kobject_set_name_vargs(kobj, fmt, vargs);
  16. va_end(vargs);
  17. return retval;
  18. }
  19. /**
  20. * kobject_set_name_vargs - Set the name of an kobject
  21. * @kobj: struct kobject to set the name of
  22. * @fmt: format string used to build the name
  23. * @vargs: vargs to format the string.
  24. */
  25. int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
  26. va_list vargs)
  27. {
  28. const char *old_name = kobj->name;
  29. char *s;
  30. if (kobj->name && !fmt)
  31. return 0;
  32. kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
  33. if (!kobj->name)
  34. return -ENOMEM;
  35. /* ewww... some of these buggers have '/' in the name ... */
  36. while ((s = strchr(kobj->name, '/')))
  37. s[0] = '!';
  38. kfree(old_name);
  39. return 0;
  40. }
  41. /* Simplified asprintf. */
  42. char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
  43. {
  44. unsigned int len;
  45. char *p;
  46. va_list aq;
  47. va_copy(aq, ap);
  48. len = vsnprintf(NULL, 0, fmt, aq);
  49. va_end(aq);
  50. p = kmalloc(len+1, gfp);
  51. if (!p)
  52. return NULL;
  53. vsnprintf(p, len+1, fmt, ap);
  54. return p;
  55. }

3.2 kset_register

下面代码位于drivers/base/kobject.c。

  1. /**
  2. * kset_register - initialize and add a kset.
  3. * @k: kset.
  4. */
  5. int kset_register(struct kset *k)
  6. {
  7. int err;
  8. if (!k)
  9. return -EINVAL;
  10. kset_init(k);           /*初始化kset*/
  11. err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*/
  12. if (err)
  13. return err;
  14. kobject_uevent(&k->kobj, KOBJ_ADD);
  15. return 0;
  16. }

这里面调用了3个函数。这里先介绍前两个函数。

3.2.1 kset_init

该函数用于初始化kset。

下面代码位于drivers/base/kobject.c。

  1. /**
  2. * kset_init - initialize a kset for use
  3. * @k: kset
  4. */
  5. void kset_init(struct kset *k)
  6. {
  7. kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/
  8. INIT_LIST_HEAD(&k->list);    /*初始化链表头*/
  9. spin_lock_init(&k->list_lock);   /*初始化自旋锁*/
  10. }
  11. static void kobject_init_internal(struct kobject *kobj)
  12. {
  13. if (!kobj)
  14. return;
  15. kref_init(&kobj->kref);           /*初始化引用基计数*/
  16. INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
  17. kobj->state_in_sysfs = 0;
  18. kobj->state_add_uevent_sent = 0;
  19. kobj->state_remove_uevent_sent = 0;
  20. kobj->state_initialized = 1;
  21. }

3.2.2 kobject_add_internal

该函数将在sysfs中建立目录。

下面代码位于drivers/base/kobject.c。

  1. static int kobject_add_internal(struct kobject *kobj)
  2. {
  3. int error = 0;
  4. struct kobject *parent;
  5. if (!kobj)
  6. return -ENOENT;
  7. /*检查name字段是否存在*/
  8. if (!kobj->name || !kobj->name[0]) {
  9. WARN(1, "kobject: (%p): attempted to be registered with empty "
  10. "name!\n", kobj);
  11. return -EINVAL;
  12. }
  13. parent = kobject_get(kobj->parent);  /*有父对象则增加父对象引用计数*/
  14. /* join kset if set, use it as parent if we do not already have one */
  15. if (kobj->kset) {
  16. if (!parent)
  17. /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
  18. parent = kobject_get(&kobj->kset->kobj);
  19. kobj_kset_join(kobj);       /*将kojbect添加到kset结构中的链表当中*/
  20. kobj->parent = parent;
  21. }
  22. pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
  23. kobject_name(kobj), kobj, __func__,
  24. parent ? kobject_name(parent) : "<NULL>",
  25. kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
  26. error = create_dir(kobj);   /*根据kobj->name在sys中建立目录*/
  27. if (error) {
  28. kobj_kset_leave(kobj);  /*删除链表项*/
  29. kobject_put(parent);    /*减少引用计数*/
  30. kobj->parent = NULL;
  31. /* be noisy on error issues */
  32. if (error == -EEXIST)
  33. printk(KERN_ERR "%s failed for %s with "
  34. "-EEXIST, don't try to register things with "
  35. "the same name in the same directory.\n",
  36. __func__, kobject_name(kobj));
  37. else
  38. printk(KERN_ERR "%s failed for %s (%d)\n",
  39. __func__, kobject_name(kobj), error);
  40. dump_stack();
  41. } else
  42. kobj->state_in_sysfs = 1;
  43. return error;
  44. }

在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。

在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。

至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。

4. driver model

第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。

Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。

这个属于分离的思想,将设备和驱动分开管理

同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。

4.1 bus

总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。

下列代码位于include/linux/device.h。

  1. <strong><span style="font-family:System;font-size:12px;">struct bus_type {
  2. const char        *name;
  3. struct bus_attribute    *bus_attrs;
  4. struct device_attribute    *dev_attrs;
  5. struct driver_attribute    *drv_attrs;
  6. int (*match)(struct device *dev, struct device_driver *drv);
  7. int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
  8. int (*probe)(struct device *dev);
  9. int (*remove)(struct device *dev);
  10. void (*shutdown)(struct device *dev);
  11. int (*suspend)(struct device *dev, pm_message_t state);
  12. int (*suspend_late)(struct device *dev, pm_message_t state);
  13. int (*resume_early)(struct device *dev);
  14. int (*resume)(struct device *dev);
  15. struct dev_pm_ops *pm;
  16. struct bus_type_private *p;
  17. };
  18. /**
  19. * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
  20. *
  21. * @subsys - the struct kset that defines this bus.  This is the main kobject
  22. * @drivers_kset - the list of drivers associated with this bus
  23. * @devices_kset - the list of devices associated with this bus
  24. * @klist_devices - the klist to iterate over the @devices_kset
  25. * @klist_drivers - the klist to iterate over the @drivers_kset
  26. * @bus_notifier - the bus notifier list for anything that cares about things
  27. * on this bus.
  28. * @bus - pointer back to the struct bus_type that this structure is associated
  29. * with.
  30. *
  31. * This structure is the one that is the actual kobject allowing struct
  32. * bus_type to be statically allocated safely.  Nothing outside of the driver
  33. * core should ever touch these fields.
  34. */
  35. struct bus_type_private {
  36. struct kset subsys;
  37. struct kset *drivers_kset;
  38. struct kset *devices_kset;
  39. struct klist klist_devices;
  40. struct klist klist_drivers;
  41. struct blocking_notifier_head bus_notifier;
  42. unsigned int drivers_autoprobe:1;
  43. struct bus_type *bus;
  44. };</span></strong>

我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。

drivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。

同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。

4.2 device

设备对象在driver-model中使用struct device来表示。

下列代码位于include/linux/device.h。

  1. struct device {
  2. struct device       *parent;
  3. struct device_private   *p;
  4. struct kobject kobj;
  5. const char      *init_name; /* initial name of the device */
  6. struct device_type  *type;
  7. struct semaphore    sem;    /* semaphore to synchronize calls to
  8. * its driver.
  9. */
  10. struct bus_type *bus;       /* type of bus device is on */
  11. struct device_driver *driver;   /* which driver has allocated this
  12. device */
  13. void        *driver_data;   /* data private to the driver */
  14. void        *platform_data; /* Platform specific data, device
  15. core doesn't touch it */
  16. struct dev_pm_info  power;
  17. #ifdef CONFIG_NUMA
  18. int     numa_node;  /* NUMA node this device is close to */
  19. #endif
  20. u64     *dma_mask;  /* dma mask (if dma'able device) */
  21. u64     coherent_dma_mask;/* Like dma_mask, but for
  22. alloc_coherent mappings as
  23. not all hardware supports
  24. 64 bit addresses for consistent
  25. allocations such descriptors. */
  26. struct device_dma_parameters *dma_parms;
  27. struct list_head    dma_pools;  /* dma pools (if dma'ble) */
  28. struct dma_coherent_mem *dma_mem; /* internal for coherent mem
  29. override */
  30. /* arch specific additions */
  31. struct dev_archdata archdata;
  32. dev_t           devt;   /* dev_t, creates the sysfs "dev" */
  33. spinlock_t      devres_lock;
  34. struct list_head    devres_head;
  35. struct klist_node   knode_class;
  36. struct class        *class;
  37. struct attribute_group  **groups;   /* optional groups */
  38. void    (*release)(struct device *dev);
  39. };
  40. /**
  41. * struct device_private - structure to hold the private to the driver core portions of the device structure.
  42. *
  43. * @klist_children - klist containing all children of this device
  44. * @knode_parent - node in sibling list
  45. * @knode_driver - node in driver list
  46. * @knode_bus - node in bus list
  47. * @device - pointer back to the struct class that this structure is
  48. * associated with.
  49. *
  50. * Nothing outside of the driver core should ever touch these fields.
  51. */
  52. struct device_private {
  53. struct klist klist_children;
  54. struct klist_node knode_parent;
  55. struct klist_node knode_driver;
  56. struct klist_node knode_bus;
  57. struct device *device;
  58. };

device本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录

该device所挂载的bus由knode_bus指定。

该device所对应的设备驱动由knode_driver指定。

4.3 driver

设备设备对象在driver-model中使用struct device_driver来表示。

下列代码位于include/linux/device.h。

  1. struct device_driver {
  2. const char      *name;
  3. struct bus_type     *bus;
  4. struct module       *owner;
  5. const char      *mod_name;  /* used for built-in modules */
  6. int (*probe) (struct device *dev);
  7. int (*remove) (struct device *dev);
  8. void (*shutdown) (struct device *dev);
  9. int (*suspend) (struct device *dev, pm_message_t state);
  10. int (*resume) (struct device *dev);
  11. struct attribute_group **groups;
  12. struct dev_pm_ops *pm;
  13. struct driver_private *p;
  14. };
  15. struct driver_private {
  16. struct kobject kobj;
  17. struct klist klist_devices;
  18. struct klist_node knode_bus;
  19. struct module_kobject *mkobj;
  20. struct device_driver *driver;
  21. };

device_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。

该设备驱动所支持的设备由klist_devices指定。

该设备驱动所挂载的总线由knode_bus制定。

5. Bus举例

本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。

platform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:

start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。

注:kernel_init()是在rest_init函数中创建内核线程来执行的。

  1. int __init platform_bus_init(void)
  2. {
  3. int error;
  4. early_platform_cleanup();
  5. error = device_register(&platform_bus);
  6. if (error)
  7. return error;
  8. error =  bus_register(&platform_bus_type);
  9. if (error)
  10. device_unregister(&platform_bus);
  11. return error;
  12. }
  13. struct bus_type platform_bus_type = {
  14. .name       = "platform",
  15. .dev_attrs  = platform_dev_attrs,
  16. .match      = platform_match,
  17. .uevent     = platform_uevent,
  18. .pm     = PLATFORM_PM_OPS_PTR,
  19. };
  20. EXPORT_SYMBOL_GPL(platform_bus_type);

从bus_type,我们看到该总线的名字为platform。

调用了两个函数,我们只关注bus_register函数。

  1. /**
  2. * bus_register - register a bus with the system.
  3. * @bus: bus.
  4. *
  5. * Once we have that, we registered the bus with the kobject
  6. * infrastructure, then register the children subsystems it has:
  7. * the devices and drivers that belong to the bus.
  8. */
  9. int bus_register(struct bus_type *bus)
  10. {
  11. int retval;
  12. struct bus_type_private *priv;
  13. priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
  14. if (!priv)
  15. return -ENOMEM;
  16. /*互相保存*/
  17. priv->bus = bus;
  18. bus->p = priv;
  19. BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
  20. /*设定kobject->name*/
  21. retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
  22. if (retval)
  23. goto out;
  24. priv->subsys.kobj.kset = bus_kset;
  25. priv->subsys.kobj.ktype = &bus_ktype;
  26. priv->drivers_autoprobe = 1;
  27. /*注册kset,在bus/建立目录XXX,XXX为bus->name*/
  28. retval = kset_register(&priv->subsys);
  29. if (retval)
  30. goto out;
  31. /*创建属性,在bus/XXX/建立文件uevent*/
  32. retval = bus_create_file(bus, &bus_attr_uevent);
  33. if (retval)
  34. goto bus_uevent_fail;
  35. /*创建kset,在bus/XXX/建立目录devices*/
  36. priv->devices_kset = kset_create_and_add("devices", NULL,
  37. &priv->subsys.kobj);
  38. if (!priv->devices_kset) {
  39. retval = -ENOMEM;
  40. goto bus_devices_fail;
  41. }
  42. /*创建kset,在bus/XXX/建立目录drivers*/
  43. priv->drivers_kset = kset_create_and_add("drivers", NULL,
  44. &priv->subsys.kobj);
  45. if (!priv->drivers_kset) {
  46. retval = -ENOMEM;
  47. goto bus_drivers_fail;
  48. }
  49. /*初始化2个内核链表,*/
  50. klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
  51. klist_init(&priv->klist_drivers, NULL, NULL);
  52. /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/
  53. retval = add_probe_files(bus);
  54. if (retval)
  55. goto bus_probe_files_fail;
  56. /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/
  57. retval = bus_add_attrs(bus);
  58. if (retval)
  59. goto bus_attrs_fail;
  60. pr_debug("bus: '%s': registered\n", bus->name);
  61. return 0;
  62. bus_attrs_fail:
  63. remove_probe_files(bus);
  64. bus_probe_files_fail:
  65. kset_unregister(bus->p->drivers_kset);
  66. bus_drivers_fail:
  67. kset_unregister(bus->p->devices_kset);
  68. bus_devices_fail:
  69. bus_remove_file(bus, &bus_attr_uevent);
  70. bus_uevent_fail:
  71. kset_unregister(&bus->p->subsys);
  72. kfree(bus->p);
  73. out:
  74. bus->p = NULL;
  75. return retval;
  76. }
  77. EXPORT_SYMBOL_GPL(bus_register);

函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。

在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。

接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。

紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。

  1. /* add the kobject to its kset's list */
  2. static void kobj_kset_join(struct kobject *kobj)
  3. {
  4. if (!kobj->kset)
  5. return;
  6. kset_get(kobj->kset);    /*增加kset引用计数*/
  7. spin_lock(&kobj->kset->list_lock);
  8. list_add_tail(&kobj->entry, &kobj->kset->list);    /*将kojbect添加到kset结构中的链表当中*/
  9. spin_unlock(&kobj->kset->list_lock);
  10. }

kset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。

然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。

  1. int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
  2. {
  3. int error;
  4. if (bus_get(bus)) {
  5. error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
  6. bus_put(bus);
  7. } else
  8. error = -EINVAL;
  9. return error;
  10. }
  11. EXPORT_SYMBOL_GPL(bus_create_file);

有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。

接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。

这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。

也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。

我们来看下关系图:

随后,调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。

  1. static int add_probe_files(struct bus_type *bus)
  2. {
  3. int retval;
  4. retval = bus_create_file(bus, &bus_attr_drivers_probe);
  5. if (retval)
  6. goto out;
  7. retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
  8. if (retval)
  9. bus_remove_file(bus, &bus_attr_drivers_probe);
  10. out:
  11. return retval;
  12. }

该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。

最后调用bus_add_attrs创建总线相关的属性文件。

  1. /**
  2. * bus_add_attrs - Add default attributes for this bus.
  3. * @bus: Bus that has just been registered.
  4. */
  5. static int bus_add_attrs(struct bus_type *bus)
  6. {
  7. int error = 0;
  8. int i;
  9. if (bus->bus_attrs) {
  10. for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
  11. error = bus_create_file(bus, &bus->bus_attrs[i]);
  12. if (error)
  13. goto err;
  14. }
  15. }
  16. done:
  17. return error;
  18. err:
  19. while (--i >= 0)
  20. bus_remove_file(bus, &bus->bus_attrs[i]);
  21. goto done;
  22. }

我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。

好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。

[root@yj423 platform]#pwd
/sys/bus/platform
[root@yj423 platform]#ls
devices            drivers            drivers_autoprobe  drivers_probe      uevent

最后,我们对整个bus_register的过程进行一个小结。

6. device举例

本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。

6.1 虚拟的platform设备

之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备

在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。

  1. int __init platform_bus_init(void)
  2. {
  3. int error;
  4. early_platform_cleanup();
  5. error = device_register(&platform_bus);
  6. if (error)
  7. return error;
  8. error =  bus_register(&platform_bus_type);
  9. if (error)
  10. device_unregister(&platform_bus);
  11. return error;
  12. }
  13. struct device platform_bus = {
  14. .init_name    = "platform",
  15. };
  16. EXPORT_SYMBOL_GPL(platform_bus)

下列函数位于drivers/base/core.c。

  1. /**
  2. * device_register - register a device with the system.
  3. * @dev: pointer to the device structure
  4. *
  5. * This happens in two clean steps - initialize the device
  6. * and add it to the system. The two steps can be called
  7. * separately, but this is the easiest and most common.
  8. * I.e. you should only call the two helpers separately if
  9. * have a clearly defined need to use and refcount the device
  10. * before it is added to the hierarchy.
  11. *
  12. * NOTE: _Never_ directly free @dev after calling this function, even
  13. * if it returned an error! Always use put_device() to give up the
  14. * reference initialized in this function instead.
  15. */
  16. int device_register(struct device *dev)
  17. {
  18. device_initialize(dev); /*初始化dev的某些字段*/
  19. return device_add(dev); /*将设备添加到系统中*/
  20. }

一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:

下列函数位于drivers/base/core.c。

  1. /**
  2. * device_initialize - init device structure.
  3. * @dev: device.
  4. *
  5. * This prepares the device for use by other layers by initializing
  6. * its fields.
  7. * It is the first half of device_register(), if called by
  8. * that function, though it can also be called separately, so one
  9. * may use @dev's fields. In particular, get_device()/put_device()
  10. * may be used for reference counting of @dev after calling this
  11. * function.
  12. *
  13. * NOTE: Use put_device() to give up your reference instead of freeing
  14. * @dev directly once you have called this function.
  15. */
  16. void device_initialize(struct device *dev)
  17. {
  18. dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/
  19. kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/
  20. INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/
  21. init_MUTEX(&dev->sem);                /*初始化互斥体*/
  22. spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/
  23. INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/
  24. device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/
  25. device_pm_init(dev);                /*设置该device可操作*/
  26. set_dev_node(dev, -1);                /*设置NUMA节点*/
  27. }

6.1.1 有关devices_kset

首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。

该对象的建立是在devices_init函数中完成的。

  1. int __init devices_init(void)
  2. {
  3. devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
  4. if (!devices_kset)
  5. return -ENOMEM;
  6. dev_kobj = kobject_create_and_add("dev", NULL);
  7. if (!dev_kobj)
  8. goto dev_kobj_err;
  9. sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
  10. if (!sysfs_dev_block_kobj)
  11. goto block_kobj_err;
  12. sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
  13. if (!sysfs_dev_char_kobj)
  14. goto char_kobj_err;
  15. return 0;
  16. char_kobj_err:
  17. kobject_put(sysfs_dev_block_kobj);
  18. block_kobj_err:
  19. kobject_put(dev_kobj);
  20. dev_kobj_err:
  21. kset_unregister(devices_kset);
  22. return -ENOMEM;
  23. }

由此可见,devices_kset对象表示的目录为/sys下的devices目录。

6.1.2 kobject_init

下列函数位于lib/kojbect.c。

  1. /**
  2. * kobject_init - initialize a kobject structure
  3. * @kobj: pointer to the kobject to initialize
  4. * @ktype: pointer to the ktype for this kobject.
  5. *
  6. * This function will properly initialize a kobject such that it can then
  7. * be passed to the kobject_add() call.
  8. *
  9. * After this function is called, the kobject MUST be cleaned up by a call
  10. * to kobject_put(), not by a call to kfree directly to ensure that all of
  11. * the memory is cleaned up properly.
  12. */
  13. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
  14. {
  15. char *err_str;
  16. if (!kobj) {
  17. err_str = "invalid kobject pointer!";
  18. goto error;
  19. }
  20. if (!ktype) {
  21. err_str = "must have a ktype to be initialized properly!\n";
  22. goto error;
  23. }
  24. if (kobj->state_initialized) {
  25. /* do not error out as sometimes we can recover */
  26. printk(KERN_ERR "kobject (%p): tried to init an initialized "
  27. "object, something is seriously wrong.\n", kobj);
  28. dump_stack();
  29. }
  30. kobject_init_internal(kobj);
  31. kobj->ktype = ktype;
  32. return;
  33. error:
  34. printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
  35. dump_stack();
  36. }
  37. EXPORT_SYMBOL(kobject_init);
  38. static void kobject_init_internal(struct kobject *kobj)
  39. {
  40. if (!kobj)
  41. return;
  42. kref_init(&kobj->kref);            /*初始化引用基计数*/
  43. INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
  44. kobj->state_in_sysfs = 0;
  45. kobj->state_add_uevent_sent = 0;
  46. kobj->state_remove_uevent_sent = 0;
  47. kobj->state_initialized = 1;
  48. }

该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。

6.1.3 device_init_wakeup

参数val为0,设置该device不能够唤醒。

  1. #ifdef CONFIG_PM
  2. /* changes to device_may_wakeup take effect on the next pm state change.
  3. * by default, devices should wakeup if they can.
  4. */
  5. static inline void device_init_wakeup(struct device *dev, int val)
  6. {
  7. dev->power.can_wakeup = dev->power.should_wakeup = !!val;
  8. }
  9. 。。。。。。
  10. #else /* !CONFIG_PM */
  11. /* For some reason the next two routines work even without CONFIG_PM */
  12. static inline void device_init_wakeup(struct device *dev, int val)
  13. {
  14. dev->power.can_wakeup = !!val;
  15. }
  16. 。。。。。。
  17. #endif

6.1.4 device_pm_init

设置电源的状态。

  1. static inline void device_pm_init(struct device *dev)
  2. {
  3. dev->power.status = DPM_ON;    /*该device被认为可操作*/
  4. }

6.1.5 set_dev_node

如果使用NUMA,则设置NUMA节点。

  1. #ifdef CONFIG_NUMA
  2. 。。。。。。
  3. static inline void set_dev_node(struct device *dev, int node)
  4. {
  5. dev->numa_node = node;
  6. }
  7. #else
  8. 。。。。。。
  9. static inline void set_dev_node(struct device *dev, int node)
  10. {
  11. }
  12. #endif

6.2 device_add

接下来是注册的第二步:调用device_add。

  1. /**
  2. * device_add - add device to device hierarchy.
  3. * @dev: device.
  4. *
  5. * This is part 2 of device_register(), though may be called
  6. * separately _iff_ device_initialize() has been called separately.
  7. *
  8. * This adds @dev to the kobject hierarchy via kobject_add(), adds it
  9. * to the global and sibling lists for the device, then
  10. * adds it to the other relevant subsystems of the driver model.
  11. *
  12. * NOTE: _Never_ directly free @dev after calling this function, even
  13. * if it returned an error! Always use put_device() to give up your
  14. * reference instead.
  15. */
  16. int device_add(struct device *dev)
  17. {
  18. struct device *parent = NULL;
  19. struct class_interface *class_intf;
  20. int error = -EINVAL;
  21. dev = get_device(dev);  /*增加引用计数*/
  22. if (!dev)
  23. goto done;
  24. dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);    /*分配device_private结构*/
  25. if (!dev->p) {
  26. error = -ENOMEM;
  27. goto done;
  28. }
  29. dev->p->device = dev; /*保存dev*/
  30. klist_init(&dev->p->klist_children, klist_children_get,   /*初始化内核链表*/
  31. klist_children_put);
  32. /*
  33. * for statically allocated devices, which should all be converted
  34. * some day, we need to initialize the name. We prevent reading back
  35. * the name, and force the use of dev_name()
  36. */
  37. if (dev->init_name) {
  38. dev_set_name(dev, dev->init_name);   /*dev->kobject->name = dev->init_name*/
  39. dev->init_name = NULL;
  40. }
  41. if (!dev_name(dev)) /*检查dev->kobject->name*/
  42. goto name_error;
  43. pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
  44. parent = get_device(dev->parent);    /*增加父设备引用计数*/
  45. setup_parent(dev, parent);          /*设置dev->kobject->parent*/
  46. /* use parent numa_node */
  47. if (parent)
  48. set_dev_node(dev, dev_to_node(parent));
  49. /* first, register with generic layer. */
  50. /* we require the name to be set before, and pass NULL */
  51. /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
  52. error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
  53. if (error)
  54. goto Error;
  55. /* notify platform of device entry */
  56. if (platform_notify)
  57. platform_notify(dev);
  58. /*在XXX下建立文件uevent*/
  59. error = device_create_file(dev, &uevent_attr);
  60. if (error)
  61. goto attrError;
  62. if (MAJOR(dev->devt)) {/*主设备号不为0*/
  63. error = device_create_file(dev, &devt_attr);/*创建属性文件dev*/
  64. if (error)
  65. goto ueventattrError;
  66. /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */
  67. error = device_create_sys_dev_entry(dev);
  68. if (error)
  69. goto devtattrError;
  70. }
  71. error = device_add_class_symlinks(dev);
  72. if (error)
  73. goto SymlinkError;
  74. error = device_add_attrs(dev);  /*添加类设备属型文件和属性组*/
  75. if (error)
  76. goto AttrsError;
  77. error = bus_add_device(dev);    /*添加3个symlink*/
  78. if (error)
  79. goto BusError;
  80. error = dpm_sysfs_add(dev);     /*创建power子目录,并在其下添加电源管理的属性组文件*/
  81. if (error)
  82. goto DPMError;
  83. device_pm_add(dev);             /*将该device添加到电源管理链表中*/
  84. /* Notify clients of device addition.  This call must come
  85. * after dpm_sysf_add() and before kobject_uevent().
  86. */
  87. if (dev->bus)
  88. blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  89. BUS_NOTIFY_ADD_DEVICE, dev);
  90. kobject_uevent(&dev->kobj, KOBJ_ADD);    /*通知用户层*/
  91. bus_attach_device(dev);                 /*将设备添加到总线的设备链表中,并尝试获取驱动*/
  92. if (parent)
  93. klist_add_tail(&dev->p->knode_parent, /*有父设备,则将该设备添加到父设备的儿子链表中*/
  94. &parent->p->klist_children);
  95. if (dev->class) {                        /*该设备属于某个设备类*/
  96. mutex_lock(&dev->class->p->class_mutex);
  97. /* tie the class to the device */
  98. klist_add_tail(&dev->knode_class,    /*将device添加到class的类设备链表中*/
  99. &dev->class->p->class_devices);
  100. /* notify any interfaces that the device is here */
  101. list_for_each_entry(class_intf,
  102. &dev->class->p->class_interfaces, node)
  103. if (class_intf->add_dev)
  104. class_intf->add_dev(dev, class_intf);
  105. mutex_unlock(&dev->class->p->class_mutex);
  106. }
  107. done:
  108. put_device(dev);
  109. return error;
  110. DPMError:
  111. bus_remove_device(dev);
  112. BusError:
  113. device_remove_attrs(dev);
  114. AttrsError:
  115. device_remove_class_symlinks(dev);
  116. SymlinkError:
  117. if (MAJOR(dev->devt))
  118. device_remove_sys_dev_entry(dev);
  119. devtattrError:
  120. if (MAJOR(dev->devt))
  121. device_remove_file(dev, &devt_attr);
  122. ueventattrError:
  123. device_remove_file(dev, &uevent_attr);
  124. attrError:
  125. kobject_uevent(&dev->kobj, KOBJ_REMOVE);
  126. kobject_del(&dev->kobj);
  127. Error:
  128. cleanup_device_parent(dev);
  129. if (parent)
  130. put_device(parent);
  131. name_error:
  132. kfree(dev->p);
  133. dev->p = NULL;
  134. goto done;
  135. }

该函数调用了非常多的其他函数,接下来对主要的函数做出分析。

6.2.1 setup_parent函数

下列代码位于drivers/base/core.c。

  1. static void setup_parent(struct device *dev, struct device *parent)
  2. {
  3. struct kobject *kobj;
  4. kobj = get_device_parent(dev, parent);
  5. if (kobj)
  6. dev->kobj.parent = kobj;
  7. }
  8. static struct kobject *get_device_parent(struct device *dev,
  9. struct device *parent)
  10. {
  11. /* class devices without a parent live in /sys/class/<classname>/ */
  12. if (dev->class && (!parent || parent->class != dev->class))
  13. return &dev->class->p->class_subsys.kobj;
  14. /* all other devices keep their parent */
  15. else if (parent)
  16. return &parent->kobj;
  17. return NULL;
  18. }

该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。

6.2.2 kobject_add函数

下列代码位于lib/kobject.c。

  1. /**
  2. * kobject_add - the main kobject add function
  3. * @kobj: the kobject to add
  4. * @parent: pointer to the parent of the kobject.
  5. * @fmt: format to name the kobject with.
  6. *
  7. * The kobject name is set and added to the kobject hierarchy in this
  8. * function.
  9. *
  10. * If @parent is set, then the parent of the @kobj will be set to it.
  11. * If @parent is NULL, then the parent of the @kobj will be set to the
  12. * kobject associted with the kset assigned to this kobject.  If no kset
  13. * is assigned to the kobject, then the kobject will be located in the
  14. * root of the sysfs tree.
  15. *
  16. * If this function returns an error, kobject_put() must be called to
  17. * properly clean up the memory associated with the object.
  18. * Under no instance should the kobject that is passed to this function
  19. * be directly freed with a call to kfree(), that can leak memory.
  20. *
  21. * Note, no "add" uevent will be created with this call, the caller should set
  22. * up all of the necessary sysfs files for the object and then call
  23. * kobject_uevent() with the UEVENT_ADD parameter to ensure that
  24. * userspace is properly notified of this kobject's creation.
  25. */
  26. int kobject_add(struct kobject *kobj, struct kobject *parent,
  27. const char *fmt, ...)
  28. {
  29. va_list args;
  30. int retval;
  31. if (!kobj)
  32. return -EINVAL;
  33. if (!kobj->state_initialized) {
  34. printk(KERN_ERR "kobject '%s' (%p): tried to add an "
  35. "uninitialized object, something is seriously wrong.\n",
  36. kobject_name(kobj), kobj);
  37. dump_stack();
  38. return -EINVAL;
  39. }
  40. va_start(args, fmt);
  41. retval = kobject_add_varg(kobj, parent, fmt, args);
  42. va_end(args);
  43. return retval;
  44. }
  45. EXPORT_SYMBOL(kobject_add);
  46. static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
  47. const char *fmt, va_list vargs)
  48. {
  49. int retval;
  50. retval = kobject_set_name_vargs(kobj, fmt, vargs);
  51. if (retval) {
  52. printk(KERN_ERR "kobject: can not set name properly!\n");
  53. return retval;
  54. }
  55. kobj->parent = parent;
  56. return kobject_add_internal(kobj);
  57. }
  58. static int kobject_add_internal(struct kobject *kobj)
  59. {
  60. int error = 0;
  61. struct kobject *parent;
  62. if (!kobj)
  63. return -ENOENT;
  64. /*检查name字段是否存在*/
  65. if (!kobj->name || !kobj->name[0]) {
  66. WARN(1, "kobject: (%p): attempted to be registered with empty "
  67. "name!\n", kobj);
  68. return -EINVAL;
  69. }
  70. parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/
  71. /* join kset if set, use it as parent if we do not already have one */
  72. if (kobj->kset) {
  73. if (!parent)
  74. /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
  75. parent = kobject_get(&kobj->kset->kobj);
  76. kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/
  77. kobj->parent = parent;
  78. }
  79. pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
  80. kobject_name(kobj), kobj, __func__,
  81. parent ? kobject_name(parent) : "<NULL>",
  82. kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
  83. error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/
  84. if (error) {
  85. kobj_kset_leave(kobj);    /*删除链表项*/
  86. kobject_put(parent);    /*减少引用计数*/
  87. kobj->parent = NULL;
  88. /* be noisy on error issues */
  89. if (error == -EEXIST)
  90. printk(KERN_ERR "%s failed for %s with "
  91. "-EEXIST, don't try to register things with "
  92. "the same name in the same directory.\n",
  93. __func__, kobject_name(kobj));
  94. else
  95. printk(KERN_ERR "%s failed for %s (%d)\n",
  96. __func__, kobject_name(kobj), error);
  97. dump_stack();
  98. } else
  99. kobj->state_in_sysfs = 1;
  100. return error;
  101. }

在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。

而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。

但是这里比较奇怪的是,为什么platform目录没有对应的kset对象???

6.2.3 device_create_sys_dev_entry函数

在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。

但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。

下列代码位于drivers/base/core.c。

  1. static int device_create_sys_dev_entry(struct device *dev)
  2. {
  3. struct kobject *kobj = device_to_dev_kobj(dev);
  4. int error = 0;
  5. char devt_str[15];
  6. if (kobj) {
  7. format_dev_t(devt_str, dev->devt);
  8. error = sysfs_create_link(kobj, &dev->kobj, devt_str);
  9. }
  10. return error;
  11. }
  12. /**
  13. * device_to_dev_kobj - select a /sys/dev/ directory for the device
  14. * @dev: device
  15. *
  16. * By default we select char/ for new entries.  Setting class->dev_obj
  17. * to NULL prevents an entry from being created.  class->dev_kobj must
  18. * be set (or cleared) before any devices are registered to the class
  19. * otherwise device_create_sys_dev_entry() and
  20. * device_remove_sys_dev_entry() will disagree about the the presence
  21. * of the link.
  22. */
  23. static struct kobject *device_to_dev_kobj(struct device *dev)
  24. {
  25. struct kobject *kobj;
  26. if (dev->class)
  27. kobj = dev->class->dev_kobj;
  28. else
  29. kobj = sysfs_dev_char_kobj;
  30. return kobj;
  31. }

6.2.4 device_add_class_symlinks函数

由于dev->class为NULL,本函数其实没做任何工作。

下列代码位于drivers/base/core.c。

  1. static int device_add_class_symlinks(struct device *dev)
  2. {
  3. int error;
  4. if (!dev->class)
  5. return 0;
  6. error = sysfs_create_link(&dev->kobj,
  7. &dev->class->p->class_subsys.kobj,
  8. "subsystem");
  9. if (error)
  10. goto out;
  11. #ifdef CONFIG_SYSFS_DEPRECATED
  12. /* stacked class devices need a symlink in the class directory */
  13. if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
  14. device_is_not_partition(dev)) {
  15. error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
  16. &dev->kobj, dev_name(dev));
  17. if (error)
  18. goto out_subsys;
  19. }
  20. if (dev->parent && device_is_not_partition(dev)) {
  21. struct device *parent = dev->parent;
  22. char *class_name;
  23. /*
  24. * stacked class devices have the 'device' link
  25. * pointing to the bus device instead of the parent
  26. */
  27. while (parent->class && !parent->bus && parent->parent)
  28. parent = parent->parent;
  29. error = sysfs_create_link(&dev->kobj,
  30. &parent->kobj,
  31. "device");
  32. if (error)
  33. goto out_busid;
  34. class_name = make_class_name(dev->class->name,
  35. &dev->kobj);
  36. if (class_name)
  37. error = sysfs_create_link(&dev->parent->kobj,
  38. &dev->kobj, class_name);
  39. kfree(class_name);
  40. if (error)
  41. goto out_device;
  42. }
  43. return 0;
  44. out_device:
  45. if (dev->parent && device_is_not_partition(dev))
  46. sysfs_remove_link(&dev->kobj, "device");
  47. out_busid:
  48. if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
  49. device_is_not_partition(dev))
  50. sysfs_remove_link(&dev->class->p->class_subsys.kobj,
  51. dev_name(dev));
  52. #else
  53. /* link in the class directory pointing to the device */
  54. error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
  55. &dev->kobj, dev_name(dev));
  56. if (error)
  57. goto out_subsys;
  58. if (dev->parent && device_is_not_partition(dev)) {
  59. error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
  60. "device");
  61. if (error)
  62. goto out_busid;
  63. }
  64. return 0;
  65. out_busid:
  66. sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
  67. #endif
  68. out_subsys:
  69. sysfs_remove_link(&dev->kobj, "subsystem");
  70. out:
  71. return error;
  72. }

6.2.5 device_add_attrs函数

同样dev->class为空,什么都没干。

下列代码位于drivers/base/core.c。

  1. static int device_add_attrs(struct device *dev)
  2. {
  3. struct class *class = dev->class;
  4. struct device_type *type = dev->type;
  5. int error;
  6. if (class) {
  7. error = device_add_attributes(dev, class->dev_attrs);
  8. if (error)
  9. return error;
  10. }
  11. if (type) {
  12. error = device_add_groups(dev, type->groups);
  13. if (error)
  14. goto err_remove_class_attrs;
  15. }
  16. error = device_add_groups(dev, dev->groups);
  17. if (error)
  18. goto err_remove_type_groups;
  19. return 0;
  20. err_remove_type_groups:
  21. if (type)
  22. device_remove_groups(dev, type->groups);
  23. err_remove_class_attrs:
  24. if (class)
  25. device_remove_attributes(dev, class->dev_attrs);
  26. return error;
  27. }

6.2.6 bus_add_device函数

由于dev->bus未指定,因此这个函数什么都没干。

该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。

下列代码位于drivers/base/bus.c。

  1. /**
  2. * bus_add_device - add device to bus
  3. * @dev: device being added
  4. *
  5. * - Add the device to its bus's list of devices.
  6. * - Create link to device's bus.
  7. */
  8. int bus_add_device(struct device *dev)
  9. {
  10. struct bus_type *bus = bus_get(dev->bus);
  11. int error = 0;
  12. if (bus) {
  13. pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
  14. error = device_add_attrs(bus, dev);
  15. if (error)
  16. goto out_put;
  17. /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/
  18. error = sysfs_create_link(&bus->p->devices_kset->kobj,
  19. &dev->kobj, dev_name(dev));
  20. if (error)
  21. goto out_id;
  22. /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*/
  23. error = sysfs_create_link(&dev->kobj,
  24. &dev->bus->p->subsys.kobj, "subsystem");
  25. if (error)
  26. goto out_subsys;
  27. /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/
  28. error = make_deprecated_bus_links(dev);
  29. if (error)
  30. goto out_deprecated;
  31. }
  32. return 0;
  33. out_deprecated:
  34. sysfs_remove_link(&dev->kobj, "subsystem");
  35. out_subsys:
  36. sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
  37. out_id:
  38. device_remove_attrs(bus, dev);
  39. out_put:
  40. bus_put(dev->bus);
  41. return error;
  42. }

6.2.7 dpm_sysfs_add函数

下列代码位于drivers/base/power/sysfs.c。

  1. int dpm_sysfs_add(struct device * dev)
  2. {
  3. return sysfs_create_group(&dev->kobj, &pm_attr_group);
  4. }
  5. static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
  6. static struct attribute * power_attrs[] = {
  7. &dev_attr_wakeup.attr,
  8. NULL,
  9. };
  10. static struct attribute_group pm_attr_group = {
  11. .name    = "power",
  12. .attrs    = power_attrs,
  13. };

该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。

在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。

6.2.8 device_pm_add函数

下列代码位于drivers/base/power/main.c。

  1. /**
  2. *  device_pm_add - add a device to the list of active devices
  3. *  @dev:   Device to be added to the list
  4. */
  5. void device_pm_add(struct device *dev)
  6. {
  7. pr_debug("PM: Adding info for %s:%s\n",
  8. dev->bus ? dev->bus->name : "No Bus",
  9. kobject_name(&dev->kobj));
  10. mutex_lock(&dpm_list_mtx);
  11. if (dev->parent) {
  12. if (dev->parent->power.status >= DPM_SUSPENDING)
  13. dev_warn(dev, "parent %s should not be sleeping\n",
  14. dev_name(dev->parent));
  15. } else if (transition_started) {
  16. /*
  17. * We refuse to register parentless devices while a PM
  18. * transition is in progress in order to avoid leaving them
  19. * unhandled down the road
  20. */
  21. dev_WARN(dev, "Parentless device registered during a PM transaction\n");
  22. }
  23. list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/
  24. mutex_unlock(&dpm_list_mtx);
  25. }

该函数只是将设备添加到电源管理链表中。

6.2.9 bus_attach_device函数

在本例中,由于bus未指定,该函数实际不做任何工作。

下列代码位于drivers/base/bus.c。

  1. /**
  2. * bus_attach_device - add device to bus
  3. * @dev: device tried to attach to a driver
  4. *
  5. * - Add device to bus's list of devices.
  6. * - Try to attach to driver.
  7. */
  8. void bus_attach_device(struct device *dev)
  9. {
  10. struct bus_type *bus = dev->bus;
  11. int ret = 0;
  12. if (bus) {
  13. if (bus->p->drivers_autoprobe)
  14. ret = device_attach(dev);   /*尝试获取驱动*/
  15. WARN_ON(ret < 0);
  16. if (ret >= 0)        /*将设备挂在到总线中*/
  17. klist_add_tail(&dev->p->knode_bus,
  18. &bus->p->klist_devices);
  19. }
  20. }
  21. /**
  22. * device_attach - try to attach device to a driver.
  23. * @dev: device.
  24. *
  25. * Walk the list of drivers that the bus has and call
  26. * driver_probe_device() for each pair. If a compatible
  27. * pair is found, break out and return.
  28. *
  29. * Returns 1 if the device was bound to a driver;
  30. * 0 if no matching device was found;
  31. * -ENODEV if the device is not registered.
  32. *
  33. * When called for a USB interface, @dev->parent->sem must be held.
  34. */
  35. int device_attach(struct device *dev)
  36. {
  37. int ret = 0;
  38. down(&dev->sem);
  39. if (dev->driver) {    /*如果已指定驱动,即已绑定*/
  40. ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/
  41. if (ret == 0)
  42. ret = 1;
  43. else {
  44. dev->driver = NULL;
  45. ret = 0;
  46. }
  47. } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/
  48. ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
  49. }
  50. up(&dev->sem);
  51. return ret;
  52. }
  53. EXPORT_SYMBOL_GPL(device_attach);

如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。

为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。

我们来看下bus_for_each_drv:

  1. /**
  2. * bus_for_each_drv - driver iterator
  3. * @bus: bus we're dealing with.
  4. * @start: driver to start iterating on.
  5. * @data: data to pass to the callback.
  6. * @fn: function to call for each driver.
  7. *
  8. * This is nearly identical to the device iterator above.
  9. * We iterate over each driver that belongs to @bus, and call
  10. * @fn for each. If @fn returns anything but 0, we break out
  11. * and return it. If @start is not NULL, we use it as the head
  12. * of the list.
  13. *
  14. * NOTE: we don't return the driver that returns a non-zero
  15. * value, nor do we leave the reference count incremented for that
  16. * driver. If the caller needs to know that info, it must set it
  17. * in the callback. It must also be sure to increment the refcount
  18. * so it doesn't disappear before returning to the caller.
  19. */
  20. int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
  21. void *data, int (*fn)(struct device_driver *, void *))
  22. {
  23. struct klist_iter i;
  24. struct device_driver *drv;
  25. int error = 0;
  26. if (!bus)
  27. return -EINVAL;
  28. klist_iter_init_node(&bus->p->klist_drivers, &i,
  29. start ? &start->p->knode_bus : NULL);
  30. while ((drv = next_driver(&i)) && !error)
  31. error = fn(drv, data);
  32. klist_iter_exit(&i);
  33. return error;
  34. }
  35. EXPORT_SYMBOL_GPL(bus_for_each_drv);

该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:

  1. static int __device_attach(struct device_driver *drv, void *data)
  2. {
  3. struct device *dev = data;
  4. if (!driver_match_device(drv, dev))   /*进行匹配工作*/
  5. return 0;
  6. return driver_probe_device(drv, dev);
  7. }
  8. static inline int driver_match_device(struct device_driver *drv,
  9. struct device *dev)
  10. {
  11. return drv->bus->match ? drv->bus->match(dev, drv) : 1;
  12. }
  13. /**
  14. * driver_probe_device - attempt to bind device & driver together
  15. * @drv: driver to bind a device to
  16. * @dev: device to try to bind to the driver
  17. *
  18. * This function returns -ENODEV if the device is not registered,
  19. * 1 if the device is bound sucessfully and 0 otherwise.
  20. *
  21. * This function must be called with @dev->sem held.  When called for a
  22. * USB interface, @dev->parent->sem must be held as well.
  23. */
  24. int driver_probe_device(struct device_driver *drv, struct device *dev)
  25. {
  26. int ret = 0;
  27. if (!device_is_registered(dev))    /*该device是否已在sysfs中*/
  28. return -ENODEV;
  29. pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
  30. drv->bus->name, __func__, dev_name(dev), drv->name);
  31. ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/
  32. return ret;
  33. }

该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。

我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。

随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。

really_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。

6.2.10 小结

在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。

最后以函数调用过程的总结来结束第6.2小结。

6.3 spi主控制器的平台设备

本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。

在内核的启动阶段,platform设备将被注册进内核。我们来看下。

下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c

  1. static struct resource s3c_spi0_resource[] = {
  2. [0] = {
  3. .start = S3C24XX_PA_SPI,
  4. .end   = S3C24XX_PA_SPI + 0x1f,
  5. .flags = IORESOURCE_MEM,
  6. },
  7. [1] = {
  8. .start = IRQ_SPI0,
  9. .end   = IRQ_SPI0,
  10. .flags = IORESOURCE_IRQ,
  11. }
  12. };
  13. static u64 s3c_device_spi0_dmamask = 0xffffffffUL;
  14. struct platform_device s3c_device_spi0 = {
  15. .name          = "s3c2410-spi",
  16. .id          = 0,
  17. .num_resources      = ARRAY_SIZE(s3c_spi0_resource),
  18. .resource      = s3c_spi0_resource,
  19. .dev              = {
  20. .dma_mask = &s3c_device_spi0_dmamask,
  21. .coherent_dma_mask = 0xffffffffUL
  22. }
  23. };
  24. static struct platform_device *smdk2440_devices[] __initdata = {
  25. &s3c_device_usb,
  26. &s3c_device_lcd,
  27. &s3c_device_wdt,
  28. &s3c_device_i2c0,
  29. &s3c_device_iis,
  30. &s3c_device_spi0,
  31. };
  32. static void __init smdk2440_machine_init(void)
  33. {
  34. s3c24xx_fb_set_platdata(&smdk2440_fb_info);
  35. s3c_i2c0_set_platdata(NULL);
  36. platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
  37. smdk_machine_init();
  38. }

在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。

6.3.1 platform_add_devices

  1. /**
  2. * platform_add_devices - add a numbers of platform devices
  3. * @devs: array of platform devices to add
  4. * @num: number of platform devices in array
  5. */
  6. int platform_add_devices(struct platform_device **devs, int num)
  7. {
  8. int i, ret = 0;
  9. for (i = 0; i < num; i++) {
  10. ret = platform_device_register(devs[i]);
  11. if (ret) {
  12. while (--i >= 0)
  13. platform_device_unregister(devs[i]);
  14. break;
  15. }
  16. }
  17. return ret;
  18. }
  19. EXPORT_SYMBOL_GPL(platform_add_devices);

该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。

6.3.2  platform_device_register

  1. /**
  2. * platform_device_register - add a platform-level device
  3. * @pdev: platform device we're adding
  4. */
  5. int platform_device_register(struct platform_device *pdev)
  6. {
  7. device_initialize(&pdev->dev);
  8. return platform_device_add(pdev);
  9. }
  10. EXPORT_SYMBOL_GPL(platform_device_register);

调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。

6.3.2  platform_device_register

  1. /**
  2. * platform_device_add - add a platform device to device hierarchy
  3. * @pdev: platform device we're adding
  4. *
  5. * This is part 2 of platform_device_register(), though may be called
  6. * separately _iff_ pdev was allocated by platform_device_alloc().
  7. */
  8. int platform_device_add(struct platform_device *pdev)
  9. {
  10. int i, ret = 0;
  11. if (!pdev)
  12. return -EINVAL;
  13. if (!pdev->dev.parent)
  14. pdev->dev.parent = &platform_bus;    /*该设备的父设备是platform设备,/sys/devices/platform*/
  15. pdev->dev.bus = &platform_bus_type;      /*设备挂载到platform总线上*/
  16. if (pdev->id != -1)
  17. dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
  18. else
  19. dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/
  20. /*遍历平台设备的资源,并将资源添加到资源树中*/
  21. for (i = 0; i < pdev->num_resources; i++) {
  22. struct resource *p, *r = &pdev->resource[i];
  23. if (r->name == NULL)
  24. r->name = dev_name(&pdev->dev);   /*获取dev->kobject->name*/
  25. p = r->parent;
  26. if (!p) {   /*p空*/
  27. if (resource_type(r) == IORESOURCE_MEM)
  28. p = &iomem_resource;
  29. else if (resource_type(r) == IORESOURCE_IO)
  30. p = &ioport_resource;
  31. }
  32. if (p && insert_resource(p, r)) {   /*将资源添加到资源树中*/
  33. printk(KERN_ERR
  34. "%s: failed to claim resource %d\n",
  35. dev_name(&pdev->dev), i);
  36. ret = -EBUSY;
  37. goto failed;
  38. }
  39. }
  40. pr_debug("Registering platform device '%s'. Parent at %s\n",
  41. dev_name(&pdev->dev), dev_name(pdev->dev.parent));
  42. ret = device_add(&pdev->dev);    /*添加设备*/
  43. if (ret == 0)
  44. return ret;
  45. failed:
  46. while (--i >= 0) {
  47. struct resource *r = &pdev->resource[i];
  48. unsigned long type = resource_type(r);
  49. if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
  50. release_resource(r);
  51. }
  52. return ret;
  53. }
  54. EXPORT_SYMBOL_GPL(platform_device_add);

在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。

本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。

那么这个"其他的工作"干了些什么呢?

首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。

然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。

最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。

在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。

由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。

6.3.3 不一样device_add调用结果

首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:

pdev->dev->kobj.kset = devices_kset

pdev->dev-.parent = &platform_bus

pdev->dev.bus = &platform_bus_type

set_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。

kobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。

device_create_file建立属性文件uevent。

bus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。

/sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。

/sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。

dpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。

执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。

[root@yj423 s3c2410-spi.0]#pwd
/sys/devices/platform/s3c2410-spi.0
[root@yj423 s3c2410-spi.0]#ll
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi
-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias
drwxr-xr-x    2 root     root             0 Jan  1 00:29 power
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform
-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent

[root@yj423 devices]#pwd
/sys/bus/platform/devices
[root@yj423 devices]#ll s3c2410-spi.0 
lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.0

通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。

bus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。

接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。

7. driver举例

我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。

7.1 s3c24xx_spi_init

下列代码位于drivers/spi/spi_s3c24xx.c。

  1. MODULE_ALIAS("platform:s3c2410-spi");
  2. static struct platform_driver s3c24xx_spi_driver = {
  3. .remove        = __exit_p(s3c24xx_spi_remove),
  4. .suspend    = s3c24xx_spi_suspend,
  5. .resume        = s3c24xx_spi_resume,
  6. .driver        = {
  7. .name    = "s3c2410-spi",
  8. .owner    = THIS_MODULE,
  9. },
  10. };
  11. static int __init s3c24xx_spi_init(void)
  12. {
  13. return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register
  14. }

驱动注册通过调用platform_driver_probe来完成。

注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。

7.2  platform_driver_probe

下列代码位于drivers/base/platform.c。

  1. /**
  2. * platform_driver_probe - register driver for non-hotpluggable device
  3. * @drv: platform driver structure
  4. * @probe: the driver probe routine, probably from an __init section
  5. *
  6. * Use this instead of platform_driver_register() when you know the device
  7. * is not hotpluggable and has already been registered, and you want to
  8. * remove its run-once probe() infrastructure from memory after the driver
  9. * has bound to the device.
  10. *
  11. * One typical use for this would be with drivers for controllers integrated
  12. * into system-on-chip processors, where the controller devices have been
  13. * configured as part of board setup.
  14. *
  15. * Returns zero if the driver registered and bound to a device, else returns
  16. * a negative error code and with the driver not registered.
  17. */
  18. int __init_or_module platform_driver_probe(struct platform_driver *drv,
  19. int (*probe)(struct platform_device *))
  20. {
  21. int retval, code;
  22. /* temporary section violation during probe() */
  23. drv->probe = probe;
  24. retval = code = platform_driver_register(drv); /*注册platform驱动*/
  25. /* Fixup that section violation, being paranoid about code scanning
  26. * the list of drivers in order to probe new devices.  Check to see
  27. * if the probe was successful, and make sure any forced probes of
  28. * new devices fail.
  29. */
  30. spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
  31. drv->probe = NULL;
  32. if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
  33. retval = -ENODEV;
  34. drv->driver.probe = platform_drv_probe_fail;
  35. spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
  36. if (code != retval)
  37. platform_driver_unregister(drv);
  38. return retval;
  39. }
  40. EXPORT_SYMBOL_GPL(platform_driver_probe);

这里的重点是platform_driver_register,由它来完成了platform驱动的注册。

7.3 platform_driver_register

  1. /**
  2. * platform_driver_register
  3. * @drv: platform driver structure
  4. */
  5. int platform_driver_register(struct platform_driver *drv)
  6. {
  7. drv->driver.bus = &platform_bus_type;
  8. if (drv->probe)
  9. drv->driver.probe = platform_drv_probe;
  10. if (drv->remove)
  11. drv->driver.remove = platform_drv_remove;
  12. if (drv->shutdown)
  13. drv->driver.shutdown = platform_drv_shutdown;
  14. if (drv->suspend)
  15. drv->driver.suspend = platform_drv_suspend;
  16. if (drv->resume)
  17. drv->driver.resume = platform_drv_resume;
  18. return driver_register(&drv->driver); /*驱动注册*/
  19. }
  20. EXPORT_SYMBOL_GPL(platform_driver_register);

driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。

7.4 driver_register

下列代码位于drivers/base/driver.c。

  1. /**
  2. * driver_register - register driver with bus
  3. * @drv: driver to register
  4. *
  5. * We pass off most of the work to the bus_add_driver() call,
  6. * since most of the things we have to do deal with the bus
  7. * structures.
  8. */
  9. int driver_register(struct device_driver *drv)
  10. {
  11. int ret;
  12. struct device_driver *other;
  13. BUG_ON(!drv->bus->p);
  14. if ((drv->bus->probe && drv->probe) ||
  15. (drv->bus->remove && drv->remove) ||
  16. (drv->bus->shutdown && drv->shutdown))
  17. printk(KERN_WARNING "Driver '%s' needs updating - please use "
  18. "bus_type methods\n", drv->name);
  19. other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/
  20. if (other) {    /*存在则报错*/
  21. put_driver(other);
  22. printk(KERN_ERR "Error: Driver '%s' is already registered, "
  23. "aborting...\n", drv->name);
  24. return -EEXIST;
  25. }
  26. ret = bus_add_driver(drv);  /*将驱动添加到一个总线中*/
  27. if (ret)
  28. return ret;
  29. ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/
  30. if (ret)
  31. bus_remove_driver(drv);
  32. return ret;
  33. }
  34. EXPORT_SYMBOL_GPL(driver_register);

这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。

接下来就分析这两个函数。

7.5 driver_find

下列代码位于drivers/base/driver.c。

  1. /**
  2. * driver_find - locate driver on a bus by its name.
  3. * @name: name of the driver.
  4. * @bus: bus to scan for the driver.
  5. *
  6. * Call kset_find_obj() to iterate over list of drivers on
  7. * a bus to find driver by name. Return driver if found.
  8. *
  9. * Note that kset_find_obj increments driver's reference count.
  10. */
  11. struct device_driver *driver_find(const char *name, struct bus_type *bus)
  12. {
  13. struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
  14. struct driver_private *priv;
  15. if (k) {
  16. priv = to_driver(k);
  17. return priv->driver;
  18. }
  19. return NULL;
  20. }
  21. EXPORT_SYMBOL_GPL(driver_find);
  1. /**
  2. * kset_find_obj - search for object in kset.
  3. * @kset: kset we're looking in.
  4. * @name: object's name.
  5. *
  6. * Lock kset via @kset->subsys, and iterate over @kset->list,
  7. * looking for a matching kobject. If matching object is found
  8. * take a reference and return the object.
  9. */
  10. struct kobject *kset_find_obj(struct kset *kset, const char *name)
  11. {
  12. struct kobject *k;
  13. struct kobject *ret = NULL;
  14. spin_lock(&kset->list_lock);
  15. list_for_each_entry(k, &kset->list, entry) {
  16. if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
  17. ret = kobject_get(k);
  18. break;
  19. }
  20. }
  21. spin_unlock(&kset->list_lock);
  22. return ret;
  23. }

这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。

7.6 bus_add_driver

下列代码位于drivers/base/bus.c

  1. /**
  2. * bus_add_driver - Add a driver to the bus.
  3. * @drv: driver.
  4. */
  5. int bus_add_driver(struct device_driver *drv)
  6. {
  7. struct bus_type *bus;
  8. struct driver_private *priv;
  9. int error = 0;
  10. bus = bus_get(drv->bus); /*增加引用计数获取bus_type*/
  11. if (!bus)
  12. return -EINVAL;
  13. pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
  14. priv = kzalloc(sizeof(*priv), GFP_KERNEL);  /*分配driver_private结构体*/
  15. if (!priv) {
  16. error = -ENOMEM;
  17. goto out_put_bus;
  18. }
  19. /*初始化内核链表*/
  20. klist_init(&priv->klist_devices, NULL, NULL);
  21. /*相互保存*/
  22. priv->driver = drv;
  23. drv->p = priv;
  24. /*设置该kobj属于那个kset*/
  25. priv->kobj.kset = bus->p->drivers_kset;
  26. error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,   /*parent=NULL*/
  27. "%s", drv->name);   /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/
  28. if (error)
  29. goto out_unregister;
  30. if (drv->bus->p->drivers_autoprobe) {
  31. error = driver_attach(drv); /*尝试绑定驱动和设备*/
  32. if (error)
  33. goto out_unregister;
  34. }
  35. /*添加该驱动到bus的内核链表中*/
  36. klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
  37. module_add_driver(drv->owner, drv);/*?????????*/
  38. /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/
  39. error = driver_create_file(drv, &driver_attr_uevent);
  40. if (error) {
  41. printk(KERN_ERR "%s: uevent attr (%s) failed\n",
  42. __func__, drv->name);
  43. }
  44. /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/
  45. error = driver_add_attrs(bus, drv);
  46. if (error) {
  47. /* How the hell do we get out of this pickle? Give up */
  48. printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
  49. __func__, drv->name);
  50. }
  51. /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/
  52. error = add_bind_files(drv);
  53. if (error) {
  54. /* Ditto */
  55. printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
  56. __func__, drv->name);
  57. }
  58. /*通知用户空间???*/
  59. kobject_uevent(&priv->kobj, KOBJ_ADD);
  60. return 0;
  61. out_unregister:
  62. kfree(drv->p);
  63. drv->p = NULL;
  64. kobject_put(&priv->kobj);
  65. out_put_bus:
  66. bus_put(bus);
  67. return error;
  68. }

在设置driver的kobj.kset为drivers目录所对应的kset之后,调用了kobject_init_and_add,我们来看下。

7.6.1 kobject_init_and_add

下列代码位于lib/kobject.c。

  1. /**
  2. * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
  3. * @kobj: pointer to the kobject to initialize
  4. * @ktype: pointer to the ktype for this kobject.
  5. * @parent: pointer to the parent of this kobject.
  6. * @fmt: the name of the kobject.
  7. *
  8. * This function combines the call to kobject_init() and
  9. * kobject_add().  The same type of error handling after a call to
  10. * kobject_add() and kobject lifetime rules are the same here.
  11. */
  12. int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
  13. struct kobject *parent, const char *fmt, ...)
  14. {
  15. va_list args;
  16. int retval;
  17. kobject_init(kobj, ktype);
  18. va_start(args, fmt);
  19. retval = kobject_add_varg(kobj, parent, fmt, args);
  20. va_end(args);
  21. return retval;
  22. }
  23. EXPORT_SYMBOL_GPL(kobject_init_and_add);

该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。

调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。

我们来验证下:

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi

接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。

7.6.2 driver_attach

下列代码位于drivers/base/dd.c。

  1. /**
  2. * driver_attach - try to bind driver to devices.
  3. * @drv: driver.
  4. *
  5. * Walk the list of devices that the bus has on it and try to
  6. * match the driver with each one.  If driver_probe_device()
  7. * returns 0 and the @dev->driver is set, we've found a
  8. * compatible pair.
  9. */
  10. int driver_attach(struct device_driver *drv)
  11. {
  12. return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
  13. }
  14. EXPORT_SYMBOL_GPL(driver_attach);

该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。

这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。

  1. /**
  2. * bus_for_each_dev - device iterator.
  3. * @bus: bus type.
  4. * @start: device to start iterating from.
  5. * @data: data for the callback.
  6. * @fn: function to be called for each device.
  7. *
  8. * Iterate over @bus's list of devices, and call @fn for each,
  9. * passing it @data. If @start is not NULL, we use that device to
  10. * begin iterating from.
  11. *
  12. * We check the return of @fn each time. If it returns anything
  13. * other than 0, we break out and return that value.
  14. *
  15. * NOTE: The device that returns a non-zero value is not retained
  16. * in any way, nor is its refcount incremented. If the caller needs
  17. * to retain this data, it should do, and increment the reference
  18. * count in the supplied callback.
  19. */
  20. int bus_for_each_dev(struct bus_type *bus, struct device *start,
  21. void *data, int (*fn)(struct device *, void *))
  22. {
  23. struct klist_iter i;
  24. struct device *dev;
  25. int error = 0;
  26. if (!bus)
  27. return -EINVAL;
  28. klist_iter_init_node(&bus->p->klist_devices, &i,
  29. (start ? &start->p->knode_bus : NULL));
  30. while ((dev = next_device(&i)) && !error)
  31. error = fn(dev, data);
  32. klist_iter_exit(&i);
  33. return error;
  34. }
  35. EXPORT_SYMBOL_GPL(bus_for_each_dev);

通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。

  1. static int __driver_attach(struct device *dev, void *data)
  2. {
  3. struct device_driver *drv = data;
  4. /*
  5. * Lock device and try to bind to it. We drop the error
  6. * here and always return 0, because we need to keep trying
  7. * to bind to devices and some drivers will return an error
  8. * simply if it didn't support the device.
  9. *
  10. * driver_probe_device() will spit a warning if there
  11. * is an error.
  12. */
  13. if (!driver_match_device(drv, dev))
  14. return 0;
  15. if (dev->parent) /* Needed for USB */
  16. down(&dev->parent->sem);
  17. down(&dev->sem);
  18. if (!dev->driver)
  19. driver_probe_device(drv, dev);
  20. up(&dev->sem);
  21. if (dev->parent)
  22. up(&dev->parent->sem);
  23. return 0;
  24. }

首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:

  1. static inline int driver_match_device(struct device_driver *drv,
  2. struct device *dev)
  3. {
  4. return drv->bus->match ? drv->bus->match(dev, drv) : 1;
  5. }

这里直接调用了platform总线的match方法,我们来看下这个方法。

  1. /**
  2. * platform_match - bind platform device to platform driver.
  3. * @dev: device.
  4. * @drv: driver.
  5. *
  6. * Platform device IDs are assumed to be encoded like this:
  7. * "<name><instance>", where <name> is a short description of the type of
  8. * device, like "pci" or "floppy", and <instance> is the enumerated
  9. * instance of the device, like '0' or '42'.  Driver IDs are simply
  10. * "<name>".  So, extract the <name> from the platform_device structure,
  11. * and compare it against the name of the driver. Return whether they match
  12. * or not.
  13. */
  14. static int platform_match(struct device *dev, struct device_driver *drv)
  15. {
  16. struct platform_device *pdev = to_platform_device(dev);
  17. struct platform_driver *pdrv = to_platform_driver(drv);
  18. /* match against the id table first */
  19. if (pdrv->id_table)
  20. return platform_match_id(pdrv->id_table, pdev) != NULL;
  21. /* fall-back to driver name match */
  22. return (strcmp(pdev->name, drv->name) == 0);
  23. }

该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。

在本例中两者同为s3c2410-spi。因此匹配完成,返回1。

返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:

  1. /**
  2. * driver_probe_device - attempt to bind device & driver together
  3. * @drv: driver to bind a device to
  4. * @dev: device to try to bind to the driver
  5. *
  6. * This function returns -ENODEV if the device is not registered,
  7. * 1 if the device is bound sucessfully and 0 otherwise.
  8. *
  9. * This function must be called with @dev->sem held.  When called for a
  10. * USB interface, @dev->parent->sem must be held as well.
  11. */
  12. int driver_probe_device(struct device_driver *drv, struct device *dev)
  13. {
  14. int ret = 0;
  15. if (!device_is_registered(dev))
  16. return -ENODEV;
  17. pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
  18. drv->bus->name, __func__, dev_name(dev), drv->name);
  19. ret = really_probe(dev, drv);
  20. return ret;
  21. }
  22. static inline int device_is_registered(struct device *dev)
  23. {
  24. return dev->kobj.state_in_sysfs;
  25. }

该函数将调用really_probe来绑定设备和它的驱动。

  1. static int really_probe(struct device *dev, struct device_driver *drv)
  2. {
  3. int ret = 0;
  4. atomic_inc(&probe_count);
  5. pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
  6. drv->bus->name, __func__, drv->name, dev_name(dev));
  7. WARN_ON(!list_empty(&dev->devres_head));
  8. dev->driver = drv;
  9. if (driver_sysfs_add(dev)) {    /*创建两个symlink,更新sysfs*/
  10. printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
  11. __func__, dev_name(dev));
  12. goto probe_failed;
  13. }
  14. if (dev->bus->probe) {
  15. ret = dev->bus->probe(dev);/*调用总线的probe方法*/
  16. if (ret)
  17. goto probe_failed;
  18. } else if (drv->probe) {
  19. ret = drv->probe(dev);   /*调用驱动的probe方法*/
  20. if (ret)
  21. goto probe_failed;
  22. }
  23. driver_bound(dev);              /*绑定设备和驱动*/
  24. ret = 1;
  25. pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
  26. drv->bus->name, __func__, dev_name(dev), drv->name);
  27. goto done;
  28. probe_failed:
  29. devres_release_all(dev);
  30. driver_sysfs_remove(dev);
  31. dev->driver = NULL;
  32. if (ret != -ENODEV && ret != -ENXIO) {
  33. /* driver matched but the probe failed */
  34. printk(KERN_WARNING
  35. "%s: probe of %s failed with error %d\n",
  36. drv->name, dev_name(dev), ret);
  37. }
  38. /*
  39. * Ignore errors returned by ->probe so that the next driver can try
  40. * its luck.
  41. */
  42. ret = 0;
  43. done:
  44. atomic_dec(&probe_count);
  45. wake_up(&probe_waitqueue);
  46. return ret;
  47. }

在这个函数中调用4个函数。

第一个函数driver_sysfs_add将更新sysfs。

  1. static int driver_sysfs_add(struct device *dev)
  2. {
  3. int ret;
  4. /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,
  5. 链接指向/sys/devices/platform/XXX */
  6. ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
  7. kobject_name(&dev->kobj));
  8. if (ret == 0) {
  9. /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,
  10. 指向/sys/bus/xxx/drivers目录下的某个目录*/
  11. ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
  12. "driver");
  13. if (ret)
  14. sysfs_remove_link(&dev->driver->p->kobj,
  15. kobject_name(&dev->kobj));
  16. }
  17. return ret;
  18. }

执行完以后,建立了两个链接。

在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.0

在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。

这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi
[root@yj423 s3c2410-spi]#ll s3c2410-spi.0 
lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0

[root@yj423 s3c2410-spi.0]#pwd
/sys/devices/platform/s3c2410-spi.0
[root@yj423 s3c2410-spi.0]#ll driver
lrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi

第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。

第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。

第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。

  1. static void driver_bound(struct device *dev)
  2. {
  3. if (klist_node_attached(&dev->p->knode_driver)) {
  4. printk(KERN_WARNING "%s: device %s already bound\n",
  5. __func__, kobject_name(&dev->kobj));
  6. return;
  7. }
  8. pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
  9. __func__, dev->driver->name);
  10. if (dev->bus)
  11. blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  12. BUS_NOTIFY_BOUND_DRIVER, dev);
  13. klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
  14. }

其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。

至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。

在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。

首先,将驱动添加到总线的驱动列表中。

接着,如果定义了驱动属性文件,则创建。

最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。

我们来验证下:

[root@yj423 s3c2410-spi]#pwd
/sys/bus/platform/drivers/s3c2410-spi
[root@yj423 s3c2410-spi]#ls
bind           s3c2410-spi.0  uevent         unbind

7.7 小结

在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。

同时,还更新了链表的指向,在内核中体现了同样的关系。

最后以platform driver的注册过程结束本章。

8. sysfs底层函数

下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。

在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。

8.1 注册sysfs文件系统

sysfs文件系统的注册是调用sysfs_init函数来完成的,该函数在内核启动阶段被调用,我们来看下大致函数调用流程,这里不作分析。

start_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。


  1. int __init sysfs_init(void)
  2. {
  3. int err = -ENOMEM;
  4. /*建立cache,名字为sysfs_dir_cache*/
  5. sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
  6. sizeof(struct sysfs_dirent),
  7. 0, 0, NULL);
  8. if (!sysfs_dir_cachep)
  9. goto out;
  10. err = sysfs_inode_init();
  11. if (err)
  12. goto out_err;
  13. /*注册文件系统*/
  14. err = register_filesystem(&sysfs_fs_type);
  15. if (!err) {
  16. /*注册成功,加载文件系统*/
  17. sysfs_mount = kern_mount(&sysfs_fs_type);
  18. if (IS_ERR(sysfs_mount)) {
  19. printk(KERN_ERR "sysfs: could not mount!\n");
  20. err = PTR_ERR(sysfs_mount);
  21. sysfs_mount = NULL;
  22. unregister_filesystem(&sysfs_fs_type);
  23. goto out_err;
  24. }
  25. } else
  26. goto out_err;
  27. out:
  28. return err;
  29. out_err:
  30. kmem_cache_destroy(sysfs_dir_cachep);
  31. sysfs_dir_cachep = NULL;
  32. goto out;
  33. }
  34. static struct file_system_type sysfs_fs_type = {
  35. .name        = "sysfs",
  36. .get_sb        = sysfs_get_sb,
  37. .kill_sb    = kill_anon_super,
  38. };

8.1.1 register_filesystem

下列代码位于fs/filesystems.c。

  1. /**
  2. *  register_filesystem - register a new filesystem
  3. *  @fs: the file system structure
  4. *
  5. *  Adds the file system passed to the list of file systems the kernel
  6. *  is aware of for mount and other syscalls. Returns 0 on success,
  7. *  or a negative errno code on an error.
  8. *
  9. *  The &struct file_system_type that is passed is linked into the kernel
  10. *  structures and must not be freed until the file system has been
  11. *  unregistered.
  12. */
  13. int register_filesystem(struct file_system_type * fs)
  14. {
  15. int res = 0;
  16. struct file_system_type ** p;
  17. BUG_ON(strchr(fs->name, '.'));
  18. if (fs->next)
  19. return -EBUSY;
  20. INIT_LIST_HEAD(&fs->fs_supers);
  21. write_lock(&file_systems_lock);
  22. p = find_filesystem(fs->name, strlen(fs->name));  /*查找要住的文件是同是否存在,返回位置*/
  23. if (*p)
  24. res = -EBUSY;   /*该文件系统已存在,返回error*/
  25. else
  26. *p = fs;        /*将新的文件系统加入到链表中*/
  27. write_unlock(&file_systems_lock);
  28. return res;
  29. }
  1. static struct file_system_type **find_filesystem(const char *name, unsigned len)
  2. {
  3. struct file_system_type **p;
  4. for (p=&file_systems; *p; p=&(*p)->next)
  5. if (strlen((*p)->name) == len &&
  6. strncmp((*p)->name, name, len) == 0)
  7. break;
  8. return p;
  9. }


该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。

如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。

该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。

8.1.2 kern_mount函数

下列代码位于include/linux/fs.h

  1. #define kern_mount(type) kern_mount_data(type, NULL)

下列代码位于fs/sysfs/mount.c

  1. struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
  2. {
  3. return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
  4. }
  5. EXPORT_SYMBOL_GPL(kern_mount_data);

kern_mount实际上最后是调用了vfs_kern_mount函数。我们来看下:

  1. struct vfsmount *
  2. vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
  3. {
  4. struct vfsmount *mnt;
  5. char *secdata = NULL;
  6. int error;
  7. if (!type)
  8. return ERR_PTR(-ENODEV);
  9. error = -ENOMEM;
  10. mnt = alloc_vfsmnt(name);   /*分配struct vfsmount*/
  11. if (!mnt)
  12. goto out;
  13. if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
  14. secdata = alloc_secdata();
  15. if (!secdata)
  16. goto out_mnt;
  17. error = security_sb_copy_data(data, secdata);
  18. if (error)
  19. goto out_free_secdata;
  20. }
  21. /*get_sb方法,分配superblock对象,并初始化*/
  22. error = type->get_sb(type, flags, name, data, mnt);
  23. if (error < 0)
  24. goto out_free_secdata;
  25. BUG_ON(!mnt->mnt_sb);
  26. error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
  27. if (error)
  28. goto out_sb;
  29. mnt->mnt_mountpoint = mnt->mnt_root;/*设置挂载点的dentry*/
  30. mnt->mnt_parent = mnt;           /*设置所挂载的fs为自己本身*/
  31. up_write(&mnt->mnt_sb->s_umount);
  32. free_secdata(secdata);
  33. return mnt;
  34. out_sb:
  35. dput(mnt->mnt_root);
  36. deactivate_locked_super(mnt->mnt_sb);
  37. out_free_secdata:
  38. free_secdata(secdata);
  39. out_mnt:
  40. free_vfsmnt(mnt);
  41. out:
  42. return ERR_PTR(error);
  43. }

该函数在首先调用alloc_vfsmnt来分配struct vfsmount结构,并做了一些初试化工作。

下列函数位于fs/super.c

  1. struct vfsmount *alloc_vfsmnt(const char *name)
  2. {
  3. struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
  4. if (mnt) {
  5. int err;
  6. err = mnt_alloc_id(mnt);    /*设置mnt->mnt_id*/
  7. if (err)
  8. goto out_free_cache;
  9. if (name) {
  10. mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷贝name,并赋值*/
  11. if (!mnt->mnt_devname)
  12. goto out_free_id;
  13. }
  14. atomic_set(&mnt->mnt_count, 1);
  15. INIT_LIST_HEAD(&mnt->mnt_hash);
  16. INIT_LIST_HEAD(&mnt->mnt_child);
  17. INIT_LIST_HEAD(&mnt->mnt_mounts);
  18. INIT_LIST_HEAD(&mnt->mnt_list);
  19. INIT_LIST_HEAD(&mnt->mnt_expire);
  20. INIT_LIST_HEAD(&mnt->mnt_share);
  21. INIT_LIST_HEAD(&mnt->mnt_slave_list);
  22. INIT_LIST_HEAD(&mnt->mnt_slave);
  23. atomic_set(&mnt->__mnt_writers, 0);
  24. }
  25. return mnt;
  26. out_free_id:
  27. mnt_free_id(mnt);
  28. out_free_cache:
  29. kmem_cache_free(mnt_cache, mnt);
  30. return NULL;
  31. }

分配好结构体以后,由于参数data为NULL,将直接调用文件系统类型提供的get_sb方法,该方法就是函数sysfs_get_sb。我们来看下:

下列函数位于fs/sysfs/mount.c。

  1. static int sysfs_get_sb(struct file_system_type *fs_type,
  2. int flags, const char *dev_name, void *data, struct vfsmount *mnt)
  3. {
  4. return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
  5. }

这里直接调用了get_sb_single函数,注意这里的第4个实参sysfs_fill_super,该参数是函数名,后面将会调用该函数。

该函数将分配sysfs文件系统的superblock,获取文件系统根目录的inode和dentry。

该函数的执行过程相当复杂,在下一节单独讲述。

8.2 get_sb_single函数

下列函数位于fs/sysfs/mount.c。

  1. int get_sb_single(struct file_system_type *fs_type,
  2. int flags, void *data,
  3. int (*fill_super)(struct super_block *, void *, int),
  4. struct vfsmount *mnt)
  5. {
  6. struct super_block *s;
  7. int error;
  8. /*查找或者创建super_block*/
  9. s = sget(fs_type, compare_single, set_anon_super, NULL);
  10. if (IS_ERR(s))
  11. return PTR_ERR(s);
  12. if (!s->s_root) {        /*没有根目录dentry*/
  13. s->s_flags = flags;
  14. /*获取root( / )的 inode和dentry*/
  15. error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
  16. if (error) {
  17. deactivate_locked_super(s);
  18. return error;
  19. }
  20. s->s_flags |= MS_ACTIVE;
  21. }
  22. do_remount_sb(s, flags, data, 0);
  23. simple_set_mnt(mnt, s); /*设置vfsmount的superblock和根dentry*/
  24. return 0;
  25. }
  26. EXPORT_SYMBOL(get_sb_single);

8.2.1 sget函数

首先调用了sget函数来查找是否

下列函数位于fs/super.c。

  1. /**
  2. *  sget    -   find or create a superblock
  3. *  @type:  filesystem type superblock should belong to
  4. *  @test:  comparison callback
  5. *  @set:   setup callback
  6. *  @data:  argument to each of them
  7. */
  8. struct super_block *sget(struct file_system_type *type,
  9. int (*test)(struct super_block *,void *),
  10. int (*set)(struct super_block *,void *),
  11. void *data)
  12. {
  13. struct super_block *s = NULL;
  14. struct super_block *old;
  15. int err;
  16. retry:
  17. spin_lock(&sb_lock);
  18. if (test) {
  19. /*遍历所有属于该文件系统的super_block*/
  20. list_for_each_entry(old, &type->fs_supers, s_instances) {
  21. if (!test(old, data))
  22. continue;
  23. if (!grab_super(old))
  24. goto retry;
  25. if (s) {
  26. up_write(&s->s_umount);
  27. destroy_super(s);
  28. }
  29. return old;
  30. }
  31. }
  32. if (!s) {
  33. spin_unlock(&sb_lock);
  34. s = alloc_super(type);  /*创建新的super_block并初始化*/
  35. if (!s)
  36. return ERR_PTR(-ENOMEM);
  37. goto retry;
  38. }
  39. err = set(s, data);     /*设置s->s_dev */
  40. if (err) {
  41. spin_unlock(&sb_lock);
  42. up_write(&s->s_umount);
  43. destroy_super(s);
  44. return ERR_PTR(err);
  45. }
  46. s->s_type = type;
  47. strlcpy(s->s_id, type->name, sizeof(s->s_id)); /*拷贝name*/
  48. list_add_tail(&s->s_list, &super_blocks);        /*将新的super_block添加到链表头super_blocks中*/
  49. list_add(&s->s_instances, &type->fs_supers);  /*将新的super_block添加到相应的文件系统类型的链表中*/
  50. spin_unlock(&sb_lock);
  51. get_filesystem(type);
  52. return s;
  53. }
  54. EXPORT_SYMBOL(sget);

该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。

然后调用alloc_super函数来创建新的struct super_block。

下列函数位于fs/super.c。

  1. /**
  2. *  alloc_super -   create new superblock
  3. *  @type:  filesystem type superblock should belong to
  4. *
  5. *  Allocates and initializes a new &struct super_block.  alloc_super()
  6. *  returns a pointer new superblock or %NULL if allocation had failed.
  7. */
  8. static struct super_block *alloc_super(struct file_system_type *type)
  9. {
  10. struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配并清0super_block*/
  11. static struct super_operations default_op;
  12. if (s) {
  13. if (security_sb_alloc(s)) {
  14. kfree(s);
  15. s = NULL;
  16. goto out;
  17. }
  18. INIT_LIST_HEAD(&s->s_dirty);
  19. INIT_LIST_HEAD(&s->s_io);
  20. INIT_LIST_HEAD(&s->s_more_io);
  21. INIT_LIST_HEAD(&s->s_files);
  22. INIT_LIST_HEAD(&s->s_instances);
  23. INIT_HLIST_HEAD(&s->s_anon);
  24. INIT_LIST_HEAD(&s->s_inodes);
  25. INIT_LIST_HEAD(&s->s_dentry_lru);
  26. INIT_LIST_HEAD(&s->s_async_list);
  27. init_rwsem(&s->s_umount);
  28. mutex_init(&s->s_lock);
  29. lockdep_set_class(&s->s_umount, &type->s_umount_key);
  30. /*
  31. * The locking rules for s_lock are up to the
  32. * filesystem. For example ext3fs has different
  33. * lock ordering than usbfs:
  34. */
  35. lockdep_set_class(&s->s_lock, &type->s_lock_key);
  36. /*
  37. * sget() can have s_umount recursion.
  38. *
  39. * When it cannot find a suitable sb, it allocates a new
  40. * one (this one), and tries again to find a suitable old
  41. * one.
  42. *
  43. * In case that succeeds, it will acquire the s_umount
  44. * lock of the old one. Since these are clearly distrinct
  45. * locks, and this object isn't exposed yet, there's no
  46. * risk of deadlocks.
  47. *
  48. * Annotate this by putting this lock in a different
  49. * subclass.
  50. */
  51. down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
  52. s->s_count = S_BIAS;
  53. atomic_set(&s->s_active, 1);
  54. mutex_init(&s->s_vfs_rename_mutex);
  55. mutex_init(&s->s_dquot.dqio_mutex);
  56. mutex_init(&s->s_dquot.dqonoff_mutex);
  57. init_rwsem(&s->s_dquot.dqptr_sem);
  58. init_waitqueue_head(&s->s_wait_unfrozen);
  59. s->s_maxbytes = MAX_NON_LFS;
  60. s->dq_op = sb_dquot_ops;
  61. s->s_qcop = sb_quotactl_ops;
  62. s->s_op = &default_op;
  63. s->s_time_gran = 1000000000;
  64. }
  65. out:
  66. return s;
  67. }

分配完以后,调用作为参数传入的函数指针set,也就是set_anon_super函数,该函数用来设置s->s_dev。

下列函数位于fs/super.c。

  1. int set_anon_super(struct super_block *s, void *data)
  2. {
  3. int dev;
  4. int error;
  5. retry:
  6. if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID号*/
  7. return -ENOMEM;
  8. spin_lock(&unnamed_dev_lock);
  9. error = ida_get_new(&unnamed_dev_ida, &dev);/*获取ID号,保存在dev中*/
  10. spin_unlock(&unnamed_dev_lock);
  11. if (error == -EAGAIN)
  12. /* We raced and lost with another CPU. */
  13. goto retry;
  14. else if (error)
  15. return -EAGAIN;
  16. if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
  17. spin_lock(&unnamed_dev_lock);
  18. ida_remove(&unnamed_dev_ida, dev);
  19. spin_unlock(&unnamed_dev_lock);
  20. return -EMFILE;
  21. }
  22. s->s_dev = MKDEV(0, dev & MINORMASK);    /*构建设备号*/
  23. return 0;
  24. }

8.2.2  sysfs_fill_super函数

分配了super_block之后,将判断该super_block是否有root dentry。本例中,显然没有。然后调用形参fill_super指向的函数,也就是sysfs_fill_super函数。

下列函数位于fs/sysfs/mount.c。

  1. struct super_block * sysfs_sb = NULL;
  2. static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
  3. {
  4. struct inode *inode;
  5. struct dentry *root;
  6. sb->s_blocksize = PAGE_CACHE_SIZE;   /*4KB*/
  7. sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/
  8. sb->s_magic = SYSFS_MAGIC;           /*0x62656572*/
  9. sb->s_op = &sysfs_ops;
  10. sb->s_time_gran = 1;
  11. sysfs_sb = sb;      /*sysfs_sb即为sysfs的super_block*/
  12. /* get root inode, initialize and unlock it */
  13. mutex_lock(&sysfs_mutex);
  14. inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即为sysfs所在的根目录的dirent,,获取inode*/
  15. mutex_unlock(&sysfs_mutex);
  16. if (!inode) {
  17. pr_debug("sysfs: could not get root inode\n");
  18. return -ENOMEM;
  19. }
  20. /* instantiate and link root dentry */
  21. root = d_alloc_root(inode); /*为获得的根inode分配root(/) dentry*/
  22. if (!root) {
  23. pr_debug("%s: could not get root dentry!\n",__func__);
  24. iput(inode);
  25. return -ENOMEM;
  26. }
  27. root->d_fsdata = &sysfs_root;
  28. sb->s_root = root;   /*保存superblock的根dentry*/
  29. return 0;
  30. }
  31. struct sysfs_dirent sysfs_root = {    /*sysfs_root即为sysfs所在的根目录的dirent*/
  32. .s_name        = "",
  33. .s_count    = ATOMIC_INIT(1),
  34. .s_flags    = SYSFS_DIR,
  35. .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
  36. .s_ino        = 1,
  37. };

在设置了一些字段后,设置了sysfs_sb这个全局变量,该全局变量表示的就是sysfs的super_block。

随后,调用了sysfs_get_inode函数,来获取sysfs的根目录的dirent。该函数的参数sysfs_root为全局变量,表示sysfs的根目录的sysfs_dirent。

我们看些这个sysfs_dirent数据结构:

  1. /*
  2. * sysfs_dirent - the building block of sysfs hierarchy.  Each and
  3. * every sysfs node is represented by single sysfs_dirent.
  4. *
  5. * As long as s_count reference is held, the sysfs_dirent itself is
  6. * accessible.  Dereferencing s_elem or any other outer entity
  7. * requires s_active reference.
  8. */
  9. struct sysfs_dirent {
  10. atomic_t        s_count;
  11. atomic_t        s_active;
  12. struct sysfs_dirent *s_parent;
  13. struct sysfs_dirent *s_sibling;
  14. const char      *s_name;
  15. union {
  16. struct sysfs_elem_dir       s_dir;
  17. struct sysfs_elem_symlink   s_symlink;
  18. struct sysfs_elem_attr      s_attr;
  19. struct sysfs_elem_bin_attr  s_bin_attr;
  20. };
  21. unsigned int        s_flags;
  22. ino_t           s_ino;
  23. umode_t         s_mode;
  24. struct iattr        *s_iattr;
  25. };

其中比较关键的就是那个联合体,针对不同的形式(目录,symlink,属性文件和可执行文件)将使用不同的数据结构。

另外,sysfs_dirent将最为dentry的fs专有数据被保存下来,这一点会在下面中看到。

接着,在来看下sysfs_get_inode函数:

下列函数位于fs/sysfs/inode.c。

  1. /**
  2. *  sysfs_get_inode - get inode for sysfs_dirent
  3. *  @sd: sysfs_dirent to allocate inode for
  4. *
  5. *  Get inode for @sd.  If such inode doesn't exist, a new inode
  6. *  is allocated and basics are initialized.  New inode is
  7. *  returned locked.
  8. *
  9. *  LOCKING:
  10. *  Kernel thread context (may sleep).
  11. *
  12. *  RETURNS:
  13. *  Pointer to allocated inode on success, NULL on failure.
  14. */
  15. struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
  16. {
  17. struct inode *inode;
  18. inode = iget_locked(sysfs_sb, sd->s_ino);    /*在inode cache查找inode是否存在,不存在侧创建一个*/
  19. if (inode && (inode->i_state & I_NEW))       /*如果是新创建的inode,则包含I_NEW*/
  20. sysfs_init_inode(sd, inode);
  21. return inode;
  22. }
  23. /**
  24. * iget_locked - obtain an inode from a mounted file system
  25. * @sb:        super block of file system
  26. * @ino:    inode number to get
  27. *
  28. * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
  29. * the inode cache and if present it is returned with an increased reference
  30. * count. This is for file systems where the inode number is sufficient for
  31. * unique identification of an inode.
  32. *
  33. * If the inode is not in cache, get_new_inode_fast() is called to allocate a
  34. * new inode and this is returned locked, hashed, and with the I_NEW flag set.
  35. * The file system gets to fill it in before unlocking it via
  36. * unlock_new_inode().
  37. */
  38. struct inode *iget_locked(struct super_block *sb, unsigned long ino)
  39. {
  40. struct hlist_head *head = inode_hashtable + hash(sb, ino);
  41. struct inode *inode;
  42. inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/
  43. if (inode)
  44. return inode;         /*找到了该inode*/
  45. /*
  46. * get_new_inode_fast() will do the right thing, re-trying the search
  47. * in case it had to block at any point.
  48. */
  49. return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/
  50. }
  51. EXPORT_SYMBOL(iget_locked);
  52. static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
  53. {
  54. struct bin_attribute *bin_attr;
  55. inode->i_private = sysfs_get(sd);
  56. inode->i_mapping->a_ops = &sysfs_aops;
  57. inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
  58. inode->i_op = &sysfs_inode_operations;
  59. inode->i_ino = sd->s_ino;
  60. lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
  61. if (sd->s_iattr) {
  62. /* sysfs_dirent has non-default attributes
  63. * get them for the new inode from persistent copy
  64. * in sysfs_dirent
  65. */
  66. set_inode_attr(inode, sd->s_iattr);
  67. } else
  68. set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/
  69. /* initialize inode according to type */
  70. switch (sysfs_type(sd)) {
  71. case SYSFS_DIR:
  72. inode->i_op = &sysfs_dir_inode_operations;
  73. inode->i_fop = &sysfs_dir_operations;
  74. inode->i_nlink = sysfs_count_nlink(sd);
  75. break;
  76. case SYSFS_KOBJ_ATTR:
  77. inode->i_size = PAGE_SIZE;
  78. inode->i_fop = &sysfs_file_operations;
  79. break;
  80. case SYSFS_KOBJ_BIN_ATTR:
  81. bin_attr = sd->s_bin_attr.bin_attr;
  82. inode->i_size = bin_attr->size;
  83. inode->i_fop = &bin_fops;
  84. break;
  85. case SYSFS_KOBJ_LINK:
  86. inode->i_op = &sysfs_symlink_inode_operations;
  87. break;
  88. default:
  89. BUG();
  90. }
  91. unlock_new_inode(inode);
  92. }

该函数首先调用了,iget_locked来查找该inode是否已存在,如果不存在则创建。如果是新创建的inode,则对inode进行初始化。
再获取了根目录的inode和sysfs_dirent后,调用d_alloc_root来获得dirent。

  1. /**
  2. * d_alloc_root - allocate root dentry
  3. * @root_inode: inode to allocate the root for
  4. *
  5. * Allocate a root ("/") dentry for the inode given. The inode is
  6. * instantiated and returned. %NULL is returned if there is insufficient
  7. * memory or the inode passed is %NULL.
  8. */
  9. struct dentry * d_alloc_root(struct inode * root_inode)
  10. {
  11. struct dentry *res = NULL;
  12. if (root_inode) {
  13. static const struct qstr name = { .name = "/", .len = 1 };
  14. res = d_alloc(NULL, &name); /*分配struct dentry,没有父dentry*/
  15. if (res) {
  16. res->d_sb = root_inode->i_sb;
  17. res->d_parent = res;
  18. d_instantiated_instantiate(res, root_inode); /*绑定inode和dentry之间的关系*/
  19. }
  20. }
  21. return res;
  22. }
  23. /**
  24. * d_alloc    -    allocate a dcache entry
  25. * @parent: parent of entry to allocate
  26. * @name: qstr of the name
  27. *
  28. * Allocates a dentry. It returns %NULL if there is insufficient memory
  29. * available. On a success the dentry is returned. The name passed in is
  30. * copied and the copy passed in may be reused after this call.
  31. */
  32. struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
  33. {
  34. struct dentry *dentry;
  35. char *dname;
  36. dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/
  37. if (!dentry)
  38. return NULL;
  39. if (name->len > DNAME_INLINE_LEN-1) {
  40. dname = kmalloc(name->len + 1, GFP_KERNEL);
  41. if (!dname) {
  42. kmem_cache_free(dentry_cache, dentry);
  43. return NULL;
  44. }
  45. } else  {
  46. dname = dentry->d_iname;
  47. }
  48. dentry->d_name.name = dname;
  49. dentry->d_name.len = name->len;
  50. dentry->d_name.hash = name->hash;
  51. memcpy(dname, name->name, name->len);
  52. dname[name->len] = 0;
  53. atomic_set(&dentry->d_count, 1);
  54. dentry->d_flags = DCACHE_UNHASHED;
  55. spin_lock_init(&dentry->d_lock);
  56. dentry->d_inode = NULL;
  57. dentry->d_parent = NULL;
  58. dentry->d_sb = NULL;
  59. dentry->d_op = NULL;
  60. dentry->d_fsdata = NULL;
  61. dentry->d_mounted = 0;
  62. INIT_HLIST_NODE(&dentry->d_hash);
  63. INIT_LIST_HEAD(&dentry->d_lru);
  64. INIT_LIST_HEAD(&dentry->d_subdirs);
  65. INIT_LIST_HEAD(&dentry->d_alias);
  66. if (parent) {    /*有父目录,则设置指针来表示关系*/
  67. dentry->d_parent = dget(parent);
  68. dentry->d_sb = parent->d_sb;  /*根dentry的父对象为自己*/
  69. } else {
  70. INIT_LIST_HEAD(&dentry->d_u.d_child);
  71. }
  72. spin_lock(&dcache_lock);
  73. if (parent)        /*有父目录,则添加到父目录的儿子链表中*/
  74. list_add(&dentry->d_u.d_child, &parent->d_subdirs);
  75. dentry_stat.nr_dentry++;
  76. spin_unlock(&dcache_lock);
  77. return dentry;
  78. }
  79. /**
  80. * d_instantiate - fill in inode information for a dentry
  81. * @entry: dentry to complete
  82. * @inode: inode to attach to this dentry
  83. *
  84. * Fill in inode information in the entry.
  85. *
  86. * This turns negative dentries into productive full members
  87. * of society.
  88. *
  89. * NOTE! This assumes that the inode count has been incremented
  90. * (or otherwise set) by the caller to indicate that it is now
  91. * in use by the dcache.
  92. */
  93. void d_instantiate(struct dentry *entry, struct inode * inode)
  94. {
  95. BUG_ON(!list_empty(&entry->d_alias));
  96. spin_lock(&dcache_lock);
  97. __d_instantiate(entry, inode);
  98. spin_unlock(&dcache_lock);
  99. security_d_instantiate(entry, inode);
  100. }
  101. /* the caller must hold dcache_lock */
  102. static void __d_instantiate(struct dentry *dentry, struct inode *inode)
  103. {
  104. if (inode)
  105. list_add(&dentry->d_alias, &inode->i_dentry);/*将dentry添加到inode的链表中*/
  106. dentry->d_inode = inode;        /*保存dentry对应的inode*/
  107. fsnotify_d_instantiate(dentry, inode);
  108. }

该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。

接着调用d_instantiate来绑定inode和dentry之间的关系。

在sysfs_fill_super函数执行的最后,将sysfs_root保存到了dentry->d_fsdata。

可见,在sysfs中用sysfs_dirent来表示目录,但是对于VFS,还是要使用dentry来表示目录。

8.2.3  do_remount_sb

下列代码位于fs/super.c。

  1. /**
  2. *  do_remount_sb - asks filesystem to change mount options.
  3. *  @sb:    superblock in question
  4. *  @flags: numeric part of options
  5. *  @data:  the rest of options
  6. *      @force: whether or not to force the change
  7. *
  8. *  Alters the mount options of a mounted file system.
  9. */
  10. int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
  11. {
  12. int retval;
  13. int remount_rw;
  14. #ifdef CONFIG_BLOCK
  15. if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
  16. return -EACCES;
  17. #endif
  18. if (flags & MS_RDONLY)
  19. acct_auto_close(sb);
  20. shrink_dcache_sb(sb);
  21. fsync_super(sb);
  22. /* If we are remounting RDONLY and current sb is read/write,
  23. make sure there are no rw files opened */
  24. if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {
  25. if (force)
  26. mark_files_ro(sb);
  27. else if (!fs_may_remount_ro(sb))
  28. return -EBUSY;
  29. retval = vfs_dq_off(sb, 1);
  30. if (retval < 0 && retval != -ENOSYS)
  31. return -EBUSY;
  32. }
  33. remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
  34. if (sb->s_op->remount_fs) {
  35. lock_super(sb);
  36. retval = sb->s_op->remount_fs(sb, &flags, data);
  37. unlock_super(sb);
  38. if (retval)
  39. return retval;
  40. }
  41. sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
  42. if (remount_rw)
  43. vfs_dq_quota_on_remount(sb);
  44. return 0;
  45. }

这个函数用来修改挂在选项,这个函数就不分析了,不是重点。

8.2.4simple_set_mnt

下列函数位于fs/namespace.c。

  1. void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
  2. {
  3. mnt->mnt_sb = sb;
  4. mnt->mnt_root = dget(sb->s_root);
  5. }

该函数设置了vfsmount的superblock和根dentry。

8.2.5 小结

这里,对sysfs的注册过程做一个总结。

sysfs_init函数调用过程示意图如下:

在整个过程中,先后使用和创建了许多struct

第一,根据file_system_type表示的sysfs文件系统的类型注册了sysfs。

第二,建立了vfsmount。

第三,创建了超级块super_block。

第四,根据sysfs_dirent表示的根目录,建立了inode。

最后,根据刚才建立的inode创建了dentry。

除了sysfs_dirent,其他5个结构体都是VFS中基本的数据结构,而sysfs_dirent则是特定于sysfs文件系统的数据结构。

8.3 创建目录

在前面的描述中,使用sysfs_create_dir在sysfs下建立一个目录。我们来看下这个函数是如何来建立目录的。

下列代码位于fs/sysfs/dir.c。

  1. /**
  2. *  sysfs_create_dir - create a directory for an object.
  3. *  @kobj:      object we're creating directory for.
  4. */
  5. int sysfs_create_dir(struct kobject * kobj)
  6. {
  7. struct sysfs_dirent *parent_sd, *sd;
  8. int error = 0;
  9. BUG_ON(!kobj);
  10. if (kobj->parent)    /*如果有parent,获取parent对应的sys目录*/
  11. parent_sd = kobj->parent->sd;
  12. else                /*没有则是在sys根目录*/
  13. parent_sd = &sysfs_root;
  14. error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
  15. if (!error)
  16. kobj->sd = sd;
  17. return error;
  18. }

函数中,首先获取待建目录的父sysfs_dirent,然后将它作为参数 来调用create_dir函数。

很明显,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent将保存到参数sd中。

下列代码位于fs/sysfs/dir.c。

  1. static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
  2. const char *name, struct sysfs_dirent **p_sd)
  3. {
  4. umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
  5. struct sysfs_addrm_cxt acxt;
  6. struct sysfs_dirent *sd;
  7. int rc;
  8. /* allocate */  /*分配sysfs_dirent并初始化*/
  9. sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
  10. if (!sd)
  11. return -ENOMEM;
  12. sd->s_dir.kobj = kobj;    /*保存kobject对象*/
  13. /* link in */
  14. sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
  15. rc = sysfs_add_one(&acxt, sd);  /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/
  16. sysfs_addrm_finish(&acxt);      /*收尾工作*/
  17. if (rc == 0)        /*rc为0表示创建成功*/
  18. *p_sd = sd;
  19. else
  20. sysfs_put(sd);  /*增加引用计数*/
  21. return rc;
  22. }

这里要注意一下mode变量,改变了使用了宏定义SYSFS_DIR,这个就表示要创建的是一个目录。

mode还有几个宏定义可以使用,如下:

  1. #define SYSFS_KOBJ_ATTR         0x0002
  2. #define SYSFS_KOBJ_BIN_ATTR     0x0004
  3. #define SYSFS_KOBJ_LINK         0x0008
  4. #define SYSFS_COPY_NAME         (SYSFS_DIR | SYSFS_KOBJ_LINK)

8.3.1 sysfs_new_dirent

在create_dir函数中,首先调用了sysfs_new_dirent来建立一个新的sysfs_dirent结构体。

下列代码位于fs/sysfs/dir.c。

  1. struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
  2. {
  3. char *dup_name = NULL;
  4. struct sysfs_dirent *sd;
  5. if (type & SYSFS_COPY_NAME) {
  6. name = dup_name = kstrdup(name, GFP_KERNEL);
  7. if (!name)
  8. return NULL;
  9. }
  10. /*分配sysfs_dirent并清0*/
  11. sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
  12. if (!sd)
  13. goto err_out1;
  14. if (sysfs_alloc_ino(&sd->s_ino)) /*分配ID号*/
  15. goto err_out2;
  16. atomic_set(&sd->s_count, 1);
  17. atomic_set(&sd->s_active, 0);
  18. sd->s_name = name;
  19. sd->s_mode = mode;
  20. sd->s_flags = type;
  21. return sd;
  22. err_out2:
  23. kmem_cache_free(sysfs_dir_cachep, sd);
  24. err_out1:
  25. kfree(dup_name);
  26. return NULL;
  27. }

8.3.2 有关sysfs_dirent中的联合体

分配了sysfs_dirent后,设置了该结构中的联合体数据。先来看下联合体中的四个数据结构。

  1. /* type-specific structures for sysfs_dirent->s_* union members */
  2. struct sysfs_elem_dir {
  3. struct kobject      *kobj;
  4. /* children list starts here and goes through sd->s_sibling */
  5. struct sysfs_dirent *children;
  6. };
  7. struct sysfs_elem_symlink {
  8. struct sysfs_dirent    *target_sd;
  9. };
  10. struct sysfs_elem_attr {
  11. struct attribute    *attr;
  12. struct sysfs_open_dirent *open;
  13. };
  14. struct sysfs_elem_bin_attr {
  15. struct bin_attribute    *bin_attr;
  16. struct hlist_head    buffers;
  17. };

根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。

在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。

在8.4和8.5中我们将分别看到sysfs_elem_attr和sysfs_elem_symlink的使用。

8.3.3 sysfs_addrm_start

在获取了父sysfs_dirent,调用sysfs_addrm_start来获取与之对应的inode。

下列代码位于fs/sysfs/dir.c。

  1. /**
  2. *  sysfs_addrm_start - prepare for sysfs_dirent add/remove
  3. *  @acxt: pointer to sysfs_addrm_cxt to be used
  4. *  @parent_sd: parent sysfs_dirent
  5. *
  6. *  This function is called when the caller is about to add or
  7. *  remove sysfs_dirent under @parent_sd.  This function acquires
  8. *  sysfs_mutex, grabs inode for @parent_sd if available and lock
  9. *  i_mutex of it.  @acxt is used to keep and pass context to
  10. *  other addrm functions.
  11. *
  12. *  LOCKING:
  13. *  Kernel thread context (may sleep).  sysfs_mutex is locked on
  14. *  return.  i_mutex of parent inode is locked on return if
  15. *  available.
  16. */
  17. void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
  18. struct sysfs_dirent *parent_sd)
  19. {
  20. struct inode *inode;
  21. memset(acxt, 0, sizeof(*acxt));
  22. acxt->parent_sd = parent_sd;
  23. /* Lookup parent inode.  inode initialization is protected by
  24. * sysfs_mutex, so inode existence can be determined by
  25. * looking up inode while holding sysfs_mutex.
  26. */
  27. mutex_lock(&sysfs_mutex);
  28. /*根据parent_sd来寻找父inode*/
  29. inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
  30. parent_sd);
  31. if (inode) {
  32. WARN_ON(inode->i_state & I_NEW);
  33. /* parent inode available */
  34. acxt->parent_inode = inode;      /*保存找到的父inode*/
  35. /* sysfs_mutex is below i_mutex in lock hierarchy.
  36. * First, trylock i_mutex.  If fails, unlock
  37. * sysfs_mutex and lock them in order.
  38. */
  39. if (!mutex_trylock(&inode->i_mutex)) {
  40. mutex_unlock(&sysfs_mutex);
  41. mutex_lock(&inode->i_mutex);
  42. mutex_lock(&sysfs_mutex);
  43. }
  44. }
  45. }
  46. /*
  47. * Context structure to be used while adding/removing nodes.
  48. */
  49. struct sysfs_addrm_cxt {
  50. struct sysfs_dirent    *parent_sd;
  51. struct inode        *parent_inode;
  52. struct sysfs_dirent    *removed;
  53. int            cnt;
  54. };

注意形参sysfs_addrm_cxt,该结构作用是临时存放数据。

8.3.4 sysfs_add_one

下列代码位于fs/sysfs/dir.c。

  1. /**
  2. *  sysfs_add_one - add sysfs_dirent to parent
  3. *  @acxt: addrm context to use
  4. *  @sd: sysfs_dirent to be added
  5. *
  6. *  Get @acxt->parent_sd and set sd->s_parent to it and increment
  7. *  nlink of parent inode if @sd is a directory and link into the
  8. *  children list of the parent.
  9. *
  10. *  This function should be called between calls to
  11. *  sysfs_addrm_start() and sysfs_addrm_finish() and should be
  12. *  passed the same @acxt as passed to sysfs_addrm_start().
  13. *
  14. *  LOCKING:
  15. *  Determined by sysfs_addrm_start().
  16. *
  17. *  RETURNS:
  18. *  0 on success, -EEXIST if entry with the given name already
  19. *  exists.
  20. */
  21. int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
  22. {
  23. int ret;
  24. ret = __sysfs_add_one(acxt, sd);
  25. if (ret == -EEXIST) {
  26. char *path = kzalloc(PATH_MAX, GFP_KERNEL);
  27. WARN(1, KERN_WARNING
  28. "sysfs: cannot create duplicate filename '%s'\n",
  29. (path == NULL) ? sd->s_name :
  30. strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),
  31. sd->s_name));
  32. kfree(path);
  33. }
  34. return ret;
  35. }
  36. /**
  37. *    __sysfs_add_one - add sysfs_dirent to parent without warning
  38. *    @acxt: addrm context to use
  39. *    @sd: sysfs_dirent to be added
  40. *
  41. *    Get @acxt->parent_sd and set sd->s_parent to it and increment
  42. *    nlink of parent inode if @sd is a directory and link into the
  43. *    children list of the parent.
  44. *
  45. *    This function should be called between calls to
  46. *    sysfs_addrm_start() and sysfs_addrm_finish() and should be
  47. *    passed the same @acxt as passed to sysfs_addrm_start().
  48. *
  49. *    LOCKING:
  50. *    Determined by sysfs_addrm_start().
  51. *
  52. *    RETURNS:
  53. *    0 on success, -EEXIST if entry with the given name already
  54. *    exists.
  55. */
  56. int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
  57. {
  58. /*查找该parent_sd下有无将要建立的sd,没有返回NULL*/
  59. if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
  60. return -EEXIST;
  61. sd->s_parent = sysfs_get(acxt->parent_sd);    /*设置父sysfs_dirent,增加父sysfs_dirent的引用计数*/
  62. if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要创建的是目录或文件,并且有父inode*/
  63. inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/
  64. acxt->cnt++;
  65. sysfs_link_sibling(sd);
  66. return 0;
  67. }
  68. /**
  69. *    sysfs_find_dirent - find sysfs_dirent with the given name
  70. *    @parent_sd: sysfs_dirent to search under
  71. *    @name: name to look for
  72. *
  73. *    Look for sysfs_dirent with name @name under @parent_sd.
  74. *
  75. *    LOCKING:
  76. *    mutex_lock(sysfs_mutex)
  77. *
  78. *    RETURNS:
  79. *    Pointer to sysfs_dirent if found, NULL if not.
  80. */
  81. struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
  82. const unsigned char *name)
  83. {
  84. struct sysfs_dirent *sd;
  85. for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
  86. if (!strcmp(sd->s_name, name))
  87. return sd;
  88. return NULL;
  89. }
  90. /**
  91. *    sysfs_link_sibling - link sysfs_dirent into sibling list
  92. *    @sd: sysfs_dirent of interest
  93. *
  94. *    Link @sd into its sibling list which starts from
  95. *    sd->s_parent->s_dir.children.
  96. *
  97. *    Locking:
  98. *    mutex_lock(sysfs_mutex)
  99. */
  100. static void sysfs_link_sibling(struct sysfs_dirent *sd)
  101. {
  102. struct sysfs_dirent *parent_sd = sd->s_parent;
  103. struct sysfs_dirent **pos;
  104. BUG_ON(sd->s_sibling);
  105. /* Store directory entries in order by ino.  This allows
  106. * readdir to properly restart without having to add a
  107. * cursor into the s_dir.children list.
  108. */
  109. /*children链表根据s_ino按升序排列,现在将sd插入到正确的儿子链表中*/
  110. for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
  111. if (sd->s_ino < (*pos)->s_ino)
  112. break;
  113. }
  114. /*插入链表*/
  115. sd->s_sibling = *pos;
  116. *pos = sd;
  117. }

该函数直接调用了__sysfs_add_one,后者先调用sysfs_find_dirent来查找该parent_sd下有无该的sysfs_dirent,如果没有,则设置创建好的新的sysfs_dirent的s_parent字段。也就是将新的sysfs_dirent添加到父sys_dirent中。接着调用sysfs_link_sibling函数,将新建的sysfs_dirent添加到sd->s_parent->s_dir.children链表中。

8.3.5 sysfs_addrm_finish

下列代码位于fs/sysfs/dir.c。

  1. /**
  2. *  sysfs_addrm_finish - finish up sysfs_dirent add/remove
  3. *  @acxt: addrm context to finish up
  4. *
  5. *  Finish up sysfs_dirent add/remove.  Resources acquired by
  6. *  sysfs_addrm_start() are released and removed sysfs_dirents are
  7. *  cleaned up.  Timestamps on the parent inode are updated.
  8. *
  9. *  LOCKING:
  10. *  All mutexes acquired by sysfs_addrm_start() are released.
  11. */
  12. void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
  13. {
  14. /* release resources acquired by sysfs_addrm_start() */
  15. mutex_unlock(&sysfs_mutex);
  16. if (acxt->parent_inode) {
  17. struct inode *inode = acxt->parent_inode;
  18. /* if added/removed, update timestamps on the parent */
  19. if (acxt->cnt)
  20. inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*/
  21. mutex_unlock(&inode->i_mutex);
  22. iput(inode);
  23. }
  24. /* kill removed sysfs_dirents */
  25. while (acxt->removed) {
  26. struct sysfs_dirent *sd = acxt->removed;
  27. acxt->removed = sd->s_sibling;
  28. sd->s_sibling = NULL;
  29. sysfs_drop_dentry(sd);
  30. sysfs_deactivate(sd);
  31. unmap_bin_file(sd);
  32. sysfs_put(sd);
  33. }
  34. }

该函数结束了添加sysfs_dirent的工作,这个就不多做说明了。

至此,添加一个目录的工作已经完成了,添加目录的工作其实就是创建了一个新的sysfs_dirent,并把它添加到父sysfs_dirent中。

下面我们看下如何添加属性文件。

8.4 创建属性文件

添加属性文件使用sysfs_create_file函数。

下列函数位于fs/sysfs/file.c。

  1. /**
  2. *  sysfs_create_file - create an attribute file for an object.
  3. *  @kobj:  object we're creating for.
  4. *  @attr:  attribute descriptor.
  5. */
  6. int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
  7. {
  8. BUG_ON(!kobj || !kobj->sd || !attr);
  9. return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
  10. }
  11. int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
  12. int type)
  13. {
  14. return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
  15. }
  16. int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
  17. const struct attribute *attr, int type, mode_t amode)
  18. {
  19. umode_t mode = (amode & S_IALLUGO) | S_IFREG;
  20. struct sysfs_addrm_cxt acxt;
  21. struct sysfs_dirent *sd;
  22. int rc;
  23. /*分配sysfs_dirent并初始化*/
  24. sd = sysfs_new_dirent(attr->name, mode, type);
  25. if (!sd)
  26. return -ENOMEM;
  27. sd->s_attr.attr = (void *)attr;
  28. sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/
  29. rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
  30. sysfs_addrm_finish(&acxt);            /*收尾工作*/
  31. if (rc)            /*0表示创建成功*/
  32. sysfs_put(sd);
  33. return rc;
  34. }

sysfs_create_file用参数SYSFS_KOBJ_ATTR(表示建立属性文件)来调用了sysfs_add_file,后者又直接调用了sysfs_add_file_mode。

sysfs_add_file_mode函数的执行和8.3节的create_dir函数非常类似,只不过它并没有保存kobject对象,也就是说该sysfs_dirent并没有一个对应的kobject对象。

需要注意的是,这里是建立属性文件,因此使用了联合体中的结构体s_attr。

8.5 创建symlink

最后,来看下symlink的建立。

  1. /**
  2. *  sysfs_create_link - create symlink between two objects.
  3. *  @kobj:  object whose directory we're creating the link in.
  4. *  @target:    object we're pointing to.
  5. *  @name:      name of the symlink.
  6. */
  7. int sysfs_create_link(struct kobject *kobj, struct kobject *target,
  8. const char *name)
  9. {
  10. return sysfs_do_create_link(kobj, target, name, 1);
  11. }
  12. static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
  13. const char *name, int warn)
  14. {
  15. struct sysfs_dirent *parent_sd = NULL;
  16. struct sysfs_dirent *target_sd = NULL;
  17. struct sysfs_dirent *sd = NULL;
  18. struct sysfs_addrm_cxt acxt;
  19. int error;
  20. BUG_ON(!name);
  21. if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/
  22. parent_sd = &sysfs_root;
  23. else        /*有父sysfs_dirent*/
  24. parent_sd = kobj->sd;
  25. error = -EFAULT;
  26. if (!parent_sd)
  27. goto out_put;
  28. /* target->sd can go away beneath us but is protected with
  29. * sysfs_assoc_lock.  Fetch target_sd from it.
  30. */
  31. spin_lock(&sysfs_assoc_lock);
  32. if (target->sd)
  33. target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*/
  34. spin_unlock(&sysfs_assoc_lock);
  35. error = -ENOENT;
  36. if (!target_sd)
  37. goto out_put;
  38. error = -ENOMEM;
  39. /*分配sysfs_dirent并初始化*/
  40. sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
  41. if (!sd)
  42. goto out_put;
  43. sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/
  44. target_sd = NULL;    /* reference is now owned by the symlink */
  45. sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
  46. if (warn)
  47. error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
  48. else
  49. error = __sysfs_add_one(&acxt, sd);
  50. sysfs_addrm_finish(&acxt);            /*收尾工作*/
  51. if (error)
  52. goto out_put;
  53. return 0;
  54. out_put:
  55. sysfs_put(target_sd);
  56. sysfs_put(sd);
  57. return error;
  58. }

这个函数的执行也和8.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。

因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。

8.6 小结

本节首先对syfs这一特殊的文件系统的注册过程进行了分析。接着对目录,属性文件和symlink的建立进行了分析。这三者的建立过程基本一致,但是目录

有kobject对象,而剩余两个没有。其次,这三者的每个sysfs_dirent中,都使用了自己的联合体数据。

9 总结

本文首先对sysfs的核心数据kobject,kset等数据结构做出了分析,正是通过它们才能向用户空间呈现出设备驱动模型。

接着,以/sys/bus目录的建立为例,来说明如何通过kobject和kset来建立该bus目录。

随后,介绍了驱动模型中表示总线,设备和驱动的三个数据结构。

然后,介绍了platform总线(bus/platform)的注册,再介绍了虚拟的platform设备(devices/platform)的添加过程。

之后 ,以spi主控制器的platform设备为例,介绍了该platform设备和相应的驱动的注册过程。

最后,介绍了底层sysfs文件系统的注册过程和如何建立目录,属性文件和symlink的过程。

最新文章

  1. Python 判断变量的类型
  2. 消息提示插件toastr.js与Messenger组件
  3. opencv学习笔记(二)寻找轮廓
  4. android实现系统电话通话过程中自动感应黑屏
  5. poj 1934(LCS)
  6. 浪潮服务器通过ipmitool获取mac地址
  7. Matlab中用内建函数代替for循环
  8. hdu 5057 Argestes and Sequence
  9. 如何将网站升级为HTTPS协议?
  10. 关于hibernate查询结果类的封装
  11. ICPC Asia Regional 2015 Japan.Routing a Marathon Race(DFS)
  12. mysql查看连接数排查问题
  13. React/VUE 脚手架2.0和3.0
  14. 搭建好lamp,部署owncloud。
  15. UWP Button添加圆角阴影(二)
  16. 解决xib布局方式支持ios6,ios7
  17. C - 无间道之并查集 HihoCoder - 1066
  18. TFS 切换登录用户的方法[转]
  19. Redis-1-Redis的安装
  20. Zabbix数据库表结构

热门文章

  1. 轻量级验证码生成插件webutil-licenseImage
  2. C#利用Emit反射实现AOP,以及平台化框架封装思路
  3. WPF MVVM使用prism4.1搭建
  4. Arduino 3G shield using SoftwareSerial to control
  5. 改善C#公共程序类库质量的10种方法和工具
  6. SVN插件
  7. 怎样清除SWAP里的文件
  8. Python的下载和安装
  9. 分享下mac安装xamarin跨平台开发环境的坑
  10. SVG基础以及使用Javascript DOM操作SVG