赞
踩
前言:
本篇文章以S3C6410公版的Linux BSP和U-Boot来进行分析,文中所有提及的名词和数据都是以该环境为例,所有的代码流程也是以该环境为例来进行分析。哈哈。如果有不正确或者不完善的地方,欢迎前来拍砖留言或者发邮件到guopeixin@126.com进行讨论,先行谢过。
简单的来说,根文件系统包括虚拟根文件系统和真实根文件系统。在Kernel启动的初始阶段,首先去创建虚拟的根文件系统,接下来再去调用do_mount来加载真正的文件系统,并将根文件系统切换到真正的文件系统,也即真实的文件系统。
在传统的Windows机器上目录结构中,可能会包括C:或者D:盘,而他们一般就称之为特定逻辑磁盘的根目录。从文件系统的层面来说,每一个分区都包含了一个根目录区,也即系统中存在多个根目录。
但是,在Linux系统中,目录结构与Windows上有较大的不同。系统中只有一个根目录,路径是“/”,而其它的分区只是挂载在根目录中的一个文件夹,如“/proc”和“system”等,这里的“/”就是Linux中的根目录。
对应根目录也就存在一个根目录文件系统的概念,我们可以将某一个分区挂载为根目录文件系统,如6410公版中就将mtdblk2挂载为根目录文件系统。程序中可以通过U-Boot给Kernel指定参数或者编译选项来指定,如目前的开发板中就通过如下的编译选项来制定根目录文件系统:
CONFIG_CMDLINE="console=ttyS0,115200 mem=108M rdinit=/linuxrc root=/dev/mtdblock2" |
简单的来说,根目录文件系统就是一种目录结构,包括了Linux启动的时候所必须的一些目录结构和重要文件。
根文件系统有两种,一种是虚拟根文件系统,另外一种是真实的根文件系统。一般情况下,会首先在虚拟的根文件系统中做一部分工作,然后切换到真实的根文件系统下面。
笼统的来说,虚拟的根文件系统包括三种类型,即Initramfs、cpio-initrd和image-initrd。
Initrd是在Linux中普遍采用的一种技术,就是由Bootloader加载的内存盘。在系统启动的过程中,首先会执行Initrd中的“某一个文件” 来完成驱动模块加载的任务,第二阶段才会执行真正的根文件系统中的/sbin/init。这里提到的第一阶段是为第二阶段服务的,主要是用来加载根文件系统以及根文件系统存储介质的驱动程序。
资料中提到,存在多种类型的Initrd,实际应用中包括无Initrd、Linux Kernel和Initrd打包、Linux Kernel和Initrd分离以及RAMDisk Initrd。
目前,手中项目采用的就是第四种策略。在系统启动的时候,U-Boot会将Linux Kernel和Rootfs加载到内存,并跳转到Linux Kernel的入口地址执行程序。这篇文章将侧重对该种情况进行分析。
首先不得不从老掉牙的Linux系统的函数start_kernel()说起。函数start_kernel()中会去调用vfs_caches_init()来初始化VFS。
下面看一下函数vfs_caches_init ()的代码:
void __init vfs_caches_init(unsigned long mempages) { unsigned long reserve; /* Base hash sizes on available memory, with a reserve equal to 150% of current kernel size */ reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1); mempages -= reserve; names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); dcache_init(); inode_init(); files_init(mempages); [1] mnt_init(); bdev_cache_init(); chrdev_init(); } |
代码【1】:vfs_caches_init()中最重要的函数。函数mnt_init()会创建一个rootfs,这是个虚拟的rootfs,即内存文件系统,后面还会指向真实的文件系统。
接下来看一下函数mnt_init():
Void __init mnt_init(void) { unsigned u; int err; init_rwsem(&namespace_sem); mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); if (!mount_hashtable) panic("Failed to allocate mount hash table/n"); printk("Mount-cache hash table entries: %lu/n", HASH_SIZE); for (u = 0; u < HASH_SIZE; u++) INIT_LIST_HEAD(&mount_hashtable[u]); 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__); [1] init_rootfs(); [2] init_mount_tree(); } |
代码[1]:创建虚拟根文件系统;
代码[2]:注册根文件系统。
接下来看一下函数init_mount_tree()的代码:
static void __init init_mount_tree(void) { struct vfsmount *mnt; struct mnt_namespace *ns; struct path root; [1] mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); if (IS_ERR(mnt)) panic("Can't create rootfs"); ns = kmalloc(sizeof(*ns), GFP_KERNEL); if (!ns) panic("Can't allocate initial namespace"); atomic_set(&ns->count, 1); INIT_LIST_HEAD(&ns->list); init_waitqueue_head(&ns->poll); ns->event = 0; list_add(&mnt->mnt_list, &ns->list); ns->root = mnt; mnt->mnt_ns = ns; init_task.nsproxy->m |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。