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檔案系統的挂載過程,這裡隻畫出挂載後的主要結構之間關系圖。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TVXRGN5cVW1ZUbiZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DOygTOzUDMxETMyYDM0EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
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目錄,然後為以後挂載檔案系統提供挂載點。