分类: LINUX
2017-03-13 14:09:09
原文地址:VFS的rootfs初始化 作者:xingzuzi
在Linux系统中,每个文件系统都会以数据结构来表示,定义为:
Code.1
struct file_system_type { const char *name; //文件系统名称,如ext2 int fs_flags; int (*get_sb) (struct file_system_type *, int, const char *, void *, struct vfsmount *); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next;//指向下一文件系统 struct list_head fs_supers; struct lock_class_key s_lock_key; struct lock_class_key s_umount_key; };
|
注册文件系统就是将各种文件系统实例化,形成链表,内核中使用一个名为file_systems的全局变量来指向该链表表头。
Code.2
static struct file_system_type *file_systems;
|
VFS建立目录树首先要初始化rootfs,然后将其挂接。
对于rootfs类型,其文件系统实例结构定义为:
Code.3
static struct file_system_type rootfs_fs_type = { .name = "rootfs", .get_sb = rootfs_get_sb, //get_sb的方法为rootfs_get_sb,这个在init_mnt_tree中会用到 .kill_sb = kill_litter_super, };
|
此时用图来表示为:
一个独立的file_systems指针,一个file_system_type的rootfs
首先要初始化rootfs:
Code.4
int __init init_rootfs(void) //初始化rootfs { return register_filesystem(&rootfs_fs_type); //注册rootfs }
|
其中
Code.4.1
int register_filesystem(struct file_system_type * fs) { int res = 0; struct file_system_type ** p;
if (fs->next) return -EBUSY; INIT_LIST_HEAD(&fs->fs_supers);//初始化LIST_HEAD fs->fs_supers write_lock(&file_systems_lock); // p = find_filesystem(fs->name); //检查文件系统是否被注册,下面的详细说明 if (*p) res = -EBUSY; else *p = fs; //没有被注册,将file_systems的链表指向此fs,形成注册的文件系统的链表结构 write_unlock(&file_systems_lock); return res; }
|
下面是find_filesystem的实现:
Code.4.1.1
static struct file_system_type **find_filesystem(const char *name) { struct file_system_type **p; for (p=&file_systems; *p; p=&(*p)->next) //file_systems是全局变量指向文件系统类型 if (strcmp((*p)->name,name) == 0) //查找文件系统是否被注册过,如果没有,那么p最后为file_systems链尾的next,如果被注册过,那么返回指向这个文件系统的指针 break; return p; }
|
这样,rootfs就注册成功了,此时可表示为:
File_systemsr指向file_system_type(ramfs)。
然后是初始化树,init_mount_tree。
init_mount_tree首先会调用do_kern_mount("rootfs", 0, "rootfs", NULL);进行rootfs的挂接。
Code.5
struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data) { struct file_system_type *type = get_fs_type(fstype); //通过ramfs得到ramfs的file_system_type struct vfsmount *mnt; if (!type) return ERR_PTR(-ENODEV); mnt = vfs_kern_mount(type, flags, name, data);//开始干正事了 put_filesystem(type); return mnt; }
|
只保留主干代码的vfs_kern_mount。
Code.5.1
struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { struct vfsmount *mnt; int error;
mnt = alloc_vfsmnt(name); //初始化一个struct vfsmount mnt,并初始化struct中的LIST_HEAD,mnt->mnt_count=1;mnt->mnt_devname=name
error = type->get_sb(type, flags, name, data, mnt);//建立一个superblock,然后与mnt建立上关系,下面会有说明 if (error < 0) goto out_free_secdata;
mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt;//将parent指向自己 return mnt; }
|
type->get_sb的实例在此时应该为ramfs_get_sb。
Code.5.1.1
int ramfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { return get_sb_nodev(fs_type, flags, data, ramfs_fill_super, mnt); //使用ramfs_fill_super来写superblock的相关数据 }
|
Code.5.1.1.1
int get_sb_nodev(struct file_system_type *fs_type, int flags, void *data, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt) { int error; struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);//初始化一个super block,设置s->s_dev,s->s_type=type,s->s_id=type->name,将super_blocks指向s->s_list,将type->fs_super指向s->s_instances。
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);//这里的fill_super即是ramfs_fill_super,下面详细说明 s->s_flags |= MS_ACTIVE; return simple_set_mnt(mnt, s); }
|
Code.5.1.1.1.1
static int ramfs_fill_super(struct super_block * sb, void * data, int silent) { struct inode * inode; struct dentry * root;
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = RAMFS_MAGIC; sb->s_op = &ramfs_ops;//这里定义的ramfs_ops为 /* static const struct super_operations ramfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, }; */ sb->s_time_gran = 1; inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);//初始化一个inode,并将与sb建立关系,设置inode各种属性
root = d_alloc_root(inode);//分配dentry root if (!root) { iput(inode); return -ENOMEM; } sb->s_root = root; return 0; }
|