linux文件系统的系统分析--(三)rootfs的安装



在《linux文件系统的系统分析--(一)文件系统类型的注册》我们以rootfs为例分析了文件系统是如何注册的,接着我们就分析rootfs的安装。

         在mnt_init-->init_mount_tree:

[cpp]   view plain  copy
  1. static void __init init_mount_tree(void)  
  2. {  
  3.     struct vfsmount *mnt;  
  4.     struct mnt_namespace *ns;  
  5.     struct path root;  
  6.   
  7.     mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);  
  8.     if (IS_ERR(mnt))  
  9.         panic("Can't create rootfs");  
  10.     ns = create_mnt_ns(mnt);  
  11.     if (IS_ERR(ns))  
  12.         panic("Can't allocate initial namespace");  
  13.   
  14.     init_task.nsproxy->mnt_ns = ns;  
  15.     get_mnt_ns(ns);  
  16.   
  17.     root.mnt = ns->root;  
  18.     root.dentry = ns->root->mnt_root;  
  19.   
  20.     set_fs_pwd(current->fs, &root);  
  21.     set_fs_root(current->fs, &root);  
  22. }  
            其中vfsmount结构体用来描述安装的文件系统;mnt_namespace描述命名空间;

            分为3部分来分析这个函数:

            1、mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);这个是安装操作的核心;

[cpp]   view plain  copy
  1. struct vfsmount *  
  2. do_kern_mount(const char *fstype, int flags, const char *name, void *data)  
  3. {  
  4.     struct file_system_type *type = get_fs_type(fstype);  
  5.     struct vfsmount *mnt;  
  6.     if (!type)  
  7.         return ERR_PTR(-ENODEV);  
  8.     mnt = vfs_kern_mount(type, flags, name, data);  
  9.     if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&  
  10.         !mnt->mnt_sb->s_subtype)  
  11.         mnt = fs_set_subtype(mnt, fstype);  
  12.     put_filesystem(type);  
  13.     return mnt;  
  14. }  
           1.1、首先根据“rootfs”这个标识文件系统类型的字符串在file_systems为表头的单向链表中查找文件系统类型,获取rootfs文件系统的类型( rootfs_fs_type);

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

[cpp]   view plain  copy
  1. struct vfsmount *  
  2. vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)  
  3. {  
  4.     struct vfsmount *mnt;  
  5.     char *secdata = NULL;  
  6.     int error;  
  7.   
  8.     if (!type)  
  9.         return ERR_PTR(-ENODEV);  
  10.   
  11.     error = -ENOMEM;  
  12.     mnt = alloc_vfsmnt(name);  
  13.     if (!mnt)  
  14.         goto out;  
  15.   
  16.     if (flags & MS_KERNMOUNT)  
  17.         mnt->mnt_flags = MNT_INTERNAL;  
  18.   
  19.     if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {  
  20.         secdata = alloc_secdata();  
  21.         if (!secdata)  
  22.             goto out_mnt;  
  23.   
  24.         error = security_sb_copy_data(data, secdata);  
  25.         if (error)  
  26.             goto out_free_secdata;  
  27.     }  
  28.   
  29.     error = type->get_sb(type, flags, name, data, mnt);  
  30.     if (error < 0)  
  31.         goto out_free_secdata;  
  32.     BUG_ON(!mnt->mnt_sb);  
  33.     WARN_ON(!mnt->mnt_sb->s_bdi);  
  34.   
  35.     error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);  
  36.     if (error)  
  37.         goto out_sb;  
  38.   
  39.     /* 
  40.      * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE 
  41.      * but s_maxbytes was an unsigned long long for many releases. Throw 
  42.      * this warning for a little while to try and catch filesystems that 
  43.      * violate this rule. This warning should be either removed or 
  44.      * converted to a BUG() in 2.6.34. 
  45.      */  
  46.     WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "  
  47.         "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);  
  48.   
  49.     mnt->mnt_mountpoint = mnt->mnt_root;  
  50.     mnt->mnt_parent = mnt;  
  51.     up_write(&mnt->mnt_sb->s_umount);  
  52.     free_secdata(secdata);  
  53.     return mnt;  
  54. out_sb:  
  55.     dput(mnt->mnt_root);  
  56.     deactivate_locked_super(mnt->mnt_sb);  
  57. out_free_secdata:  
  58.     free_secdata(secdata);  
  59. out_mnt:  
  60.     free_vfsmnt(mnt);  
  61. out:  
  62.     return ERR_PTR(error);  
  63. }  

            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来获取超级块:

[cpp]   view plain  copy
  1. static int rootfs_get_sb(struct file_system_type *fs_type,  
  2.     int flags, const char *dev_name, void *data, struct vfsmount *mnt)  
  3. {  
  4.     return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,  
  5.                 mnt);  
  6. }  
      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目录下了。


       到这里,"/"终于出现了!

转自http://blog.csdn.net/dndxhej/article/details/7423734



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值