linux文件系統的系統分析--(三)rootfs的安裝

 在《linux文件系統的系統分析--(一)文件系統類型的註冊》我們以rootfs爲例分析了文件系統是如何註冊的,接着我們就分析rootfs的安裝。

         在mnt_init-->init_mount_tree:

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;
	get_mnt_ns(ns);

	root.mnt = ns->root;
	root.dentry = ns->root->mnt_root;

	set_fs_pwd(current->fs, &root);
	set_fs_root(current->fs, &root);
}
            其中vfsmount結構體用來描述安裝的文件系統;mnt_namespace描述命名空間;

            分爲3部分來分析這個函數:

            1、mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);這個是安裝操作的核心;

struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
	struct file_system_type *type = get_fs_type(fstype);
	struct vfsmount *mnt;
	if (!type)
		return ERR_PTR(-ENODEV);
	mnt = vfs_kern_mount(type, flags, name, data);
	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
	    !mnt->mnt_sb->s_subtype)
		mnt = fs_set_subtype(mnt, fstype);
	put_filesystem(type);
	return mnt;
}
           1.1、首先根據“rootfs”這個標識文件系統類型的字符串在file_systems爲表頭的單向鏈表中查找文件系統類型,獲取rootfs文件系統的類型(rootfs_fs_type);

           1.2、mnt = vfs_kern_mount(type, flags, name, data);

struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
	struct vfsmount *mnt;
	char *secdata = NULL;
	int error;

	if (!type)
		return ERR_PTR(-ENODEV);

	error = -ENOMEM;
	mnt = alloc_vfsmnt(name);
	if (!mnt)
		goto out;

	if (flags & MS_KERNMOUNT)
		mnt->mnt_flags = MNT_INTERNAL;

	if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
		secdata = alloc_secdata();
		if (!secdata)
			goto out_mnt;

		error = security_sb_copy_data(data, secdata);
		if (error)
			goto out_free_secdata;
	}

	error = type->get_sb(type, flags, name, data, mnt);
	if (error < 0)
		goto out_free_secdata;
	BUG_ON(!mnt->mnt_sb);
	WARN_ON(!mnt->mnt_sb->s_bdi);

	error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
	if (error)
		goto out_sb;

	/*
	 * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
	 * but s_maxbytes was an unsigned long long for many releases. Throw
	 * this warning for a little while to try and catch filesystems that
	 * violate this rule. This warning should be either removed or
	 * converted to a BUG() in 2.6.34.
	 */
	WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
		"negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);

	mnt->mnt_mountpoint = mnt->mnt_root;
	mnt->mnt_parent = mnt;
	up_write(&mnt->mnt_sb->s_umount);
	free_secdata(secdata);
	return mnt;
out_sb:
	dput(mnt->mnt_root);
	deactivate_locked_super(mnt->mnt_sb);
out_free_secdata:
	free_secdata(secdata);
out_mnt:
	free_vfsmnt(mnt);
out:
	return ERR_PTR(error);
}

            1.2.1、mnt = alloc_vfsmnt(name);初始化struct vfsmount *mnt;結構體;

            1.2.2、error = type->get_sb(type, flags, name, data, mnt);調用rootfs的get_sb方法rootfs_get_sb來獲取超級塊:

static int rootfs_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|MS_NOUSER, data, ramfs_fill_super,
			    mnt);
}
      get_sb_nodev函數主要步驟如下:
      1.2.2.1、struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
      set_anon_super獲得一個未使用的次設備號dev,然後用主設備號0和次設備號dev設置s的s_dev字段
      調用alloc_super函數來初始化s,然後對s這個super_block超級塊的幾個關鍵字段賦值:
      s的s_dev字段就是前面提到的設備號,s的s_type就是rootfs_fs_type這個file_system_type結構體類型的指針,
      s的s_id字段放置文件系統類型的名稱"rootfs",將新建的super_block對象加入以super_blocks爲頭的雙向鏈表中,鏈接的字段是struct list_head s_list;
              將s的s_instances字段加入rootfs的的fs_supers雙向鏈表頭,這裏表明同一種文件系統類型可以有多個super_block,有多個實例,這些鬥用fs_supers串起來。

             1.2.2.2、調用rootfs的fill_super(ramfs_fill_super)來分配索引節點對象和對應的目錄項對象,並填充超級塊字段值。這裏會建立rootfs的“/”目錄項對象和索引節點對象。

             sb->s_root = root;   這個root就是“/”目錄項對象。

             1.2.2.3、將mnt的mnt_sb指向剛建的super_block超級塊對象,將mnt的mnt_root指向sb的s_root對象("/"的目錄項對象)

             1.2.3、

             mnt->mnt_mountpoint = mnt->mnt_root;  安裝樹的根的目錄項和安裝點的目錄項都指向前面的root(rootfs的"/"目錄項對象)
     mnt->mnt_parent = mnt;  將我們mount的文件系統指向自己。比如在/mnt/a下是mount了一塊ext2的磁盤,在/mnt/a/b下又mount  omfs文件系統,那麼這裏的parent就可              以指明這個關係。

            2、ns = create_mnt_ns(mnt);

             新建一個私有的命名空間(mnt_namespace),並添加root fs:

               mnt->mnt_ns = new_ns;
new_ns->root = mnt;
list_add(&new_ns->list, &new_ns->root->mnt_list);

           3、

              root.mnt = ns->root;
      root.dentry = ns->root->mnt_root;


       set_fs_pwd(current->fs, &root);
       set_fs_root(current->fs, &root);

           將進程0的根目錄和當前工作目錄設備爲根文件系統。



           到目前我們看得rootfs都是基於內存的數據,要真正安裝根文件系統,就要安裝實際的文件系統。我們以磁盤的文件系統爲例。

           在系統初始化的最後部分:

            start_kernel-->rest_init-->kernel_init-->prepare_namespace

            1、把root_device_name變量設置爲從啓動參數"root"中獲取的設備文件名。同樣把ROOT_DEV變量設置爲同一設備文件的主設備號和次設備號。

            實際上代碼中會優先將root_device_name和mtd ubi做對比,如果有這樣的flash設備,就從flash上建立文件系統。

            2、還是以磁盤說明,調用mount_root函數:

                  2.1、調用sys_mknod在rootfs初始根文件系統中創建設備文件/dev/root,其主次設備號與ROOT_DEV中的一樣。

                  2.2、分配一個緩衝區並用文件系統類型名鏈表填充它。該鏈表通過啓動參數"rootfstype"傳送給內核,也可以通過file_systems爲頭的單向鏈表中獲取元素建立。

                  2.3、掃描上面建立的鏈表,對每一種文件系統鬥調用sys_mount在根目錄上安裝給定的文件系統類型。但是由於每種文件系統都有自己的magic,在get_sb時候會從 

                  物理設備的特定位置讀到magic,這個magic實在mkfs的時候寫入物理設備的。因爲magic的存在,所以大多數文件系統不可用,只有一個例外,就是用根設備上實際                   使用過的文件系統的函數來填充超級塊的那個調用,該文件系統安裝在rootfs文件系統的/root目錄。

           3、

       sys_mount(".", "/", NULL, MS_MOVE, NULL);
       sys_chroot(".");

               移動rootfs文件系統目錄上的已安裝文件系統的安裝點。

           注意的是:rootfs文件系統沒有卸載,只是隱藏在基於磁盤(磁盤或flash這種存儲介質)的根文件系統下了。

         舉個例子說明:

         在pc的ubuntu下,

                 lrwxrwxrwx 1 root root 4 2012-04-03 14:46 /dev/root -> sda7

         sda7是安裝ubuntu的盤

         df -TH結果如下:

          Filesystem    Type    Size  Used Avail Use% Mounted on
          /dev/sda7     ext4     27G   24G 1011M  97% /
          none      devtmpfs    494M  716K  493M   1% /dev
          none         tmpfs    500M  1.3M  499M   1% /dev/shm
          none         tmpfs    500M  384K  500M   1% /var/run
          none         tmpfs    500M     0  500M   0% /var/lock

        看到的是ext4文件系統是在/dev/sda7這個磁盤上的,但它作爲實際的根文件系統,mount在"/"上了。

        因爲是雙系統,還可以看到:

           /dev/sda5  fuseblk    156G  141G   15G  91% /media/DATAPART

       win下的磁盤都被linux掛在/media目錄下了。


       到這裏,"/"終於出現了!

發佈了0 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章