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的过程。
感谢博友分享: