how initrd is mounted by linux kernel

Post Free Ads for Agri, Solar, Eco products

Lets first try to understand what are the ways to mount the root file system, Altough the documentation from Documentation/early-userspace/README inside kernel source code is bit outdated, it is still has valid information as below,

The kernel has currently 3 ways to mount the root filesystem:

a) all required device and filesystem drivers compiled into the kernel, no initrd. init/main.c:init() will call prepare_namespace() to mount the final root filesystem, based on the root= option and optional init= to run some other init binary than listed at the end of init/main.c:init().

b) some device and filesystem drivers built as modules and stored in an initrd. The initrd must contain a binary ‘/linuxrc’ which is supposed to load these driver modules. It is also possible to mount the final root filesystem via linuxrc and use the pivot_root syscall. The initrd is mounted and executed via prepare_namespace().

c) using initramfs. The call to prepare_namespace() must be skipped.
This means that a binary must do all the work. Said binary can be stored into initramfs either via modifying usr/gen_init_cpio.c or via the new initrd format, an cpio archive. It must be called “/init”. This binary is responsible to do all the things prepare_namespace() would do.

To maintain backwards compatibility, the /init binary will only run if it comes via an initramfs cpio archive. If this is not the case,
init/main.c:init() will run prepare_namespace() to mount the final root and exec one of the predefined init binaries.

Now, lets check the code from kernel init/main.c file,

static char *ramdisk_execute_command;

static int __init rdinit_setup(char *str)
{
unsigned int i;

ramdisk_execute_command = str;
/* See “auto” comment in init_setup */
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup(“rdinit=”, rdinit_setup);

static int __ref kernel_init(void *unused)
{

if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err(“Failed to execute %s (error %d)\n”,
ramdisk_execute_command, ret);
}

SHUFFLED :   Preparing ubuntu for gstreamer development

}

static noinline void __init kernel_init_freeable(void)
{

/*
* 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();
}

}

The above call from “prapare_namespace” goes to init/do_mounts.c as below,

/*
* 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 %d sec 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;
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);
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);
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(“.”);
}

Now, we will try to understand the first three ways mentioned,

c ) for using initramfs :

The related source code inside kernel is located inside usr/ directory and in file gen_init_cpio.c , refer source for more details. Once you compile the kernel, you will get the gen_init_cpio binary compiled for the host, which you can use with input file file_list which may contain details of device nodes, directories etc.

Android Android Commands Android Java Applications Application Libraries Bash / Shell Scripts Bluetooth driver Build Frameworks Commands and Packages Core Kernel C Programs Development Environment Setup Documents / Books Errors & Failures File Systems Framebuffer / Display Driver git Go Language Programs Hardware Platforms Home JAVA Programs Kernel & Device Drivers Kernel Booting and Porting Linux, OS Concepts and Networking Linux Device Drivers Linux Host, Ubuntu, SysAdmin Linux Kernel Linux Networking Middleware Libraries, HAL NDK / Middleware / HAL Network Driver OS Concepts PHP Procfs Filesystem Programming Languages RaspberryPi Scripting and Automation Search Engine Optimisation ( SEO ) Socurce Code Management ( SCM ) System Administration, Security Testing and Debugging Uncategorized Userspace Utilities Web design and development Wordpress Yocto / Bitbake / Openembedded

Leave a Reply