第一:前言



以前的时候,当编译内核,发现就没有安装。同一根选项设置图像的旧版本可用。为了彻底解决这一问题,研究了根文件系统加载过程。特殊总结如下。我希望能对这部分知识有所帮助。



二:的rootfs的类型



总的来说,可以分为两种:虚拟文件系统和实际文件系统,现在的趋势是把更多的内核函数在用户空间,保持内核的精简。虚拟rootfs也是Linux分销商的一种常用方法,初始化工作的一部分,可以在一个虚拟的文件系统,然后切换到真正的文件系统。



在虚拟文件系统的发展过程中,也有以下版本:



Initramfs:



Initramfs介绍了2.5内核,实际上它的意思是:在内核映像添加cpio包,cpio包包括一个小的文件系统,在内核启动时,内核将解开cpio包,其中包括文件系统内核文件系统中的文件系统的初始化代码的一部分释放,作为一个用户级进程来执行。这种显而易见的好处是精简内核的初始化代码,使内核初始化容易定制。这样就包含在内核映像。



在cpio initrd rootfs:cpio格式



在图像的initrd rootfs传统格式:



对于这两个虚拟文件系统的生产,请参考其他信息。



三:的rootfs文件系统挂载过程



这里就不同,可以分析以上。这指的是系统初始化的根节点,该节点。它的rootfs文件系统在内存中,这部分已经在>分析和文件系统。再说了对于知识的连续性。



start_kernel --à;mnt_init()():



__init mnt_init虚空(void)



{



hellip;hellip;



hellip;hellip;



init_rootfs();



init_mount_tree();



}



对init_rootfs代码如下:



国际__init init_rootfs(void)



{



int错误;



错误=bdi_init(ramfs_backing_dev_info);



如果(错误)



返回ERR;



错误=register_filesystem(rootfs_fs_type);



如果(错误)



bdi_destroy(ramfs_backing_dev_info);



返回ERR;



}



这个功能很简单,它是一个文件系统注册文件系统。



init_mount_tree()的代码如下:



静态__init init_mount_tree(void)



{



结构安装点* MNT;



结构mnt_namespace * NS;



路径根结构;



MNT = do_kern_mount(rootfs



如果(is_err(MNT))



恐慌(无法创建文件系统);



NS = kmalloc(sizeof(NS),gfp_kernel);



如果(!NS)



恐慌(无法分配初始命名空间);



atomic_set(NS ->计数,1);



init_list_head(NS ->列表);



init_waitqueue_head(NS ->调查);



ns =事件= 0;



list_add(MNT -> mnt_list,NS ->列表);



NS—>根= MNT;



MNT -> mnt_ns = NS;



init_task。子类化代理-> mnt_ns = NS;



get_mnt_ns(NS);



root.mnt = NS ->根;



root.dentry = NS—>根> mnt_root;



set_fs_pwd(电流-> FS,根);



set_fs_root(电流-> FS,根);



}



在这里,rootfs文件系统挂载,挂载点默认和的最终切换过程的根目录和当前目录和这是根目录的起源。但它只是初始化。安装一个特定的文件系统的根目录后,一般切换到一个特定的文件系统,在系统启动时,mount命令不能看到rootfs的安装信息。



四:挂载虚拟文件系统



根目录已挂起,可以安装特定的文件系统。



在start_kernel()()()严重;rest_init --à;kernel_init():



静态变量__init kernel_init(void *未使用)



{



hellip;hellip;



hellip;hellip;



do_basic_setup();



如果(!ramdisk_execute_command)



ramdisk_execute_command = /初始化;



如果sys_access((((const char * ramdisk_execute_command __user),0)!= 0){



ramdisk_execute_command = null;



prepare_namespace();



}



*



好啦,我们已经完成了初步的启动,和



*我们基本上开始运行。摆脱



* initmem段和启动用户模式的东西。



* /



init_post();



返回0;



}



do_basic_setup()是一个关键的功能,所有的模块,直接编译进内核是由它的代码片段如下:



静态__init do_basic_setup(void)



{



司机会送热插拔事件* / / *



init_workqueues();



usermodehelper_init();



driver_init();



init_irq_proc();



do_initcalls();



}



do_initcalls()是用来在__initcall_start和__initcall_end段开始的所有功能,而静态模块编译进内核还将其作品在这个区间。



与根文件系统相关的初始化函数引用的rootfs_initcall()。注意,有以下的初始化函数:



rootfs_initcall(populate_rootfs);



也就是说,该populate_rootfs将被初始化时,系统初始化,代码如下:



静态变量__init populate_rootfs(void)



{



char *的意思unpack_to_rootfs(__initramfs_start,



__initramfs_end - __initramfs_start,0);



如果(错误)



恐慌(错误);



如果(initrd_start){



# ifdef config_blk_dev_ram



int fd;



printk(kern_info 检查如果图像是initramfs…);



错误=unpack_to_rootfs((char *)initrd_start,



initrd_end - initrd_start,1);



如果(!ERR){



printk(是);



unpack_to_rootfs((char *)initrd_start,



initrd_end - initrd_start,0);



free_initrd();



返回0;



}



printk(不是(%s);看起来像一个initrdn



FD = sys_open( / initrd。图像



如果(FD = 0){



sys_write(FD,(char *)initrd_start,



initrd_end - initrd_start);



sys_close(FD);



free_initrd();



}



其他#



printk(kern_info开箱initramfs…);



错误=unpack_to_rootfs((char *)initrd_start,



initrd_end - initrd_start,0);



如果(错误)



恐慌(错误);



printk(但);



free_initrd();



# endif



}



返回0;



}



unpack_to_rootfs:顾名思义,它是打开包装并释放到rootfs。它实际上有两个功能,一是发布包,另一个是查看包装是否属于cpio结构封装。函数的选择是基于最后一个参数。



在这个函数中,它对应于虚拟的三根文件系统之前所分析的案例,一个是initramfs。这是与内核集成的。当编译内核,它存储在地区__initramfs_start到__initramfs_end通过链接脚本。在这种情况下,该unpack_to_rootfs直接调用它释放到根目录。如果它不在这个形式,对__initramfs_start和__initramfs_end值相等,而长度是零。不做任何处理。签出。



对应于以下两种情况。正如你所看到的代码,你必须config_blk_dev_ram支持image-initrd.otherwise,它在cpio initrd的形式处理。



为cpio-initrd.release它的情况下直接到根目录,它的image-initrd.release案例/ initrd.image。并最终回归initrd内存区域伙伴系统。该存储器可以通过为其他目的使用的操作系统。



接下来,内核并不担心如何处理这些条件:



回到kernel_init()函数:



静态变量__init kernel_init(void *未使用)



{



hellip;hellip;。



hellip;hellip;。



do_basic_setup();



*



*检查是否有早期用户空间的初始化。如果是,就让它



*工作



* /



如果(!ramdisk_execute_command)



ramdisk_execute_command = /初始化;



如果sys_access((((const char * ramdisk_execute_command __user),0)!= 0){



ramdisk_execute_command = null;



prepare_namespace();



}



U3000 U3000