sysfs文件系统根目录项的建立
时间:2010-08-06 来源:tq08g2z
sysfs文件系统根目录项的建立
话说sysfs_fs_type 的get_sb 方法get_sb_single()中调用了传递进来的fill_super方法来进一步的初始化刚刚建立的super_block对象。这个方法实际上是sysfs_fill_super()函数。还是这个函数最有意思,最最实在,其定义为:
---------------------------------------------------------------------
fs/sysfs/mount.c
26 static struct vfsmount *sysfs_mount;
27 struct kmem_cache *sysfs_dir_cachep;
28
29 static const struct super_operations sysfs_ops = {
30 .statfs = simple_statfs,
31 .drop_inode = generic_delete_inode,
32 .delete_inode = sysfs_delete_inode,
33 };
34
35 struct sysfs_dirent sysfs_root = {
36 .s_name = "",
37 .s_count = ATOMIC_INIT(1),
38 .s_flags = SYSFS_DIR,
39 .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
40 .s_ino = 1,
41 };
43 static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
44 {
45 struct inode *inode;
46 struct dentry *root;
47
48 sb->s_blocksize = PAGE_CACHE_SIZE;
49 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
50 sb->s_magic = SYSFS_MAGIC;
51 sb->s_op = &sysfs_ops;
52 sb->s_time_gran = 1;
53
54 /* get root inode, initialize and unlock it */
55 mutex_lock(&sysfs_mutex);
56 inode = sysfs_get_inode(sb, &sysfs_root);
57 mutex_unlock(&sysfs_mutex);
58 if (!inode) {
59 pr_debug("sysfs: could not get root inode\n");
60 return -ENOMEM;
61 }
62
63 /* instantiate and link root dentry */
64 root = d_alloc_root(inode);
65 if (!root) {
66 pr_debug("%s: could not get root dentry!\n",__func__);
67 iput(inode);
68 return -ENOMEM;
69 }
70 root->d_fsdata = &sysfs_root;
71 sb->s_root = root;
72 return 0;
73 }
---------------------------------------------------------------------
这个函数执行如下操作:
1、设置超级块的sb->s_blocksize为PAGE_CACHE_SIZE,sb->s_blocksize_bits字段为PAGE_CACHE_SHIFT,sb->s_magic字段为SYSFS_MAGIC,sb->s_op字段指向sysfs_ops,sb->s_time_gran字段为1。
2、获得sysfs互斥体。
3、调用sysfs_get_inode(sb, &sysfs_root),根据sysfs_root的内容来建立sysfs文件系统根目录的inode对象。在这里,来解释一下sysfs_dirent结构体。它是sysfs文件系统层次结构的构建块,sysfs中的每个节点都由一个单独的sysfs_dirent结构来呈现,是sysfs自己的目录项。其定义为:
---------------------------------------------------------------------
fs/sysfs/sysfs.h
51 struct sysfs_dirent {
52 atomic_t s_count; /* 引用计数器 */
53 atomic_t s_active;
54 #ifdef CONFIG_DEBUG_LOCK_ALLOC
55 struct lockdep_map dep_map;
56 #endif
57 struct sysfs_dirent *s_parent;
58 struct sysfs_dirent *s_sibling;
59 const char *s_name; /* 名字 */
60
61 union {
62 struct sysfs_elem_dir s_dir;
63 struct sysfs_elem_symlink s_symlink;
64 struct sysfs_elem_attr s_attr;
65 struct sysfs_elem_bin_attr s_bin_attr;
66 };
67
68 unsigned int s_flags; /* 节点标志(属性) */
69 unsigned short s_mode; /* 节点模式 */
70 ino_t s_ino; /* inode节点号 */
71 struct sysfs_inode_attrs *s_iattr;
72 };
---------------------------------------------------------------------
接下来来看sysfs_get_inode()的定义:
---------------------------------------------------------------------
fs/sysfs/inode.c
285 /**
286 * sysfs_get_inode - get inode for sysfs_dirent
287 * @sb: super block
288 * @sd: sysfs_dirent to allocate inode for
289 *
290 * Get inode for @sd. If such inode doesn't exist, a new inode
291 * is allocated and basics are initialized. New inode is
292 * returned locked.
293 *
294 * LOCKING:
295 * Kernel thread context (may sleep).
296 *
297 * RETURNS:
298 * Pointer to allocated inode on success, NULL on failure.
299 */
300 struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd)
301 {
302 struct inode *inode;
303
304 inode = iget_locked(sb, sd->s_ino);
305 if (inode && (inode->i_state & I_NEW))
306 sysfs_init_inode(sd, inode);
307
308 return inode;
309 }
---------------------------------------------------------------------
这个函数执行如下操作:
a. 调用iget_locked(sb, sd->s_ino)来获得inode对象。它本质上先在inode哈希表中查找特定文件系统中对应inode号的inode对象。若找不到,则在inode的slab缓冲池中分配新的inode对象,初始化它并返回其地址。由sysfs_root 的定义,我们知道sysfs根目录的inode号为1。
b.调用sysfs_init_inode(sd, inode)函数来初始化刚刚为根目录创建的inode。这个函数我们也得仔细瞧瞧:
---------------------------------------------------------------------
fs/sysfs/inode.c
28 static const struct address_space_operations sysfs_aops = {
29 .readpage = simple_readpage,
30 .write_begin = simple_write_begin,
31 .write_end = simple_write_end,
32 };
33
34 static struct backing_dev_info sysfs_backing_dev_info = {
35 .name = "sysfs",
36 .ra_pages = 0, /* No readahead */
37 .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
38 };
39
40 static const struct inode_operations sysfs_inode_operations ={
41 .permission = sysfs_permission,
42 .setattr = sysfs_setattr,
43 .getattr = sysfs_getattr,
44 .setxattr = sysfs_setxattr,
45 };
216 static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
217 {
218 struct sysfs_inode_attrs *iattrs = sd->s_iattr;
219
220 inode->i_mode = sd->s_mode;
221 if (iattrs) {
222 /* sysfs_dirent has non-default attributes
223 * get them from persistent copy in sysfs_dirent
224 */
225 set_inode_attr(inode, &iattrs->ia_iattr);
226 security_inode_notifysecctx(inode,
227 iattrs->ia_secdata,
228 iattrs->ia_secdata_len);
229 }
230
231 if (sysfs_type(sd) == SYSFS_DIR)
232 inode->i_nlink = sysfs_count_nlink(sd);
233 }
248 static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
249 {
250 struct bin_attribute *bin_attr;
251
252 inode->i_private = sysfs_get(sd);
253 inode->i_mapping->a_ops = &sysfs_aops;
254 inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
255 inode->i_op = &sysfs_inode_operations;
256
257 set_default_inode_attr(inode, sd->s_mode);
258 sysfs_refresh_inode(sd, inode);
259
260 /* initialize inode according to type */
261 switch (sysfs_type(sd)) {
262 case SYSFS_DIR:
263 inode->i_op = &sysfs_dir_inode_operations;
264 inode->i_fop = &sysfs_dir_operations;
265 break;
266 case SYSFS_KOBJ_ATTR:
267 inode->i_size = PAGE_SIZE;
268 inode->i_fop = &sysfs_file_operations;
269 break;
270 case SYSFS_KOBJ_BIN_ATTR:
271 bin_attr = sd->s_bin_attr.bin_attr;
272 inode->i_size = bin_attr->size;
273 inode->i_fop = &bin_fops;
274 break;
275 case SYSFS_KOBJ_LINK:
276 inode->i_op = &sysfs_symlink_inode_operations;
277 break;
278 default:
279 BUG();
280 }
281
282 unlock_new_inode(inode);
283 }
---------------------------------------------------------------------
这个函数执行如下操作:
(1)、增加sysfs根目录的sysfs_dirent对象sysfs_root的引用计数,并使根目录inode的inode->i_private字段指向这个sysfs_dirent对象。
(2)、设置根目录inode的inode->i_mapping->a_ops字段为&sysfs_aops,inode->i_mapping->backing_dev_info字段为&sysfs_backing_dev_info,inode->i_op字段为&sysfs_inode_operations(sysfs默认的inode操作集)。
(3)、调用set_default_inode_attr(inode, sd->s_mode)将sysfs_root的inode模式字段值赋给新建的inode的i_mode字段,设置inode的inode->i_atime、inode->i_mtime及inode->i_ctime字段为当前时间CURRENT_TIME。
(4)、调用sysfs_refresh_inode(sd, inode)函数来刷新inode,这个函数本质上再一次将sysfs_root的inode模式字段值赋给新建的inode的i_mode字段,然后设置inode的引用计数字段i_nlink(目录的子目录个数加2)。
(5)、设置inode的i_op为&sysfs_dir_inode_operations,覆盖掉先前的设置,设置i_fop字段为&sysfs_dir_operations。
c. sysfs_get_inode()返回经过了初始化的inode。
4、sysfs_fill_super()释放sysfs互斥体sysfs_mutex。
5、调用d_alloc_root(inode)根据inode来为sysfs创建根目录项。这个函数定义如下:
---------------------------------------------------------------------
fs/dcache.c
1096 /**
1097 * d_alloc_root - allocate root dentry
1098 * @root_inode: inode to allocate the root for
1099 *
1100 * Allocate a root ("/") dentry for the inode given. The inode is
1101 * instantiated and returned. %NULL is returned if there is
1102 * insufficient memory or the inode passed is %NULL.
1103 */
1104
1105 struct dentry * d_alloc_root(struct inode * root_inode)
1106 {
1107 struct dentry *res = NULL;
1108
1109 if (root_inode) {
1110 static const struct qstr name = { .name = "/", .len = 1 };
1111
1112 res = d_alloc(NULL, &name);
1113 if (res) {
1114 res->d_sb = root_inode->i_sb;
1115 res->d_parent = res;
1116 d_instantiate(res, root_inode);
1117 }
1118 }
1119 return res;
1120 }
1121 EXPORT_SYMBOL(d_alloc_root);
---------------------------------------------------------------------
这个函数执行如下操作:
a.调用d_alloc(NULL, &name)来从目录项缓存中分配dentry对象。这个函数定义为:
---------------------------------------------------------------------
fs/dcache.c
915 /**
916 * d_alloc - allocate a dcache entry
917 * @parent: parent of entry to allocate
918 * @name: qstr of the name
919 *
920 * Allocates a dentry. It returns %NULL if there is insufficient memory
921 * available. On a success the dentry is returned. The name passed in is
922 * copied and the copy passed in may be reused after this call.
923 */
924
925 struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
926 {
927 struct dentry *dentry;
928 char *dname;
929
930 dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
931 if (!dentry)
932 return NULL;
933
934 if (name->len > DNAME_INLINE_LEN-1) {
935 dname = kmalloc(name->len + 1, GFP_KERNEL);
936 if (!dname) {
937 kmem_cache_free(dentry_cache, dentry);
938 return NULL;
939 }
940 } else {
941 dname = dentry->d_iname;
942 }
943 dentry->d_name.name = dname;
944
945 dentry->d_name.len = name->len;
946 dentry->d_name.hash = name->hash;
947 memcpy(dname, name->name, name->len);
948 dname[name->len] = 0;
949
950 atomic_set(&dentry->d_count, 1);
951 dentry->d_flags = DCACHE_UNHASHED;
952 spin_lock_init(&dentry->d_lock);
953 dentry->d_inode = NULL;
954 dentry->d_parent = NULL;
955 dentry->d_sb = NULL;
956 dentry->d_op = NULL;
957 dentry->d_fsdata = NULL;
958 dentry->d_mounted = 0;
959 INIT_HLIST_NODE(&dentry->d_hash);
960 INIT_LIST_HEAD(&dentry->d_lru);
961 INIT_LIST_HEAD(&dentry->d_subdirs);
962 INIT_LIST_HEAD(&dentry->d_alias);
963
964 if (parent) {
965 dentry->d_parent = dget(parent);
966 dentry->d_sb = parent->d_sb;
967 } else {
968 INIT_LIST_HEAD(&dentry->d_u.d_child);
969 }
970
971 spin_lock(&dcache_lock);
972 if (parent)
973 list_add(&dentry->d_u.d_child, &parent->d_subdirs);
974 dentry_stat.nr_dentry++;
975 spin_unlock(&dcache_lock);
976
977 return dentry;
978 }
979 EXPORT_SYMBOL(d_alloc);
---------------------------------------------------------------------
这个函数的操作基本上都比较明确。
b.设置目录项的d_sb为,root_inode->i_sb,设置目录项的父目录项指向其本身。前面为根目录建立inode的时候,调用iget_locked()函数,传递的参数是超级块对象地址和索引节点号。
c.调用d_instantiate(res, root_inode)为一个目录项填充信息。其定义为:
---------------------------------------------------------------------
fs/dcache.c
992 /* the caller must hold dcache_lock */
993 static void __d_instantiate(struct dentry *dentry, struct inode *inode)
994 {
995 if (inode)
996 list_add(&dentry->d_alias, &inode->i_dentry);
997 dentry->d_inode = inode;
998 fsnotify_d_instantiate(dentry, inode);
999 }
1000
1001 /**
1002 * d_instantiate - fill in inode information for a dentry
1003 * @entry: dentry to complete
1004 * @inode: inode to attach to this dentry
1005 *
1006 * Fill in inode information in the entry.
1007 *
1008 * This turns negative dentries into productive full members
1009 * of society.
1010 *
1011 * NOTE! This assumes that the inode count has been incremented
1012 * (or otherwise set) by the caller to indicate that it is now
1013 * in use by the dcache.
1014 */
1015
1016 void d_instantiate(struct dentry *entry, struct inode * inode)
1017 {
1018 BUG_ON(!list_empty(&entry->d_alias));
1019 spin_lock(&dcache_lock);
1020 __d_instantiate(entry, inode);
1021 spin_unlock(&dcache_lock);
1022 security_d_instantiate(entry, inode);
1023 }
---------------------------------------------------------------------
这个函数完成的工作主要是将目录项添加进inode的目录项链表i_dentry,并使目录项的d_inode指向inode。
6、设置根目录目录项的文件系统私有字段d_fsdata和inode的i_private一样指向sysfs_root。设置sysfs超级块的根目录字段s_root指向刚刚创建的目录项root。
总之sysfs_fill_super()为文件系统创建适当的根目录inode及根目录目录项。