linux挂载跟文件系统,一般通过ramdisk方式。如果没有使用ramdisk方式,而是使用磁盘上分区文件系统,那么在prepare_namespace中进行。
static noinline void __init kernel_init_freeable(void)
{
/*
* Wait until kthreadd is all set-up.
*/
wait_for_completion(&kthreadd_done);
/* Now the scheduler is fully set up and can do blocking allocations */
gfp_allowed_mask = __GFP_BITS_MASK;
/*
* init can allocate pages on any node
*/
set_mems_allowed(node_states[N_MEMORY]);
/*
* init can run on any cpu.
*/
set_cpus_allowed_ptr(current, cpu_all_mask);
cad_pid = task_pid(current);
smp_prepare_cpus(setup_max_cpus);
do_pre_smp_initcalls();
lockup_detector_init();
smp_init();
sched_init_smp();
do_basic_setup();
/* Open the /dev/console on the rootfs, this should never fail */
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
pr_err("Warning: unable to open an initial console.\n");
(void) sys_dup(0);
(void) sys_dup(0);
/*
* check if there is an early userspace init. If yes, let it do all
* the work
*/
if (!ramdisk_execute_command) //启动参数bootargs中没有指定init进程,那么采用默认的/init
ramdisk_execute_command = "/init";
//搜索当前系统中是否有/init,如果前面已经挂载了ramdisk,就会存在/init
//ramdisk由uboot搬移到内存中,并传递给kernel,所以ramdisk可以很早就进行加载
//当实际物理设备上的根分区需要 驱动都初始化好后才能加载,所以这里是等待驱动加载完成后,才prepare_namespace挂载文件系统
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..
*/
/* rootfs is available now, try loading default modules */
load_default_modules();
}
比如bootargs中 参数: root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait
表示跟分区在mmcblk0p2 ,文件系统类型为ext4,挂载点为/dev/root(默认)
由于前面设备驱动已经加载好,所以能够找到mmcblk0p2
static int __init root_dev_setup(char *line)
{
strlcpy(saved_root_name, line, sizeof(saved_root_name));
return 1;
}
__setup("root=", root_dev_setup);
/*
* Prepare the namespace - decide what/where to mount, load ramdisks, etc.
*/
void __init prepare_namespace(void)
{
int is_floppy;
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
*
* Note: this is a potential source of long boot delays.
* For example, it is not atypical to wait 5 seconds here
* for the touchpad of a laptop to initialize.
*/
wait_for_device_probe();
md_run_setup();
if (saved_root_name[0]) {
root_device_name = saved_root_name; //saved_root_name中保存了/dev/mmcblk0p2
if (!strncmp(root_device_name, "mtd", 3) ||
!strncmp(root_device_name, "ubi", 3)) {
mount_block_root(root_device_name, root_mountflags);
goto out;
}
ROOT_DEV = name_to_dev_t(root_device_name); //根据设备名mmcblk0p2 生成设备号 dev_t,主设备号和次设备号
if (strncmp(root_device_name, "/dev/", 5) == 0)
root_device_name += 5; //root_device_name 前移5,由/dev/mmcblk0p2 变为mmcblk0p2
}
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);
async_synchronize_full();
}
is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
if (is_floppy && rd_doload && rd_load_disk(0))
ROOT_DEV = Root_RAM0;
mount_root(); //这里进行挂载
out:
devtmpfs_mount("dev");
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
}
void __init mount_root(void)
{
#ifdef CONFIG_BLOCK
create_dev("/dev/root", ROOT_DEV); //这里利用mksnod创建设备文件/dev/root,对应设备号和mmcblk0p2相同
mount_block_root("/dev/root", root_mountflags);//开始挂载根文件分区,后续会根据/dev/root找到分区mmcblk0p2
#endif
}
后续再讲其它。