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目錄,然後爲以後掛載文件系統提供掛載點。