天天看點

rootfs檔案系統的注冊和挂載

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檔案系統的挂載過程,這裡隻畫出挂載後的主要結構之間關系圖。

rootfs檔案系統的注冊和挂載

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目錄,然後為以後挂載檔案系統提供挂載點。 

繼續閱讀