在介绍根文件系统挂载之前先介绍一些基础知识initramfs当linux内核启动后,会找到并执行第一个用户程序,一般是init。这个程序存在于文件系统当中,文件系统存在于设备上,但不知道init存在哪个设备上,于是有了内核命令列选项root=,用来指定root文件系统存在于哪个设备上。然后由于后来的设备类型越来越来多,比如可能在scsi,sata,flash这些设备,还有的存在于网络设备上,不可能把这些设备的驱动编译进内核,这样内核就会越来越来大。为了解决这些问题,出现了基于ram的文件系统,initramfs,这个文件系统可以包含多个目录和程序init,然后通过这个程序,内核再用这个程序去挂载真正的要文件系统。如果没有这个程序,内核可以来寻找和挂载一个根分区,接着执行一些/sbin/init的变种。ramfsramf是一个小型的基于内存的文件系统,由于linux中页的数据被缓存在内存中,然后标识为可用,为防止别用,ramfs就是基于这种机制产生的。只是放在ramfs中的目录和页的缓存,不在写回。rootfsrootfs是一种特定的ramfs的实例,它一直存在于系统中,不能卸载。大部分其他的文件系统安装于rootfs之上。initramfs和rootfs之间的关系当内核启动的时候,会先注册和挂载一个虚拟的根文件系统,也就是rootfs,然后会把做好的initramfs(这个可以自己制作)中的文件解压到rootfs中。然后系统会挂载真的根文件系统,rootfs隐藏之后。我的开发板上的u-boot传送的参数为noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200 mem=64M。noinitrd的含义(仅当内核配置了选项 CONFIG_BLK_DEV_RAM和CONFIG_BLK_DEV_INITRD)现在的内核都可以支持initrd了,引导进程首先装载内核和一个初始化的ramdisk,然后内核将initrd转换成普通的ramdisk,也就是读写模式的根文件系统设备。然后linuxrc执行,然后装载真正的根文件系统,之后ramdisk被卸载,最后执行启动序列,比如/sbin/init。选项noinitrd告诉内核不执行上面的步骤,即使内核编译了initrd,而是把initrd的数据写到 /dev/initrd,只是这是一个一次性的设备。01void __init vfs_caches_init(unsigned long mempages)02{03 unsigned long reserve;0405 /* Base hash sizes on available memory, with a reserve equal to06 150% of current kernel size */0708 reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);09 mempages -= reserve;1011 names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,12 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);1314 dcache_init();15 inode_init();16 files_init(mempages);17 mnt_init();18 bdev_cache_init();19 chrdev_init();20}第14行为页目录缓存的初始化第15行索引结点缓存的初始化第16行文件的初始化第17行虚拟文件系统挂载的初始化第18行块设备缓存初始化。第19行字符设备初始化01void __init mnt_init(void)02{03 unsigned u;04 int err;0506 init_rwsem(&namespace_sem);0708 mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),09 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);1011 mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);1213 if (!mount_hashtable)14 panic("Failed to allocate mount hash table
");1516 printk("Mount-cache hash table entries: %lu
", HASH_SIZE);1718 for (u = 0; u < HASH_SIZE; u++)19 INIT_LIST_HEAD(&mount_hashtable[u]);2021 err = sysfs_init();22 if (err)23 printk(KERN_WARNING "%s: sysfs_init error: %d
",24 __func__, err);25 fs_kobj = kobject_create_and_add("fs", NULL);26 if (!fs_kobj)27 printk(KERN_WARNING "%s: kobj create error
", __func__);28 init_rootfs();29 init_mount_tree();30}第6行命明空间信号量的初始化第8行分配空间第11行挂载点哈希表分配空间第18行初始化所有的挂载点哈希表。第25行生成名为fs的kobject对象。第28行初始化rootfs文件系统第29行初始化mount树第一部分 rootfs文件系统的注册01int __init init_rootfs(void)02{03 int err;0405 err = bdi_init(&ramfs_backing_dev_info);06 if (err)07 return err;0809 err = register_filesystem(&rootfs_fs_type);10 if (err)11 bdi_destroy(&ramfs_backing_dev_info);1213 return err;14}第5行初始化第9行注册rootfs文件系统1static struct file_system_type rootfs_fs_type = {2 .name = "rootfs",3 .get_sb = rootfs_get_sb,4 .kill_sb = kill_litter_super,5};第二部分挂载rootfs文件和创建根目录01static void __init init_mount_tree(void)02{03 struct vfsmount *mnt;04 struct mnt_namespace *ns;05 struct path root;0607 mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);08 if (IS_ERR(mnt))09 panic("Can"t create rootfs");10 ns = kmalloc(sizeof(*ns), GFP_KERNEL);11 if (!ns)12 panic("Can"t allocate initial namespace");13 atomic_set(&ns->count, 1);14 INIT_LIST_HEAD(&ns->list);15 init_waitqueue_head(&ns->poll);16 ns->event = 0;17 list_add(&mnt->mnt_list, &ns->list);18 ns->root = mnt;19 mnt->mnt_ns = ns;2021 init_task.nsproxy->mnt_ns = ns;22 get_mnt_ns(ns);2324 root.mnt = ns->root;25 root.dentry = ns->root->mnt_root;26 set_fs_pwd(current->fs, &root);27 set_fs_root(current->fs, &root);28}这个函数的主要作用是是生成/目录的。第3行定义一个挂载点第4行定义一个命名空间第5行定义一个根路径第7行挂载rootfs文件系统,返回挂载点第10行为命名空间分配空间第13行设定命名空间的引用数为1第14行初始化命名空间链表第15行初始化等待对列第18行命名空间的根结点指向挂载点第19行挂载点指向命名空间第21行第一个进程的命名空间第向刚才初始化的。第24行路径的挂载点为命名空间的根结点第25行路径的目录为命名空间所指向的挂载点的根目录第26行设置/目录为当前的目录第27行设置/目录为根目录01struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data)02{03 struct file_system_type *type = get_fs_type(fstype);04 struct vfsmount *mnt;0506 if (!type)07 return ERR_PTR(-ENODEV);08 mnt = vfs_kern_mount(type, flags, name, data);0910 if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&11 !mnt->mnt_sb->s_subtype)12 mnt = fs_set_subtype(mnt, fstype);13 put_filesystem(type);14 return mnt;15}do_kern_mount的参数介绍fstype 要安装的文件系统的类型名flag 安装的标志name 存放文件系统的块设备的路径名data 指向传递给文件系统中read_super方法的附加指针第3行得到文件系统的类型,这里是rootfs,当然也会有其它的文件系统,比如proc,pipefs等第8行返回挂载点第13行增加对文件系统的引用01struct vfsmount *02vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)03{04 struct vfsmount *mnt;05 char *secdata = NULL;06 int error;0708 if (!type)09 return ERR_PTR(-ENODEV);1011 error = -ENOMEM;12 mnt = alloc_vfsmnt(name);13 if (!mnt)14 goto out;1516 if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {17 secdata = alloc_secdata();18 if (!secdata)19 goto out_mnt;2021 error = security_sb_copy_data(data, secdata);22 if (error)23 goto out_free_secdata;24 }2526 error = type->get_sb(type, flags, name, data, mnt);27 if (error < 0)28 goto out_free_secdata;29 BUG_ON(!mnt->mnt_sb);3031 error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);32 if (error)33 goto out_sb;3435 mnt->mnt_mountpoint = mnt->mnt_root;36 mnt->mnt_parent = mnt;37 up_write(&mnt->mnt_sb->s_umount);38 free_secdata(secdata);39 return mnt;40out_sb:41 dput(mnt->mnt_root);42 deactivate_locked_super(mnt->mnt_sb);43out_free_secdata:44 free_secdata(secdata);45out_mnt:46 free_vfsmnt(mnt);47out:48 return ERR_PTR(error);49}第4行定义挂载点第12行分配一个新的已安装文件系统的描述符,存放在局部变量mnt中第26行调用文件系统get_sb回调函数,这里是rootfs_get_sb,来初始化一个新的超级块,同时会创建/目录.后面会单独介绍第35行挂载点根目录指向与文件系统根目录对应的目录项对象的地址第36行挂载点父目录指向自己第39行返回局部变量mnt
Linux VFS数据结构secureCRT连不上虚拟机解决方案相关资讯 Linux知识
- 时光总是太匆匆!Linux已经诞生23 (08/29/2014 14:12:03)
- Linux虚拟文件系统之文件打开(sys (02/14/2012 11:41:54)
- 2012 年 Linux 峰会时间表 (02/14/2012 06:47:27)
| - 报告称当前 Linux 人才抢手 高薪也 (02/15/2012 06:35:56)
- 解析企业为何选择Linux及其特别之 (02/14/2012 08:17:59)
- Linux禁用字符闪烁的方法 (11/02/2011 10:28:25)
|
本文评论 查看全部评论 (0)