本文将对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的过程。

更新说明:
2012.09.14 在6.2.9中,添加分析 bus_for_each_drv。

转:http://blog.csdn.net/yj4231/article/details/7799245

Linux设备模型——设备驱动模型和sysfs文件系统解读的更多相关文章

  1. linux设备模型_转

    建议原博文查看,效果更佳. 转自:http://www.cnblogs.com/wwang/category/269350.html Linux设备模型 (1) 随着计算机的周边外设越来越丰富,设备管 ...

  2. Linux设备模型 (1)

    随着计算机的周边外设越来越丰富,设备管理已经成为现代操作系统的一项重要任务,这对于Linux来说也是同样的情况.每次Linux内核新版本的发布,都会伴随着一批设备驱动进入内核.在Linux内核里,驱动 ...

  3. linux驱动模型——platform(1)

    一.驱动模型包含什么? 1.1. 类class 1.1.2. 它能够自动创建/dev下的设备节点,不需要mknod /dev/xxx c x x创建.当然class还有其另外的作用,且自动创建设备节点 ...

  4. Sysfs文件系统与Linux设备模型

    转:http://www.360doc.com/content/11/1218/16/1299815_173168170.shtml sysfs把连接在系统上的设备和总线组织成为一个分级的目录及文件, ...

  5. Linux设备模型 (4)

    <Linux设备模型 (2)>和<Linux设备模型 (3)>主要通过一些简单的实作介绍了kobject.kset.kobj_type.attribute等数据结构的用法,但这 ...

  6. Linux设备模型(3)_Uevent

    转自:http://www.wowotech.net/linux_kenrel/uevent.html 1. Uevent的功能 Uevent是Kobject的一部分,用于在Kobject状态发生改变 ...

  7. Linux设备模型(总线、设备、驱动程序和类)

    Linux设备驱动程序学习(13) -Linux设备模型(总线.设备.驱动程序和类)[转] 文章的例子和实验使用<LDD3>所配的lddbus模块(稍作修改). 提示:在学习这部分内容是一 ...

  8. Linux设备模型 学习总结

    看LDD3中设备模型一章,觉得思维有些混乱.这里从整体的角度来理理思路.本文从四个方面来总结一些内容: 1.底层数据结构:kobject,kset.2.linux设备模型层次关系:bus_type,d ...

  9. Linux 设备模型浅析之 uevent 篇(2)

    Linux 设备模型浅析之 uevent 篇 本文属本人原创,欢迎转载,转载请注明出处.由于个人的见识和能力有限,不可能面 面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是 yzq.seen@gma ...

随机推荐

  1. 【POJ】【2601】Simple calculations

    推公式/二分法 好题! 题解:http://blog.csdn.net/zck921031/article/details/7690288 这题明显是一个方程组……可以推公式推出来…… 然而这太繁琐了 ...

  2. 【BZOJ】【1202】【HNOI2005】狡猾的商人

    Orz iwtwiioi  http://www.cnblogs.com/iwtwiioi/p/3887617.html 并查集+前缀和 啊……这题应该是水题吧?但是我这个大沙茶居然一天都没想出来…… ...

  3. 浅谈KL散度

    一.第一种理解 相对熵(relative entropy)又称为KL散度(Kullback–Leibler divergence,简称KLD),信息散度(information divergence) ...

  4. DEVICE DRAW VERTEX BUFFER TOO SMALL

    D3D11 WARNING #356 这个傻warning的意思看起来是说vertex buffer 太小了 描述是这样的: Vertex Buffer at the input vertex slo ...

  5. topcoder 642

    A:直接拆开字符串写就好了. 今天的题目比较容易一些: B:题目大意: 求最少的翻转次数,每次翻转i是对应 y%i==0都会翻转. 球所有翻转为off状态的最小次数: 从最小idx开始,依次做就好了, ...

  6. DB2 的create or update方法

    通过merge方法实现的: MERGE INTO IFEBASE.STYLE AS MT USING (SELECT :scenario AS SCENARIO_ID, :style AS SHAPE ...

  7. Scrum敏捷软件开发之技术实践——测试驱动开发TDD

    重复无聊的定义 测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法.它要求在编写某个功能的代码之前先编写测试代码,然后只编写 ...

  8. maven mirror repository

    简单点来说,repository就是个仓库.maven里有两种仓库,本地仓库和远程仓库.远程仓库相当于公共的仓库,大家都能看到.本地仓库是你本地的一个山寨版,只有你看的到,主要起缓存作用.当你向仓库请 ...

  9. SELINUX设为Disable 影响java SSH工具包Jsch 0.1.49.jar的一个案例

    最近项目中遇到一个典型事件,当RHEL 的SELINUX设为DISABLE时 使用JAVA的Jsch 库调用SSH命令时将随机返回空字符串,我使用的版本是0.1.49,最新版本0.1.51未测试. 关 ...

  10. Set Matrix Zeroes

    Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. click ...