If you are in the Linux embedded system world, you may have noticed in the mount-table, the presence of this /dev/root device backing the root file system.
In desktop distribution the /dev/root presence is by far less frequent, but in some unusual environment, you might find this either, and when it is there, it is frequent to find it as a symbolic link to a real block device.
On the other hands, in embedded system it is not unusual to have an even more weird situation:
Having /dev/root mounted and not have anything at the /dev/root position (no file named root in the /dev directory).
How is this possible?
Under the hood
The next step is calling mount_root()
void __init prepare_namespace(void)
{
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(5);
async_synchronize_full();
}
mount_root();
out:
devtmpfs_mount();
init_mount(".", "/", NULL, MS_MOVE, NULL);
init_chroot(".");
}
The function checks if a device is passed through the command line ("saved_root_name" is set to the boot command line "root="), if not, tries the initramfs way. In the end, if ROOT_DEV that is the rootfs device is null, and no rootwait is specified it invokates the mount_root().
The next step is calling mount_root()
void __init mount_root(void)
{
#ifdef CONFIG_ROOT_NFS
if (ROOT_DEV == Root_NFS) {
if (!mount_nfs_root())
printk(KERN_ERR "VFS: Unable to mount root fs via NFS.\n");
return;
}
#endif
#ifdef CONFIG_CIFS_ROOT
if (ROOT_DEV == Root_CIFS) {
if (!mount_cifs_root())
printk(KERN_ERR "VFS: Unable to mount root fs via SMB.\n");
return;
}
#endif
if (ROOT_DEV == 0 && root_device_name && root_fs_names) {
if (mount_nodev_root() == 0)
return;
}
#ifdef CONFIG_BLOCK
{
int err = create_dev("/dev/root", ROOT_DEV);
if (err < 0)
pr_emerg("Failed to create /dev/root: %d\n", err);
mount_block_root("/dev/root", root_mountflags);
}
#endif
}
In this function, a certain number of #ifcfg are visible. Apparently, the rootfs can exist if all these switches are off. In this case, the rootfs is mounted by using its name root_device_name and its fstype root_device_name. In the vast majority of cases, when the rootfs is backed by a block device, the ROOT_DEV has already a value and the CONFIG_BLOCK part of the code is executed.
Here a couple of points are visible:
The kernel creates the /dev/root device
After that, it mounts the rootfs
But if the device is not yet mounted, where is this /dev/root actually created?
The answer is that the kernel had a special instance of the ramfs called rootfs mounted on the / at the time it created the /dev/root, and therefore, when the new filesystem is mounted over the / directory, unless it already contains the device, /dev/root is simply not present.
Considering that tempfs is typically mounted over the /dev directory, init scripts need to make sure that the /dev/root exists.
If none creates it, the system has the proc/mountinfo table populated with the /dev/root device, but it is not backed by any file in the /dev directory.
I have one problem. /dev/root creation failing with -2. what is missing?
ReplyDelete