Coder
分类: LINUX
2010-08-06 23:22:02
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及根目录目录项。