rootfs文件系统是由init_rootfs()完成的。
int __init init_rootfs(void)
{
int err;
err = bdi_init(&ramfs_backing_dev_info);
if (err)
return err;
err = register_filesystem(&rootfs_fs_type);
if (err)
bdi_destroy(&ramfs_backing_dev_info);
return err;
}
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
struct file_system_type ** p;
BUG_ON(strchr(fs->name, '.'));
if (fs->next)
return -EBUSY;
INIT_LIST_HEAD(&fs->fs_supers);
write_lock(&file_systems_lock);
p = find_filesystem(fs->name, strlen(fs->name));
if (*p)
res = -EBUSY;
else
*p = fs;
if(strncmp(fs->name, "rootfs", strlen(fs->name)) == 0)
printk(KERN_WARNING 0x%x,0x%x,0x%x,",file_systems,file_systems->next,file_systems->next->next);
write_unlock(&file_systems_lock);
return res;
}
注册过程可以参考上篇文章 sysfs 文件系统的注册过程。
我在该函数中加入打印语句,打印全局变量file_systems和file_systems->next,
file_systems->next->next,在其他地方也加有打印语句,打印全局变量rootfs_fs_type和
Sysfs_fs_type的地址。打印结果如下:
&sysfs_fs_type = 0x802c7550
&rootfs_fs_type = 0x802c7810
file_systems = 0x802c7550
file_systems->next = 0x802c7810
file_systems->next->next = 0x0
可见file_systems指向&sysfs_fs_type,file_systems->next 也就是&sysfs_fs_type->next指向
&rootfs_fs_type,而 file_systems->next->next 也就是&rootfs_fs_type->next为空。因为此时只注册了两个文件系统。打印结果也验证了上篇文章的图一。
下面来看看rootfs文件系统的挂载和根目录的建立
static void __init init_mount_tree(void)
{
struct vfsmount *mnt;
struct mnt_namespace *ns;
struct path root;
mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
if (IS_ERR(mnt))
panic("Can't create rootfs");
ns = create_mnt_ns(mnt);
if (IS_ERR(ns))
panic("Can't allocate initial namespace");
init_task.nsproxy->mnt_ns = ns;
/*ns->count = 2*/
get_mnt_ns(ns);
/*将根目录的挂载点和目录项设置为
*挂载rootfs时生成的挂载点和目录项
*/
root.mnt = ns->root;
root.dentry = ns->root->mnt_root;
set_fs_pwd(current->fs, &root);
set_fs_root(current->fs, &root);
}
1.
rootfs文件系统的挂载是由do_kern_mount("rootfs", 0, "rootfs", NULL)完成。
挂载过程参考sysfs文件系统的挂载过程,这里只画出挂载后的主要结构之间关系图。
2.
挂载完成后,会创建一个namespace,并将rootfs添加进去
struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
{
struct mnt_namespace *new_ns;
new_ns = alloc_mnt_ns();
if (!IS_ERR(new_ns)) {
/*建立namespace和root mnt之间的关系*/
mnt->mnt_ns = new_ns;
new_ns->root = mnt;
/*???*/
list_add(&new_ns->list, &new_ns->root->mnt_list);
}
return new_ns;
}
static struct mnt_namespace *alloc_mnt_ns(void)
{
struct mnt_namespace *new_ns;
/*分配一个namespace*/
new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns)
return ERR_PTR(-ENOMEM);
/*ns->count = 1*/
atomic_set(&new_ns->count, 1);
new_ns->root = NULL;
INIT_LIST_HEAD(&new_ns->list);
init_waitqueue_head(&new_ns->poll);
new_ns->event = 0;
return new_ns;
}
3.代码的最后两行设置init进程的根目录和当前目录,这样所有以后从 init进程 fork 出来的进程也都先天地继承了这一信息。
以上讲了一大堆数据结构的来历,其实最终目的不过是要在内存中建立一颗 VFS 目录树而已,更确切地说, init_mount_tree() 这个函数为 VFS 建立了根目录 "/",而一旦有了根,那么这棵数就可以发展壮大,比如可以通过系统调用 sys_mkdir 在这棵树上建立新的叶子节点等。例如建立一个dev目录,然后为以后挂载文件系统提供挂载点。