linux根文件系统的挂载过程详解 linux文件挂载是什么意思( 二 )


跟根文件系统相关的初始化函数都会由rootfs_initcall()所引用 。注意到有以下初始化函数:
rootfs_initcall(populate_rootfs);
也就是说会在系统初始化的时候会调用populate_rootfs进行初始化 。代码如下:
static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start,
__initramfs_end - __initramfs_start, 0);
if (err)
panic(err);
if (initrd_start) {
#ifdef CONFIG_BLK_DEV_RAM
int fd;
printk(KERN_INFO "checking if image is initramfs...");
err = unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 1);
if (!err) {
printk(" it isn");
unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 0);
free_initrd();
return 0;
}
printk("it isn't (%s); looks like an initrdn", err);
fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
if (fd >= 0) {
sys_write(fd, (char *)initrd_start,
initrd_end - initrd_start);
sys_close(fd);
free_initrd();
}
#else
printk(KERN_INFO "Unpacking initramfs...");
【linux根文件系统的挂载过程详解 linux文件挂载是什么意思】err = unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 0);
if (err)
panic(err);
printk(" donen");
free_initrd();
#endif
}
return 0;
}
unpack_to_rootfs:顾名思义就是解压包,并将其释放至rootfs 。它实际上有两个功能 , 一个是释放包,一个是查看包 , 看其是否属于cpio结构的包 。功能选择是根据最后的一个参数来区分的.
在这个函数里,对应我们之前分析的三种虚拟根文件系统的情况 。一种是跟kernel融为一体的initramfs.在编译kernel的时候,通过链接脚本将其存放在__initramfs_start至__initramfs_end的区域 。这种情况下,直接调用unpack_to_rootfs将其释放到根目录.如果不是属于这种形式的 。也就是__initramfs_start和__initramfs_end的值相等 , 长度为零 。不会做任何处理 。退出.
对应后两种情况 。从代码中看到,必须要配制CONFIG_BLK_DEV_RAM才会支持image-initrd 。否则全当成cpio-initrd的形式处理 。
对于是cpio-initrd的情况 。直接将其释放到根目录 。对于是image-initrd的情况 。将其释放到/initrd.image.最后将initrd内存区域归入伙伴系统 。这段内存就可以由操作系统来做其它的用途了 。
接下来,内核对这几种情况又是怎么处理的呢?不要着急 。往下看:
回到kernel_init()这个函数:
static int __init kernel_init(void * unused)
{
…….
…….
do_basic_setup();
/*
* check if there is an early userspace init. If yes, let it do all
* the work
*/
if (!ramdisk_execute_command)
ramdisk_execute_command = "/init";
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
}
/*
* Ok, we have completed the initial bootup, and
* we're essentially up and running. Get rid of the
* initmem segments and start the user-mode stuff..
*/
init_post();
return 0;
}
ramdisk_execute_command:在kernel解析引导参数的时候使用 。如果用户指定了init文件路径,即使用了“init=”,就会将这个参数值存放到这里 。
如果没有指定init文件路径 。默认为/init
对应于前面一段的分析,我们知道,对于initramdisk和cpio-initrd的情况,都会将虚拟根文件系统释放到根目录 。如果这些虚拟文件系统里有/init这个文件 。就会转入到init_post() 。
Init_post()代码如下:
static int noinline init_post(void)
{
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0)
(void) sys_dup(0);
(void) sys_dup(0);
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %sn",
ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...n", execute_command);
}
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");

推荐阅读