您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > Linux--根文件系统的挂载过程分析
Linux--根文件系统的挂载过程分析分类:LinuxDriver2010-10-2417:5711567人阅读评论(16)收藏举报commandlinuxnullthreaddelay代码分析目录(?)[+]前言:本篇文章以S3C6410公版的LinuxBSP和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,115200mem=108Mrdinit=/linuxrcroot=/dev/mtdblock2简单的来说,根目录文件系统就是一种目录结构,包括了Linux启动的时候所必须的一些目录结构和重要文件。根文件系统有两种,一种是虚拟根文件系统,另外一种是真实的根文件系统。一般情况下,会首先在虚拟的根文件系统中做一部分工作,然后切换到真实的根文件系统下面。笼统的来说,虚拟的根文件系统包括三种类型,即Initramfs、cpio-initrd和image-initrd。二.相关重要概念1.InitrdInitrd是在Linux中普遍采用的一种技术,就是由Bootloader加载的内存盘。在系统启动的过程中,首先会执行Initrd中的“某一个文件”来完成驱动模块加载的任务,第二阶段才会执行真正的根文件系统中的/sbin/init。这里提到的第一阶段是为第二阶段服务的,主要是用来加载根文件系统以及根文件系统存储介质的驱动程序。资料中提到,存在多种类型的Initrd,实际应用中包括无Initrd、LinuxKernel和Initrd打包、LinuxKernel和Initrd分离以及RAMDiskInitrd。目前,手中项目采用的就是第四种策略。在系统启动的时候,U-Boot会将LinuxKernel和Rootfs加载到内存,并跳转到LinuxKernel的入口地址执行程序。这篇文章将侧重对该种情况进行分析。三.根文件系统加载代码分析1.VFS的注册首先不得不从老掉牙的Linux系统的函数start_kernel()说起。函数start_kernel()中会去调用vfs_caches_init()来初始化VFS。下面看一下函数vfs_caches_init()的代码:void__initvfs_caches_init(unsignedlongmempages){unsignedlongreserve;/*Basehashsizesonavailablememory,withareserveequalto150%ofcurrentkernelsize*/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__initmnt_init(void){unsignedu;interr;init_rwsem(&namespace_sem);mnt_cache=kmem_cache_create(mnt_cache,sizeof(structvfsmount),0,SLAB_HWCACHE_ALIGN|SLAB_PANIC,NULL);mount_hashtable=(structlist_head*)__get_free_page(GFP_ATOMIC);if(!mount_hashtable)panic(Failedtoallocatemounthashtable/n);printk(Mount-cachehashtableentries:%lu/n,HASH_SIZE);for(u=0;uHASH_SIZE;u++)INIT_LIST_HEAD(&mount_hashtable[u]);err=sysfs_init();if(err)printk(KERN_WARNING%s:sysfs_initerror:%d/n,__func__,err);fs_kobj=kobject_create_and_add(fs,NULL);if(!fs_kobj)printk(KERN_WARNING%s:kobjcreateerror/n,__func__);[1]init_rootfs();[2]init_mount_tree();}代码[1]:创建虚拟根文件系统;代码[2]:注册根文件系统。接下来看一下函数init_mount_tree()的代码:staticvoid__initinit_mount_tree(void){structvfsmount*mnt;structmnt_namespace*ns;structpathroot;[1]mnt=do_kern_mount(rootfs,0,rootfs,NULL);if(IS_ERR(mnt))panic(Can'tcreaterootfs);ns=kmalloc(sizeof(*ns),GFP_KERNEL);if(!ns)panic(Can'tallocateinitialnamespace);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-mnt_ns=ns;get_mnt_ns(ns);root.mnt=ns-root;root.dentry=ns-root-mnt_root;set_fs_pwd(current-fs,&root);[2]set_fs_root(current-fs,&root);}代码[1]:创建虚拟文件系统;代码[2]:将当前的文件系统配置为根文件系统。可能有人会问,为什么不直接把真实的文件系统配置为根文件系统?答案很简单,内核中没有根文件系统的设备驱动,如USB等存放根文件系统的设备驱动,而且即便你将根文件系统的设备驱动编译到内核中,此时它们还尚未加载,其实所有的Driver是由在后面的Kernel_Init线程进行加载。所以需要CPIOInitrd、Initrd和RAMDiskInitrd。另外,我们的Root设备都是以设备文件的方式指定的,如果没有根文件系统,设备文件怎么可能存在呢?2.VFS的挂载接下来,Kernel_Start会去调用rest_init()并会去创建系统中的第一个进程Kernel_Init,并由其调用所有模块的初始化函数,其中ROOTFS的初始化函数也在这个期间被调用。函数rest_init代码如下:/**Weneedtofinalizeinanon-__initfunctionorelseraceconditions*betweentherootthreadandtheinitthreadmaycausestart_kernelto*bereapedbyfree_initmembeforetherootthreadhasproceededto*cpu_idle.**gcc-3.4accidentallyinlinesthisfunction,sousenoinline.*/staticnoinlinevoid__init_refokrest_init(void)__releases(kernel_lock){intpid;kernel_thread(kernel_init,NULL,CLONE_FS|CLONE_SIGHAND);numa_default_policy();pid=kernel_thread(kthreadd,NULL,CLONE_FS|CLONE_FILES);kthreadd_task=find_task_by_pid_ns(pid,&init_pid_ns);unlock_kernel();/**Thebootidlethreadmustexecuteschedule()*atleastoncetogetthingsmoving:*/init_idle_bootup_task(current);rcu_scheduler_starting();preempt_enable_no_resched();schedule();preempt_disable();/*Callintocpu_idlewithpreemptdisabled*/cpu_idle();}函数Kernel_Init代码如下:staticint__initkernel_init(void*unused){lock_kernel();/**initcanrunonanycpu.*/set_cpus_allowed_ptr(current,CPU_MASK_ALL_PTR);/**Telltheworldthatwe'regoingtobethegrim*reaperofinnocentorphanedchildren.**Wedon'twantpeopletohavetomakeincorrect*assumptionsaboutwhereinthetaskarraythis*canbefound.*/init_pid_ns.child_reaper=current;cad_pid=task_pid(current);smp_prepare_cpus(setup_max_cpus);do_pre_smp_initcalls();start_boot_trace();smp_init();sched_init_smp();cpuset_init_smp();[1]do_basic_setup();/**checkifthereisanearlyuserspaceinit.Ifyes,letitdoall*thework*/[2]if(!ramdisk_execute_command)ramdisk_execute_comma
本文标题:Linux--根文件系统的挂载过程分析
链接地址:https://www.777doc.com/doc-6073951 .html