rootfs文件系统的简单分析
2013-06-03 10:33
316 查看
rootfs文件系统是基于内存的文件系统,也是虚拟的文件系统,在系统启动之后,隐藏在真正的根文件系统后面,不能被卸载。
在开始介绍rootfs之前,先介绍一下,rootfs的数据结构,然后再看一下rootfs中的函数rootfs_get_sb是怎么调用的。
rootfs的数据结构如下
[cpp]
view plaincopyprint?
1static struct file_system_type rootfs_fs_type = {
2 .name = "rootfs",
3 .get_sb = rootfs_get_sb,
4 .kill_sb = kill_litter_super,
5};
第2行文件系统的名字
第3行挂载文件系统时分配超级块
第4行卸载文件系统时回收超级块
[cpp]
view plaincopyprint?
01static void __init init_mount_tree(void)
02{
03 .......
04 mnt = do_kern_mount("rootfs", 0,
"rootfs", NULL);
05 .......
06}
07struct vfsmount *
08do_kern_mount(const
char *fstype, int flags,
const char *name,
void *data)
09{
10 ....
11 mnt = vfs_kern_mount(type, flags, name, data);
12 ....
13}
14struct vfsmount *
15vfs_kern_mount(struct file_system_type *type,
int flags, const
char *name, void *data)
16{
17 .....
18 error = type->get_sb(type, flags, name, data, mnt);
19 ......
20}
上面是内核在启动时挂载rootfs文件系统的简单流程,其中在第18行是,会调用rootfs文件系统中的rootfs_get_sb函数,其函数如下。
[cpp]
view plaincopyprint?
1static int rootfs_get_sb(struct file_system_type *fs_type,
2 int flags, const
char *dev_name, void *data,
struct vfsmount *mnt)
3{
4 return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
5 mnt);
6}
[cpp]
view plaincopyprint?
01int get_sb_nodev(struct file_system_type *fs_type,
02 int flags, void *data,
03 int (*fill_super)(struct super_block *,
void *, int),
04 struct vfsmount *mnt)
05{
06 int error;
07 struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
08 if (IS_ERR(s))
09 return PTR_ERR(s);
10 s->s_flags = flags;
11 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
12 if (error) {
13 deactivate_locked_super(s);
14 return error;
15 }
16 s->s_flags |= MS_ACTIVE;
17 simple_set_mnt(mnt, s);
18 return 0;
19}
第7行调用sget()函数分配新的超级块,传递set_anon_super()函数的地址作为参数。用合适的方式设置超级块的s_dev字段。
第10行将flags参数的值拷到超级块的s_flags字段中。
第11行的函数指针指向ramfs_fill_super函数,来分配索引节点对象和对应的目录项对象,并填充超级块字段的值。由于rootfs是一种特殊文件系统,没有磁盘超级块,因此只需执行这两个超级块的操作。
[cpp]
view plaincopyprint?
01static int ramfs_fill_super(struct super_block * sb,
void * data, int silent)
02{
03 struct ramfs_fs_info *fsi;
04 struct inode *inode = NULL;
05 struct dentry *root;
06 int err;
07 save_mount_options(sb, data);
08 fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
09 sb->s_fs_info = fsi;
10 if (!fsi) {
11 err = -ENOMEM;
12 goto fail;
13 }
14 err = ramfs_parse_options(data, &fsi->mount_opts);
15 if (err)
16 goto fail;
17 sb->s_maxbytes = MAX_LFS_FILESIZE;
18 sb->s_blocksize = PAGE_CACHE_SIZE;
19 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
20 sb->s_magic = RAMFS_MAGIC;
21 sb->s_op = &ramfs_ops;
22 sb->s_time_gran = 1;
23 inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);
24 if (!inode) {
25 err = -ENOMEM;
26 goto fail;
27 }
28 root = d_alloc_root(inode);
29 sb->s_root = root;
30 if (!root) {
31 err = -ENOMEM;
32 goto fail;
33 }
34 return 0;
35fail:
36 kfree(fsi);
37 sb->s_fs_info = NULL;
38 iput(inode);
39 return err;
40}
第7行如果文件系统使用generic_show_options()函数,这个函数将回调fill_super()调用,特殊情况下,.remount_fs回调函数,也会处理
第17行给超级块的文件的最长长度赋值
第18行给超级块的字节为单位的块大小的字段赋值
第19行给超级块的位为单位的大小的字段赋值
第21行超级块的方法指向ramfs_ops结构体的地址
第22行超级块时间戳的粒度赋值
第23行分配一个新的索引节点,并初始化新的索引节点
第28行分配/目录
第29行超级块的根目录指向/目录
第35-40行对一些错误信息的处理。
[cpp]
view plaincopyprint?
01struct inode *ramfs_get_inode(struct super_block *sb,
int mode, dev_t dev)
02{
03 struct inode * inode = new_inode(sb);
04 if (inode) {
05 inode->i_mode = mode;
06 inode->i_uid = current_fsuid();
07 inode->i_gid = current_fsgid();
08 inode->i_mapping->a_ops = &ramfs_aops;
09 inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
10 mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
11 mapping_set_unevictable(inode->i_mapping);
12 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
13 switch (mode & S_IFMT) {
14 default:
15 init_special_inode(inode, mode, dev);
16 break;
17 case S_IFREG:
18 inode->i_op = &ramfs_file_inode_operations;
19 inode->i_fop = &ramfs_file_operations;
20 break;
21 case S_IFDIR:
22 inode->i_op = &ramfs_dir_inode_operations;
23 inode->i_fop = &simple_dir_operations;
24 /* directory inodes start off with i_nlink == 2 (for "." entry) */
25 inc_nlink(inode);
26 break;
27 case S_IFLNK:
28 inode->i_op = &page_symlink_inode_operations;
29 break;
30 }
31 }
32 return inode;
33}
第3行分配一个新的索引节点
第5行对索引节点的模式赋值
第6行对索引节点的所有者标识符字段赋值
第7行对索引节点的组标识符字段赋值
第10行对索引节点的指向address_space对象的方法赋值(后面会分析)
第11行对索引节点的指向address_space对象的设备信息赋值
第12行索引节点的上次访问时间,上次写时间,索引节点修改时间都赋值为现在时间
第13行switch语句,用于多分支选择,这里面是选择17行的代码
第14行默认情况是使用init_special_inode函数,主要用字符设备,块设备的索引节点
第18行索引节点的方法指向ramfs_file_inode_operations;
第19行索引节点的文件方法操作指向ramfs_file_operations。
第22行如果是文件夹操作,其方法指向ramfs_dir_inode_operations;
第23行其文件操作的方法也相应的指向simple_dir_operations;
第32行返回索引节点。
[cpp]
view plaincopyprint?
01struct dentry * d_alloc_root(struct inode * root_inode)
02{
03 struct dentry *res = NULL;
04 if (root_inode) {
05 static
const struct qstr name = { .name =
"/", .len = 1 };
06 res = d_alloc(NULL, &name);
07 if (res) {
08 res->d_sb = root_inode->i_sb;
09 res->d_parent = res;
10 d_instantiate(res, root_inode);
11 }
12 }
13 return res;
14}
第4行这里面的root_inode为真值
第5行对name结构体初始化
第6行分配一个dcache 目录
第8行目录项的超级块指向指向索引节点的超级块指针
第9行目录项的父指针指向自己
第10填充索引节点信息为根目录。
其实,目录项也可以当作目录文件对待,但目录项结构与inode结构所描述的目标是不同,目录结构所代表的是逻辑意义上的文件,记录的是其逻辑上的属性。而inode结构所代表的是物理意义上的文件,记录的是其物理上的属性。
在开始介绍rootfs之前,先介绍一下,rootfs的数据结构,然后再看一下rootfs中的函数rootfs_get_sb是怎么调用的。
rootfs的数据结构如下
[cpp]
view plaincopyprint?
1static struct file_system_type rootfs_fs_type = {
2 .name = "rootfs",
3 .get_sb = rootfs_get_sb,
4 .kill_sb = kill_litter_super,
5};
1static struct file_system_type rootfs_fs_type = { 2 .name = "rootfs", 3 .get_sb = rootfs_get_sb, 4 .kill_sb = kill_litter_super, 5};
第2行文件系统的名字
第3行挂载文件系统时分配超级块
第4行卸载文件系统时回收超级块
[cpp]
view plaincopyprint?
01static void __init init_mount_tree(void)
02{
03 .......
04 mnt = do_kern_mount("rootfs", 0,
"rootfs", NULL);
05 .......
06}
07struct vfsmount *
08do_kern_mount(const
char *fstype, int flags,
const char *name,
void *data)
09{
10 ....
11 mnt = vfs_kern_mount(type, flags, name, data);
12 ....
13}
14struct vfsmount *
15vfs_kern_mount(struct file_system_type *type,
int flags, const
char *name, void *data)
16{
17 .....
18 error = type->get_sb(type, flags, name, data, mnt);
19 ......
20}
01static void __init init_mount_tree(void) 02{ 03 ....... 04 mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); 05 ....... 06} 07struct vfsmount * 08do_kern_mount(const char *fstype, int flags, const char *name, void *data) 09{ 10 .... 11 mnt = vfs_kern_mount(type, flags, name, data); 12 .... 13} 14struct vfsmount * 15vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) 16{ 17 ..... 18 error = type->get_sb(type, flags, name, data, mnt); 19 ...... 20}
上面是内核在启动时挂载rootfs文件系统的简单流程,其中在第18行是,会调用rootfs文件系统中的rootfs_get_sb函数,其函数如下。
[cpp]
view plaincopyprint?
1static int rootfs_get_sb(struct file_system_type *fs_type,
2 int flags, const
char *dev_name, void *data,
struct vfsmount *mnt)
3{
4 return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
5 mnt);
6}
1static int rootfs_get_sb(struct file_system_type *fs_type, 2 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 3{ 4 return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super, 5 mnt); 6}
[cpp]
view plaincopyprint?
01int get_sb_nodev(struct file_system_type *fs_type,
02 int flags, void *data,
03 int (*fill_super)(struct super_block *,
void *, int),
04 struct vfsmount *mnt)
05{
06 int error;
07 struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
08 if (IS_ERR(s))
09 return PTR_ERR(s);
10 s->s_flags = flags;
11 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
12 if (error) {
13 deactivate_locked_super(s);
14 return error;
15 }
16 s->s_flags |= MS_ACTIVE;
17 simple_set_mnt(mnt, s);
18 return 0;
19}
01int get_sb_nodev(struct file_system_type *fs_type, 02 int flags, void *data, 03 int (*fill_super)(struct super_block *, void *, int), 04 struct vfsmount *mnt) 05{ 06 int error; 07 struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); 08 if (IS_ERR(s)) 09 return PTR_ERR(s); 10 s->s_flags = flags; 11 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); 12 if (error) { 13 deactivate_locked_super(s); 14 return error; 15 } 16 s->s_flags |= MS_ACTIVE; 17 simple_set_mnt(mnt, s); 18 return 0; 19}
第7行调用sget()函数分配新的超级块,传递set_anon_super()函数的地址作为参数。用合适的方式设置超级块的s_dev字段。
第10行将flags参数的值拷到超级块的s_flags字段中。
第11行的函数指针指向ramfs_fill_super函数,来分配索引节点对象和对应的目录项对象,并填充超级块字段的值。由于rootfs是一种特殊文件系统,没有磁盘超级块,因此只需执行这两个超级块的操作。
[cpp]
view plaincopyprint?
01static int ramfs_fill_super(struct super_block * sb,
void * data, int silent)
02{
03 struct ramfs_fs_info *fsi;
04 struct inode *inode = NULL;
05 struct dentry *root;
06 int err;
07 save_mount_options(sb, data);
08 fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
09 sb->s_fs_info = fsi;
10 if (!fsi) {
11 err = -ENOMEM;
12 goto fail;
13 }
14 err = ramfs_parse_options(data, &fsi->mount_opts);
15 if (err)
16 goto fail;
17 sb->s_maxbytes = MAX_LFS_FILESIZE;
18 sb->s_blocksize = PAGE_CACHE_SIZE;
19 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
20 sb->s_magic = RAMFS_MAGIC;
21 sb->s_op = &ramfs_ops;
22 sb->s_time_gran = 1;
23 inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);
24 if (!inode) {
25 err = -ENOMEM;
26 goto fail;
27 }
28 root = d_alloc_root(inode);
29 sb->s_root = root;
30 if (!root) {
31 err = -ENOMEM;
32 goto fail;
33 }
34 return 0;
35fail:
36 kfree(fsi);
37 sb->s_fs_info = NULL;
38 iput(inode);
39 return err;
40}
01static int ramfs_fill_super(struct super_block * sb, void * data, int silent) 02{ 03 struct ramfs_fs_info *fsi; 04 struct inode *inode = NULL; 05 struct dentry *root; 06 int err; 07 save_mount_options(sb, data); 08 fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); 09 sb->s_fs_info = fsi; 10 if (!fsi) { 11 err = -ENOMEM; 12 goto fail; 13 } 14 err = ramfs_parse_options(data, &fsi->mount_opts); 15 if (err) 16 goto fail; 17 sb->s_maxbytes = MAX_LFS_FILESIZE; 18 sb->s_blocksize = PAGE_CACHE_SIZE; 19 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 20 sb->s_magic = RAMFS_MAGIC; 21 sb->s_op = &ramfs_ops; 22 sb->s_time_gran = 1; 23 inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0); 24 if (!inode) { 25 err = -ENOMEM; 26 goto fail; 27 } 28 root = d_alloc_root(inode); 29 sb->s_root = root; 30 if (!root) { 31 err = -ENOMEM; 32 goto fail; 33 } 34 return 0; 35fail: 36 kfree(fsi); 37 sb->s_fs_info = NULL; 38 iput(inode); 39 return err; 40}
第7行如果文件系统使用generic_show_options()函数,这个函数将回调fill_super()调用,特殊情况下,.remount_fs回调函数,也会处理
第17行给超级块的文件的最长长度赋值
第18行给超级块的字节为单位的块大小的字段赋值
第19行给超级块的位为单位的大小的字段赋值
第21行超级块的方法指向ramfs_ops结构体的地址
第22行超级块时间戳的粒度赋值
第23行分配一个新的索引节点,并初始化新的索引节点
第28行分配/目录
第29行超级块的根目录指向/目录
第35-40行对一些错误信息的处理。
[cpp]
view plaincopyprint?
01struct inode *ramfs_get_inode(struct super_block *sb,
int mode, dev_t dev)
02{
03 struct inode * inode = new_inode(sb);
04 if (inode) {
05 inode->i_mode = mode;
06 inode->i_uid = current_fsuid();
07 inode->i_gid = current_fsgid();
08 inode->i_mapping->a_ops = &ramfs_aops;
09 inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
10 mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
11 mapping_set_unevictable(inode->i_mapping);
12 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
13 switch (mode & S_IFMT) {
14 default:
15 init_special_inode(inode, mode, dev);
16 break;
17 case S_IFREG:
18 inode->i_op = &ramfs_file_inode_operations;
19 inode->i_fop = &ramfs_file_operations;
20 break;
21 case S_IFDIR:
22 inode->i_op = &ramfs_dir_inode_operations;
23 inode->i_fop = &simple_dir_operations;
24 /* directory inodes start off with i_nlink == 2 (for "." entry) */
25 inc_nlink(inode);
26 break;
27 case S_IFLNK:
28 inode->i_op = &page_symlink_inode_operations;
29 break;
30 }
31 }
32 return inode;
33}
01struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev) 02{ 03 struct inode * inode = new_inode(sb); 04 if (inode) { 05 inode->i_mode = mode; 06 inode->i_uid = current_fsuid(); 07 inode->i_gid = current_fsgid(); 08 inode->i_mapping->a_ops = &ramfs_aops; 09 inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info; 10 mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); 11 mapping_set_unevictable(inode->i_mapping); 12 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 13 switch (mode & S_IFMT) { 14 default: 15 init_special_inode(inode, mode, dev); 16 break; 17 case S_IFREG: 18 inode->i_op = &ramfs_file_inode_operations; 19 inode->i_fop = &ramfs_file_operations; 20 break; 21 case S_IFDIR: 22 inode->i_op = &ramfs_dir_inode_operations; 23 inode->i_fop = &simple_dir_operations; 24 /* directory inodes start off with i_nlink == 2 (for "." entry) */ 25 inc_nlink(inode); 26 break; 27 case S_IFLNK: 28 inode->i_op = &page_symlink_inode_operations; 29 break; 30 } 31 } 32 return inode; 33}
第3行分配一个新的索引节点
第5行对索引节点的模式赋值
第6行对索引节点的所有者标识符字段赋值
第7行对索引节点的组标识符字段赋值
第10行对索引节点的指向address_space对象的方法赋值(后面会分析)
第11行对索引节点的指向address_space对象的设备信息赋值
第12行索引节点的上次访问时间,上次写时间,索引节点修改时间都赋值为现在时间
第13行switch语句,用于多分支选择,这里面是选择17行的代码
第14行默认情况是使用init_special_inode函数,主要用字符设备,块设备的索引节点
第18行索引节点的方法指向ramfs_file_inode_operations;
第19行索引节点的文件方法操作指向ramfs_file_operations。
第22行如果是文件夹操作,其方法指向ramfs_dir_inode_operations;
第23行其文件操作的方法也相应的指向simple_dir_operations;
第32行返回索引节点。
[cpp]
view plaincopyprint?
01struct dentry * d_alloc_root(struct inode * root_inode)
02{
03 struct dentry *res = NULL;
04 if (root_inode) {
05 static
const struct qstr name = { .name =
"/", .len = 1 };
06 res = d_alloc(NULL, &name);
07 if (res) {
08 res->d_sb = root_inode->i_sb;
09 res->d_parent = res;
10 d_instantiate(res, root_inode);
11 }
12 }
13 return res;
14}
01struct dentry * d_alloc_root(struct inode * root_inode) 02{ 03 struct dentry *res = NULL; 04 if (root_inode) { 05 static const struct qstr name = { .name = "/", .len = 1 }; 06 res = d_alloc(NULL, &name); 07 if (res) { 08 res->d_sb = root_inode->i_sb; 09 res->d_parent = res; 10 d_instantiate(res, root_inode); 11 } 12 } 13 return res; 14}
第4行这里面的root_inode为真值
第5行对name结构体初始化
第6行分配一个dcache 目录
第8行目录项的超级块指向指向索引节点的超级块指针
第9行目录项的父指针指向自己
第10填充索引节点信息为根目录。
其实,目录项也可以当作目录文件对待,但目录项结构与inode结构所描述的目标是不同,目录结构所代表的是逻辑意义上的文件,记录的是其逻辑上的属性。而inode结构所代表的是物理意义上的文件,记录的是其物理上的属性。
相关文章推荐
- rootfs文件系统简单分析
- rootfs文件系统的简单分析
- linux文件系统的系统分析--(三)rootfs的安装
- linux文件系统的系统分析--(三)rootfs的安装
- Glusterfs文件系统简介和源码简单分析
- 根文件系统分析之旅——简单分析(一)
- sysfs 文件系统简单分析
- linux文件系统的系统分析--(三)rootfs的安装
- 20135337——Linux实践三:ELF文件格式(64位系统,简单分析)
- linux 根文件系统 rootfs 制作
- struts简单例子的分析(含代码注释和配置文件说明)
- 一个简单的文件系统过滤驱动框架
- Linux--根文件系统的挂载过程分析
- UBIFS文件系统分析7 - LPROPS .
- 深入浅出 - Android系统移植与平台开发(十) - led HAL简单设计案例分析
- 九鼎创展s5p4418开发板Android4.4-文件系统编译脚本分析
- Linux内核源码分析--文件系统(六、Super.c)
- Ext4功能和文件系统的简单功能
- linux 部署ELK 日志分析系统与简单测试
- 班尼路信息化系统基础选型的简单分析