首页 > 技术文章 > Linux设备驱动(7)sysfs详解

xinghuo123 2020-05-18 21:18 原文

1 sysfs底层函数
下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。
在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。

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

定义:fs\sysfs\mount.c

 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 
11     err = sysfs_inode_init();
12     if (err)
13         goto out_err;
14 
15     err = register_filesystem(&sysfs_fs_type);//注册文件系统
16     if (!err) {//注册成功,加载文件系统
17         sysfs_mnt = kern_mount(&sysfs_fs_type);
18         if (IS_ERR(sysfs_mnt)) {
19             printk(KERN_ERR "sysfs: could not mount!\n");
20             err = PTR_ERR(sysfs_mnt);
21             sysfs_mnt = 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 
35 static struct file_system_type sysfs_fs_type = {
36     .name        = "sysfs",
37     .mount        = sysfs_mount,
38     .kill_sb    = sysfs_kill_sb,
39     .fs_flags    = FS_USERNS_MOUNT,
40 };

1.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  
14 int register_filesystem(struct file_system_type * fs)
15 {
16     int res = 0;
17     struct file_system_type ** p;
18 
19     BUG_ON(strchr(fs->name, '.'));
20     if (fs->next)
21         return -EBUSY;
22     write_lock(&file_systems_lock);
23     p = find_filesystem(fs->name, strlen(fs->name));//查找要注册的文件是同是否存在,返回位置
24     if (*p)
25         res = -EBUSY;//该文件系统已存在,返回error
26     else
27         *p = fs;//将新的文件系统加入到链表中
28     write_unlock(&file_systems_lock);
29     return res;
30 }
31 
32 static struct file_system_type **find_filesystem(const char *name, unsigned len)
33 {
34     struct file_system_type **p;
35     for (p=&file_systems; *p; p=&(*p)->next)
36         if (strlen((*p)->name) == len &&
37             strncmp((*p)->name, name, len) == 0)
38             break;
39     return p;
40 }

该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。
如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。

1.2 kern_mount函数
下列代码位于include/linux/fs.h

 1 定义位于:include\linux\fs.h
 2 #define kern_mount(type) kern_mount_data(type, NULL)
 3 定义位于fs\namespace.c
 4 struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
 5 {
 6     struct vfsmount *mnt;
 7     mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
 8     if (!IS_ERR(mnt)) {
 9         /*
10          * it is a longterm mount, don't release mnt until
11          * we unmount before file sys is unregistered
12         */
13         real_mount(mnt)->mnt_ns = MNT_NS_INTERNAL;
14     }
15     return mnt;
16 }

kern_mount实际上最后是调用了vfs_kern_mount函数。位于fs\namespace.c,我们来看下:

 1 struct vfsmount *
 2 vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
 3 {
 4     struct mount *mnt;
 5     struct dentry *root;
 6 
 7     if (!type)
 8         return ERR_PTR(-ENODEV);
 9 
10     mnt = alloc_vfsmnt(name);//配struct vfsmount
11     if (!mnt)
12         return ERR_PTR(-ENOMEM);
13 
14     if (flags & MS_KERNMOUNT)
15         mnt->mnt.mnt_flags = MNT_INTERNAL;
16 
17     root = mount_fs(type, flags, name, data);
18     if (IS_ERR(root)) {
19         free_vfsmnt(mnt);
20         return ERR_CAST(root);
21     }
22 
23     mnt->mnt.mnt_root = root;//设置挂载点的dentry
24     mnt->mnt.mnt_sb = root->d_sb;//设置所挂载的fs为自己本身
25     mnt->mnt_mountpoint = mnt->mnt.mnt_root;
26     mnt->mnt_parent = mnt;
27     br_write_lock(&vfsmount_lock);
28     list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
29     br_write_unlock(&vfsmount_lock);
30     return &mnt->mnt;
31 }

1.2.1 函数alloc_vfsmnt

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

 1 static struct mount *alloc_vfsmnt(const char *name)
 2 {
 3     struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
 4     if (mnt) {
 5         int err;
 6 
 7         err = mnt_alloc_id(mnt);//设置mnt->mnt_id
 8         if (err)
 9             goto out_free_cache;
10 
11         if (name) {
12             mnt->mnt_devname = kstrdup(name, GFP_KERNEL);//拷贝name,并赋值
13             if (!mnt->mnt_devname)
14                 goto out_free_id;
15         }
16 
17 #ifdef CONFIG_SMP
18         mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);
19         if (!mnt->mnt_pcp)
20             goto out_free_devname;
21 
22         this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
23 #else
24         mnt->mnt_count = 1;
25         mnt->mnt_writers = 0;
26 #endif
27 
28         INIT_LIST_HEAD(&mnt->mnt_hash);
29         INIT_LIST_HEAD(&mnt->mnt_child);
30         INIT_LIST_HEAD(&mnt->mnt_mounts);
31         INIT_LIST_HEAD(&mnt->mnt_list);
32         INIT_LIST_HEAD(&mnt->mnt_expire);
33         INIT_LIST_HEAD(&mnt->mnt_share);
34         INIT_LIST_HEAD(&mnt->mnt_slave_list);
35         INIT_LIST_HEAD(&mnt->mnt_slave);
36 #ifdef CONFIG_FSNOTIFY
37         INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
38 #endif
39     }
40     return mnt;
41 
42 #ifdef CONFIG_SMP
43 out_free_devname:
44     kfree(mnt->mnt_devname);
45 #endif
46 out_free_id:
47     mnt_free_id(mnt);
48 out_free_cache:
49     kmem_cache_free(mnt_cache, mnt);
50     return NULL;
51 }

1.2.2 函数mount_fs

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

 1 struct dentry *
 2 mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
 3 {
 4     struct dentry *root;
 5     struct super_block *sb;
 6     char *secdata = NULL;
 7     int error = -ENOMEM;
 8 
 9     if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
10         secdata = alloc_secdata();
11         if (!secdata)
12             goto out;
13 
14         error = security_sb_copy_data(data, secdata);
15         if (error)
16             goto out_free_secdata;
17     }
18 
19     root = type->mount(type, flags, name, data);//调用type的mount函数,mount函数在上面已经初始化
20     if (IS_ERR(root)) {
21         error = PTR_ERR(root);
22         goto out_free_secdata;
23     }
24     sb = root->d_sb;
25     BUG_ON(!sb);
26     WARN_ON(!sb->s_bdi);
27     WARN_ON(sb->s_bdi == &default_backing_dev_info);
28     sb->s_flags |= MS_BORN;
29 
30     error = security_sb_kern_mount(sb, flags, secdata);
31     if (error)
32         goto out_sb;
33 
34     /*
35      * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
36      * but s_maxbytes was an unsigned long long for many releases. Throw
37      * this warning for a little while to try and catch filesystems that
38      * violate this rule.
39      */
40     WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
41         "negative value (%lld)\n", type->name, sb->s_maxbytes);
42 
43     up_write(&sb->s_umount);
44     free_secdata(secdata);
45     return root;
46 out_sb:
47     dput(root);
48     deactivate_locked_super(sb);
49 out_free_secdata:
50     free_secdata(secdata);
51 out:
52     return ERR_PTR(error);
53 }

type的mount函数,定义:fs\sysfs\mount.c

 1 static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 2     int flags, const char *dev_name, void *data)
 3 {
 4     struct sysfs_super_info *info;
 5     enum kobj_ns_type type;
 6     struct super_block *sb;
 7     int error;
 8 
 9     if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs)
10         return ERR_PTR(-EPERM);
11 
12     info = kzalloc(sizeof(*info), GFP_KERNEL);
13     if (!info)
14         return ERR_PTR(-ENOMEM);
15 
16     for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
17         info->ns[type] = kobj_ns_grab_current(type);
18 
19     sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);//调用sget函数
20     if (IS_ERR(sb) || sb->s_fs_info != info)
21         free_sysfs_super_info(info);
22     if (IS_ERR(sb))
23         return ERR_CAST(sb);
24     if (!sb->s_root) {
25         error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
26         if (error) {
27             deactivate_locked_super(sb);
28             return ERR_PTR(error);
29         }
30         sb->s_flags |= MS_ACTIVE;
31     }
32 
33     return dget(sb->s_root);
34 }

1.3 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  
17 retry:
18     spin_lock(&sb_lock);
19     if (test) {            
20         /*遍历所有属于该文件系统的super_block*/
21         list_for_each_entry(old, &type->fs_supers, s_instances) {
22             if (!test(old, data))
23                 continue;
24             if (!grab_super(old))
25                 goto retry;
26             if (s) {
27                 up_write(&s->s_umount);
28                 destroy_super(s);
29             }
30             return old;
31         }
32     }
33     if (!s) {
34         spin_unlock(&sb_lock);
35         s = alloc_super(type);    /*创建新的super_block并初始化*/
36         if (!s)
37             return ERR_PTR(-ENOMEM);
38         goto retry;
39     }
40         
41     err = set(s, data);        /*设置s->s_dev */
42     if (err) {
43         spin_unlock(&sb_lock);
44         up_write(&s->s_umount);
45         destroy_super(s);
46         return ERR_PTR(err);
47     }
48     s->s_type = type;
49     strlcpy(s->s_id, type->name, sizeof(s->s_id));    /*拷贝name*/
50     list_add_tail(&s->s_list, &super_blocks);        /*将新的super_block添加到链表头super_blocks中*/
51     list_add(&s->s_instances, &type->fs_supers);    /*将新的super_block添加到相应的文件系统类型的链表中*/
52     spin_unlock(&sb_lock);
53     get_filesystem(type);
54     return s;
55 }

该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。
然后调用alloc_super函数来创建新的struct super_block。下列函数位于fs/super.c。

 1 static struct super_block *alloc_super(struct file_system_type *type, int flags)
 2 {
 3     struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);
 4     static const struct super_operations default_op;
 5 
 6     if (s) {
 7         if (security_sb_alloc(s)) {
 8             /*
 9              * We cannot call security_sb_free() without
10              * security_sb_alloc() succeeding. So bail out manually
11              */
12             kfree(s);
13             s = NULL;
14             goto out;
15         }
16 #ifdef CONFIG_SMP
17         s->s_files = alloc_percpu(struct list_head);
18         if (!s->s_files)
19             goto err_out;
20         else {
21             int i;
22 
23             for_each_possible_cpu(i)
24                 INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i));
25         }
26 #else
27         INIT_LIST_HEAD(&s->s_files);
28 #endif
29         if (init_sb_writers(s, type))
30             goto err_out;
31         s->s_flags = flags;
32         s->s_bdi = &default_backing_dev_info;
33         INIT_HLIST_NODE(&s->s_instances);
34         INIT_HLIST_BL_HEAD(&s->s_anon);
35         INIT_LIST_HEAD(&s->s_inodes);
36         INIT_LIST_HEAD(&s->s_dentry_lru);
37         INIT_LIST_HEAD(&s->s_inode_lru);
38         spin_lock_init(&s->s_inode_lru_lock);
39         INIT_LIST_HEAD(&s->s_mounts);
40         init_rwsem(&s->s_umount);
41         lockdep_set_class(&s->s_umount, &type->s_umount_key);
42         /*
43          * sget() can have s_umount recursion.
44          *
45          * When it cannot find a suitable sb, it allocates a new
46          * one (this one), and tries again to find a suitable old
47          * one.
48          *
49          * In case that succeeds, it will acquire the s_umount
50          * lock of the old one. Since these are clearly distrinct
51          * locks, and this object isn't exposed yet, there's no
52          * risk of deadlocks.
53          *
54          * Annotate this by putting this lock in a different
55          * subclass.
56          */
57         down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
58         s->s_count = 1;
59         atomic_set(&s->s_active, 1);
60         mutex_init(&s->s_vfs_rename_mutex);
61         lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
62         mutex_init(&s->s_dquot.dqio_mutex);
63         mutex_init(&s->s_dquot.dqonoff_mutex);
64         init_rwsem(&s->s_dquot.dqptr_sem);
65         s->s_maxbytes = MAX_NON_LFS;
66         s->s_op = &default_op;
67         s->s_time_gran = 1000000000;
68         s->cleancache_poolid = -1;
69 
70         s->s_shrink.seeks = DEFAULT_SEEKS;
71         s->s_shrink.shrink = prune_super;
72         s->s_shrink.batch = 1024;
73     }
74 out:
75     return s;
76 err_out:
77     security_sb_free(s);
78 #ifdef CONFIG_SMP
79     if (s->s_files)
80         free_percpu(s->s_files);
81 #endif
82     destroy_sb_writers(s);
83     kfree(s);
84     s = NULL;
85     goto out;
86 }

分配完以后,调用作为sget函数的实参,也就是sysfs_set_super函数,该函数用来设置s->s_dev。

下列函数位于fs/super.c

1 static int sysfs_set_super(struct super_block *sb, void *data)
2 {
3     int error;
4     error = set_anon_super(sb, data);
5     if (!error)
6         sb->s_fs_info = data;
7     return error;
8 }

然后调用set_anon_super函数

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

1.4 sysfs_fill_super函数

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

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

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

在设置了一些字段后,设置了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  
16     union {
17         struct sysfs_elem_dir        s_dir;
18         struct sysfs_elem_symlink    s_symlink;
19         struct sysfs_elem_attr        s_attr;
20         struct sysfs_elem_bin_attr    s_bin_attr;
21     };
22  
23     unsigned int        s_flags;
24     ino_t            s_ino;
25     umode_t            s_mode;
26     struct iattr        *s_iattr;
27 };

其中比较关键的就是那个联合体,针对不同的形式(目录,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  
 19     inode = iget_locked(sysfs_sb, sd->s_ino);    /*在inode cache查找inode是否存在,不存在侧创建一个*/
 20     if (inode && (inode->i_state & I_NEW))        /*如果是新创建的inode,则包含I_NEW*/
 21         sysfs_init_inode(sd, inode);
 22  
 23     return inode;
 24 }
 25  
 26 /**
 27  * iget_locked - obtain an inode from a mounted file system
 28  * @sb:        super block of file system
 29  * @ino:    inode number to get
 30  *
 31  * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
 32  * the inode cache and if present it is returned with an increased reference
 33  * count. This is for file systems where the inode number is sufficient for
 34  * unique identification of an inode.
 35  *
 36  * If the inode is not in cache, get_new_inode_fast() is called to allocate a
 37  * new inode and this is returned locked, hashed, and with the I_NEW flag set.
 38  * The file system gets to fill it in before unlocking it via
 39  * unlock_new_inode().
 40  */
 41 struct inode *iget_locked(struct super_block *sb, unsigned long ino)
 42 {
 43     struct hlist_head *head = inode_hashtable + hash(sb, ino);
 44     struct inode *inode;
 45  
 46     inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/
 47     if (inode)
 48         return inode;         /*找到了该inode*/
 49     /*
 50      * get_new_inode_fast() will do the right thing, re-trying the search
 51      * in case it had to block at any point.
 52      */
 53     return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/
 54 }
 55 EXPORT_SYMBOL(iget_locked);
 56  
 57 static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 58 {
 59     struct bin_attribute *bin_attr;
 60  
 61     inode->i_private = sysfs_get(sd);
 62     inode->i_mapping->a_ops = &sysfs_aops;
 63     inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
 64     inode->i_op = &sysfs_inode_operations;
 65     inode->i_ino = sd->s_ino;
 66     lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
 67  
 68     if (sd->s_iattr) {
 69         /* sysfs_dirent has non-default attributes
 70          * get them for the new inode from persistent copy
 71          * in sysfs_dirent
 72          */
 73         set_inode_attr(inode, sd->s_iattr);
 74     } else
 75         set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/
 76  
 77  
 78     /* initialize inode according to type */
 79     switch (sysfs_type(sd)) {
 80     case SYSFS_DIR:
 81         inode->i_op = &sysfs_dir_inode_operations;
 82         inode->i_fop = &sysfs_dir_operations;
 83         inode->i_nlink = sysfs_count_nlink(sd);
 84         break;
 85     case SYSFS_KOBJ_ATTR:
 86         inode->i_size = PAGE_SIZE;
 87         inode->i_fop = &sysfs_file_operations;
 88         break;
 89     case SYSFS_KOBJ_BIN_ATTR:
 90         bin_attr = sd->s_bin_attr.bin_attr;
 91         inode->i_size = bin_attr->size;
 92         inode->i_fop = &bin_fops;
 93         break;
 94     case SYSFS_KOBJ_LINK:
 95         inode->i_op = &sysfs_symlink_inode_operations;
 96         break;
 97     default:
 98         BUG();
 99     }
100  
101     unlock_new_inode(inode);
102 }

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

该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。
接着调用d_instantiate来绑定inode和dentry之间的关系。

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

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

1.4  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     
15 #ifdef CONFIG_BLOCK
16     if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
17         return -EACCES;
18 #endif
19     if (flags & MS_RDONLY)
20         acct_auto_close(sb);
21     shrink_dcache_sb(sb);
22     fsync_super(sb);
23  
24     /* If we are remounting RDONLY and current sb is read/write,
25        make sure there are no rw files opened */
26     if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {
27         if (force)
28             mark_files_ro(sb);
29         else if (!fs_may_remount_ro(sb))
30             return -EBUSY;
31         retval = vfs_dq_off(sb, 1);
32         if (retval < 0 && retval != -ENOSYS)
33             return -EBUSY;
34     }
35     remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
36  
37     if (sb->s_op->remount_fs) {
38         lock_super(sb);
39         retval = sb->s_op->remount_fs(sb, &flags, data);
40         unlock_super(sb);
41         if (retval)
42             return retval;
43     }
44     sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
45     if (remount_rw)
46         vfs_dq_quota_on_remount(sb);
47     return 0;
48 }

这个函数用来修改挂在选项,这个函数就不分析了,不是重点。
1.5 simple_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。

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

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


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

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

第二,建立了vfsmount。

第三,创建了超级块super_block。

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

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

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

2 创建目录
在device_add/kobject_add中,最后使用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  
10     BUG_ON(!kobj);
11  
12     if (kobj->parent)    /*如果有parent,获取parent对应的sys目录*/
13         parent_sd = kobj->parent->sd;
14     else                /*没有则是在sys根目录*/
15         parent_sd = &sysfs_root;
16  
17     error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
18     if (!error)
19         kobj->sd = sd;
20     return error;
21 }

函数中,首先获取待建目录的父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  
 9     /* allocate */    /*分配sysfs_dirent并初始化*/
10     sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
11     if (!sd)
12         return -ENOMEM;
13     sd->s_dir.kobj = kobj;     /*保存kobject对象*/
14  
15     /* link in */
16     sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
17     rc = sysfs_add_one(&acxt, sd);    /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/
18     sysfs_addrm_finish(&acxt);        /*收尾工作*/
19  
20     if (rc == 0)        /*rc为0表示创建成功*/
21         *p_sd = sd;
22     else
23         sysfs_put(sd);    /*增加引用计数*/
24  
25     return rc;
26 }

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

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

#define SYSFS_KOBJ_ATTR            0x0002
#define SYSFS_KOBJ_BIN_ATTR        0x0004
#define SYSFS_KOBJ_LINK            0x0008
#define SYSFS_COPY_NAME            (SYSFS_DIR | SYSFS_KOBJ_LINK)

2.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  
 6     if (type & SYSFS_COPY_NAME) {
 7         name = dup_name = kstrdup(name, GFP_KERNEL);
 8         if (!name)
 9             return NULL;
10     }
11     /*分配sysfs_dirent并清0*/
12     sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
13     if (!sd)
14         goto err_out1;
15  
16     if (sysfs_alloc_ino(&sd->s_ino))    /*分配ID号*/
17         goto err_out2;
18  
19     atomic_set(&sd->s_count, 1);
20     atomic_set(&sd->s_active, 0);
21  
22     sd->s_name = name;
23     sd->s_mode = mode;
24     sd->s_flags = type;
25  
26     return sd;
27  
28  err_out2:
29     kmem_cache_free(sysfs_dir_cachep, sd);
30  err_out1:
31     kfree(dup_name);
32     return NULL;
33 }

2.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  
 8 struct sysfs_elem_symlink {
 9     struct sysfs_dirent    *target_sd;
10 };
11  
12 struct sysfs_elem_attr {
13     struct attribute    *attr;
14     struct sysfs_open_dirent *open;
15 };
16  
17 struct sysfs_elem_bin_attr {
18     struct bin_attribute    *bin_attr;
19     struct hlist_head    buffers;
20 };

根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。
在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。

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

2.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  
22     memset(acxt, 0, sizeof(*acxt));
23     acxt->parent_sd = parent_sd;
24  
25     /* Lookup parent inode.  inode initialization is protected by
26      * sysfs_mutex, so inode existence can be determined by
27      * looking up inode while holding sysfs_mutex.
28      */
29     mutex_lock(&sysfs_mutex);
30     /*根据parent_sd来寻找父inode*/
31     inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
32              parent_sd);
33     if (inode) {
34         WARN_ON(inode->i_state & I_NEW);
35  
36         /* parent inode available */
37         acxt->parent_inode = inode;        /*保存找到的父inode*/
38  
39         /* sysfs_mutex is below i_mutex in lock hierarchy.
40          * First, trylock i_mutex.  If fails, unlock
41          * sysfs_mutex and lock them in order.
42          */
43         if (!mutex_trylock(&inode->i_mutex)) {
44             mutex_unlock(&sysfs_mutex);
45             mutex_lock(&inode->i_mutex);
46             mutex_lock(&sysfs_mutex);
47         }
48     }
49 }
50  
51 /*
52  * Context structure to be used while adding/removing nodes.
53  */
54 struct sysfs_addrm_cxt {
55     struct sysfs_dirent    *parent_sd;
56     struct inode        *parent_inode;
57     struct sysfs_dirent    *removed;
58     int            cnt;
59 };

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

该函数直接调用了__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链表中。
2.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  
19         /* if added/removed, update timestamps on the parent */
20         if (acxt->cnt)
21             inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*/
22  
23         mutex_unlock(&inode->i_mutex);
24         iput(inode);
25     }
26  
27     /* kill removed sysfs_dirents */
28     while (acxt->removed) {
29         struct sysfs_dirent *sd = acxt->removed;
30  
31         acxt->removed = sd->s_sibling;
32         sd->s_sibling = NULL;
33  
34         sysfs_drop_dentry(sd);
35         sysfs_deactivate(sd);
36         unmap_bin_file(sd);
37         sysfs_put(sd);
38     }
39 }

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

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

下面我们看下如何添加属性文件。
2.6 创建属性文件
添加属性文件使用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  
 7 int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
 8 {
 9     BUG_ON(!kobj || !kobj->sd || !attr);
10  
11     return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
12  
13 }
14  
15 int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
16            int type)
17 {
18     return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
19 }
20  
21 int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
22             const struct attribute *attr, int type, mode_t amode)
23 {
24     umode_t mode = (amode & S_IALLUGO) | S_IFREG;
25     struct sysfs_addrm_cxt acxt;
26     struct sysfs_dirent *sd;
27     int rc;
28     /*分配sysfs_dirent并初始化*/
29     sd = sysfs_new_dirent(attr->name, mode, type);
30     if (!sd)
31         return -ENOMEM;
32     sd->s_attr.attr = (void *)attr;
33  
34     sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/
35     rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
36     sysfs_addrm_finish(&acxt);            /*收尾工作*/
37  
38     if (rc)            /*0表示创建成功*/ 
39         sysfs_put(sd);
40  
41     return rc;
42 }

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。
2.7 创建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  
13 static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
14                 const char *name, int warn)
15 {
16     struct sysfs_dirent *parent_sd = NULL;
17     struct sysfs_dirent *target_sd = NULL;
18     struct sysfs_dirent *sd = NULL;
19     struct sysfs_addrm_cxt acxt;
20     int error;
21  
22     BUG_ON(!name);
23  
24     if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/
25         parent_sd = &sysfs_root;
26     else        /*有父sysfs_dirent*/
27         parent_sd = kobj->sd;
28  
29     error = -EFAULT;
30     if (!parent_sd)
31         goto out_put;
32  
33     /* target->sd can go away beneath us but is protected with
34      * sysfs_assoc_lock.  Fetch target_sd from it.
35      */
36     spin_lock(&sysfs_assoc_lock);
37     if (target->sd)
38         target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*/
39     spin_unlock(&sysfs_assoc_lock);
40  
41     error = -ENOENT;
42     if (!target_sd)
43         goto out_put;
44  
45     error = -ENOMEM;
46     /*分配sysfs_dirent并初始化*/
47     sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
48     if (!sd)
49         goto out_put;
50  
51     sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/
52     target_sd = NULL;    /* reference is now owned by the symlink */
53  
54     sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
55     if (warn)
56         error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
57     else
58         error = __sysfs_add_one(&acxt, sd);
59     sysfs_addrm_finish(&acxt);            /*收尾工作*/
60  
61     if (error)
62         goto out_put;
63  
64     return 0;
65  
66  out_put:
67     sysfs_put(target_sd);
68     sysfs_put(sd);
69 }

这个函数的执行也和2.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。
因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。

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

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

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

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

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

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

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

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

感谢博友分享:

https://blog.csdn.net/yj4231/article/details/7799245

推荐阅读