/*
* 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 (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING
"Failed to execute %s/n",
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");
if (root_delay) {
printk(KERN_INFO
"Waiting %dsec before mounting root device.../n",
root_delay);
ssleep(root_delay);
}
/* wait for the known devices to
complete their probing */
while (driver_probe_done() != 0)
msleep(100);
//mtd的处理
md_run_setup();
if (saved_root_name[0]) {
root_device_name =
saved_root_name;
if
(!strncmp(root_device_name, "mtd", 3)) {
mount_block_root(root_device_name,
root_mountflags);
goto out;
}
ROOT_DEV =
name_to_dev_t(root_device_name);
if (strncmp(root_device_name,
"/dev/", 5) == 0)
root_device_name +=
5;
}
if (initrd_load())
goto out;
/* wait for any asynchronous scanning
to complete */
if ((ROOT_DEV == 0) &&
root_wait) {
printk(KERN_INFO
"Waiting for root device %s.../n",
saved_root_name);
while (driver_probe_done() !=
0 ||
(ROOT_DEV =
name_to_dev_t(saved_root_name)) == 0)
msleep(100);
}
is_floppy = MAJOR(ROOT_DEV) ==
FLOPPY_MAJOR;
if (is_floppy && rd_doload
&& rd_load_disk(0))
ROOT_DEV = Root_RAM0;
mount_root();
out:
sys_mount(".", "/",
NULL, MS_MOVE, NULL);
sys_chroot(".");
}
这里有几个比较有意思的处理,首先用户可以用root=来指定根文件系统。它的值保存在saved_root_name中。如果用户指定了以mtd开始的字串做为它的根文件系统。就会直接去挂载。这个文件是mtdblock的设备文件。
否则将设备结点文件转换为ROOT_DEV即设备节点号
然后,转向initrd_load()执行initrd预处理后,再将具体的根文件系统挂载。
注意到,在这个函数末尾。会调用sys_mount()来移动当前文件系统挂载点到”/”目录下。然后将根目录切换到当前目录。这样,根文件系统的挂载点就成为了我们在用户空间所看到的”/”了.
对于其它根文件系统的情况,会先经过initrd的处理。即
int
__init initrd_load(void)
{
if (mount_initrd) {
create_dev("/dev/ram",
Root_RAM0);
/*
* Load the initrd data into /dev/ram0. Execute
it as initrd
* unless /dev/ram0 is supposed to be our
actual root device,
* in that case the ram disk is just set up
here, and gets
* mounted in the normal path.
*/
if (rd_load_image("/initrd.image")
&& ROOT_DEV != Root_RAM0) {
sys_unlink("/initrd.image");
handle_initrd();
return 1;
}
}
sys_unlink("/initrd.image");
return 0;
}
建立一个ROOT_RAM)的设备节点,并将/initrd/.image释放到这个节点中,/initrd.image的内容,就是我们之前分析的image-initrd。
如果根文件设备号不是ROOT_RAM0( 用户指定的根文件系统不是/dev/ram0就会转入到handle_initrd()
如果当前根文件系统是/dev/ram0.将其直接挂载就好了。
handle_initrd()代码如下:
static
void __init handle_initrd(void)
{
int error;
int pid;
real_root_dev =
new_encode_dev(ROOT_DEV);
create_dev("/dev/root.old", Root_RAM0);
/* mount initrd
on rootfs/" /root */
mount_block_root("/dev/root.old",
root_mountflags & ~MS_RDONLY);
sys_mkdir("/old", 0700);
root_fd = sys_open("/", 0,
0);
old_fd = sys_open("/old", 0,
0);
/* move initrd over / and chdir/chroot
in initrd root */
sys_chdir("/root");
sys_mount(".", "/",
NULL, MS_MOVE, NULL);
sys_chroot(".");
/*
* In case that a resume from disk is carried
out by linuxrc or one of
* its children, we need to tell the freezer
not to wait for us.
*/
current->flags |= PF_FREEZER_SKIP;
pid = kernel_thread(do_linuxrc,
"/linuxrc", SIGCHLD);
if (pid > 0)
while (pid != sys_wait4(-1,
NULL, 0, NULL))
yield();
current->flags &=
~PF_FREEZER_SKIP;
/* move initrd to rootfs/" /old */
sys_fchdir(old_fd);
sys_mount("/", ".",
NULL, MS_MOVE, NULL);
/* switch root and cwd back to / of
rootfs */
sys_fchdir(root_fd);
sys_chroot(".");
sys_close(old_fd);
sys_close(root_fd);
if (new_decode_dev(real_root_dev) ==
Root_RAM0) {
sys_chdir("/old");
return;
}