linux文件系统的系统分析--(四)sysfs的安装和挂载


        在上一次分析rootfs的安装时,其实是不准确的,应该称为安装根文件系统。

        安装根文件系统分为两个阶段:

        1、内核安装特殊rootfs文件系统,该文件系统仅提供一个作为初始安装点的空目录。

        2、内核在空目录上安装实际根文件系统。比如pc上的ext4,比如嵌入式中用到的各种flash的根文件系统。

        这一次分析sysfs,发现sysfs的安装和挂载更特殊:

        在mnt_init中:

	err = sysfs_init();
	if (err)
		printk(KERN_WARNING "%s: sysfs_init error: %d\n",
			__func__, err);
	fs_kobj = kobject_create_and_add("fs", NULL);
	if (!fs_kobj)
		printk(KERN_WARNING "%s: kobj create error\n", __func__);
	init_rootfs();
	init_mount_tree();

         sysfs_init还在init_rootfs和init_mount_tree,这就很奇怪,rootfs还没初始化,整个vfs目录tree还没建起来,为什么就先sysfs_init了?我的理解是这样的:sys_init注册sysfs            并且建立sysfs的文件树,这样各种设备就可以在sysfs中表现出来。因为这个还是系统初始化的时候,我们需要很快先建立sysfs(fs bus driver这些目录当时仅仅建立在sysfs           的文件树中),而系统启动完以后,我们用mount -t sysfs  sysfs   /sys,这样sysfs才可以在整个vfs 目录树中得以展现,我们在用户空间才可以访问/sys目录。

          sys_init-->register_filesystem(&sysfs_fs_type); & kern_mount(&sysfs_fs_type);-->kern_mount_data-->vfs_kern_mount

          vfs_kern_mount我们已经分析过了,主要是根据文件系统的类型来创建vfsmount已安装文件系统描述符,并且sysfs自己的文件树建立起来了,也就是有了自己的“/”,这样           在初始后的过程就有了这个文件树的fs bus 等目录。

        sysfs在初始化之初就安装好了,后面才用mount -t sysfs  sysfs   /sys将其挂载在vfs目录树之下。

        在fs/namespace.c中有mount的系统调用的定义,主要是拷贝参数值到内核,然后调用do_mount

        do_mount主要步骤:

        1、调用kern_path(dir_name, LOOKUP_FOLLOW, &path);来获取安装点的路径名;

        2、检查安装的标志,决定做什么

        3、调用do_new_mount,基本上工作都在这里面。


        do_new_mount分为两步:

        1、do_kern_mount,这个已经分析过了,就是建立要mount的文件系统自己的目录树

        2、do_add_mount将步骤1中建立的目录树加入到vfs的目录树,或者说加到rootfs的目录树上,因为任何fs都必须直接或间接   挂在rootfs上。

  

        Do_add_mount 两个关键点:

       1

         /* Something was mounted here while we slept */

         while (d_mountpoint(path->dentry) &&

                follow_down(path))

注释说的很清楚:这句代码不起眼,确实mount的关键,主要作用是做vfsmount的切换,为什么这么说我们要看第二个关键点后就会明了。

      2graft_tree

       Graft:嫁接,接枝的意思

       从这个单词可以看出来,是将将要mount的目录树与当前目录的文件系统的目录树连接起来,很像嫁接技术,而原来文件系统     的目录树没损伤。

Graft_tree先做一些检查类的操作,然后执行关键函数:attach_recursive_mnt(mnt, path, NULL);

2.1propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);

将新mount的目录的mnt_listsource_mntmnt_list连接起来

2.2

                   mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);

                   commit_tree(source_mnt);

void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,

                            struct vfsmount *child_mnt)

{

         child_mnt->mnt_parent = mntget(mnt);

         child_mnt->mnt_mountpoint = dget(dentry);

         dentry->d_mounted++;

}

这样两个文件系统的目录嫁接就完成了,并且通过d_mounted标明被mount了。

static void commit_tree(struct vfsmount *mnt)

{

         struct vfsmount *parent = mnt->mnt_parent;

         struct vfsmount *m;

         LIST_HEAD(head);

         struct mnt_namespace *n = parent->mnt_ns;

 

         BUG_ON(parent == mnt);

 

         list_add_tail(&head, &mnt->mnt_list);

         list_for_each_entry(m, &head, mnt_list)

                   m->mnt_ns = n;

         list_splice(&head, n->list.prev);

 

         list_add_tail(&mnt->mnt_hash, mount_hashtable +

                                     hash(parent, mnt->mnt_mountpoint));

         list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);

         touch_mnt_namespace(n);

}

Commit_tree是将新的文件系统vfsmount加入到mount_hashtable这个hash表中。

 

分析完这里,我们再回头看第一个关键点:

         while (d_mountpoint(path->dentry) &&

                follow_down(path))

                   ;

 

static inline int d_mountpoint(struct dentry *dentry)

{

         return dentry->d_mounted;

}

 

int follow_down(struct path *path)

{

         struct vfsmount *mounted;

 

         mounted = lookup_mnt(path);

         if (mounted) {

                   dput(path->dentry);

                   mntput(path->mnt);

                   path->mnt = mounted;

                   path->dentry = dget(mounted->mnt_root);

                   return 1;

         }

         return 0;

}

 

如果当前的dentryd_mounted大于0,表明这个上面已经有mount过文件系统,就要用follow_down做文件系统的切换动作。

lookup_mnt(path);就是根据graft_tree中的mount_hashtable这个hash表来查找的。

查找到后:

                   path->mnt = mounted;

                   path->dentry = dget(mounted->mnt_root);

就完成了文件系统的切换。

 

经过这两个关键点,我们的目录树就嫁接成功了。

 

其实在路径查找中,也会有这种文件系统切换,因为要保证每个文件操作的操作方法与正确的文件系统相对应。

 

        到这里为止,sysfs也有了。下一篇分析路径查找,这个好难看,太长了。。。


 

智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告