Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of Root File system Mount in linux

2025-03-11 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces the example analysis of root file system mount in linux, which is very detailed and has certain reference value. Friends who are interested must finish it!

St1\: * {behavior:url (# ieooui)}

One: preface

Some time ago, when compiling kernel, I found that rootfs could not be mounted. The same root option sets the old version of image, but it works. To solve this problem once and for all. The mount process of rootfs is studied. It is summarized as follows, hoping to give some help to the friends who are confused about this part of the knowledge.

Two: types of rootfs

Generally speaking, there are two kinds of rootfs: virtual rootfs and real rootfs. Now the development trend of kernel is to put more functions into user space. To keep the kernel streamlined. Virtual rootfs is also a common method adopted by all linux publishers. Part of the initialization work can be done in a virtual rootfs. Then switch to the real file system.

In the development of virtual rootfs. There are several more versions:

Initramfs:

Initramfs is a technology introduced in kernel 2.5. in fact, it means: attach a cpio package to the kernel image, this cpio package contains a small file system, when the kernel starts, the kernel unlocks the cpio package and releases the file system into rootfs, and part of the initialization code in the kernel will be placed in this file system and executed as a user-level process. The obvious benefit of this is that it simplifies the initialization code of the kernel and makes the initialization process of the kernel easier to customize. The rootfs in this way is included in the kernel image.

Cpio-initrd: rootfs in cpio format

Image-initrd: rootfs in traditional format

Please refer to other materials about the production of these two virtual file systems.

Third: the mount process of rootfs file system

The rootfs mentioned here is different from the rootfs analyzed above. This refers to the root node when the system is initialized. Namely / node. It is its rootfs file system in memory. This section has been analyzed previously in > and the file system. For the sake of the consistency of knowledge, I repeat it here.

Start_kernel () à mnt_init ():

Void _ init mnt_init (void)

{

……

……

Init_rootfs ()

Init_mount_tree ()

}

The code for Init_rootfs is as follows:

Int _ init init_rootfs (void)

{

Int err

Err = bdi_init (& ramfs_backing_dev_info)

If (err)

Return err

Err = register_filesystem (& rootfs_fs_type)

If (err)

Bdi_destroy & ramfs_backing_dev_info)

Return err

}

This function is very simple. It is the file system that is registered with rootfs.

The init_mount_tree () code is as follows:

Static void _ init init_mount_tree (void)

{

Struct vfsmount * mnt

Struct mnt_namespace * ns

Struct path root

Mnt = do_kern_mount ("rootfs", 0, "rootfs", NULL)

If (IS_ERR (mnt))

Panic ("Can't create rootfs")

Ns = kmalloc (sizeof (* ns), GFP_KERNEL)

If (! ns)

Panic ("Can't allocate initial namespace")

Atomic_set (& ns- > count, 1)

INIT_LIST_HEAD (& ns- > list)

Init_waitqueue_head (& ns- > poll)

Ns- > event = 0

List_add (& mnt- > mnt_list, & ns- > list)

Ns- > root = mnt

Mnt- > mnt_ns = ns

Init_task.nsproxy- > mnt_ns = ns

Get_mnt_ns (ns)

Root.mnt = ns- > root

Root.dentry = ns- > root- > mnt_root

Set_fs_pwd (current- > fs, & root)

Set_fs_root (current- > fs, & root)

}

Here, mount the rootfs file system. Its mount point defaults to "/". Finally, switch the root directory and current directory of the process to "/". This is the origin of the root directory. But this is just initialization. After mounting a specific file system, it is common to change the root directory to the specific file system. Therefore, after the system starts, the mount information of rootfs can not be seen with the mount command.

Four: mounting of virtual file system

The root directory has been mounted, and the specific file system can be mounted.

In start_kernel () à rest_init () à kernel_init ():

Static int _ _ init kernel_init (void * unused)

{

……

……

Do_basic_setup ()

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

}

Do_basic_setup () is a critical function that starts all modules that are compiled directly into kernel. The code snippet is as follows:

Static void _ init do_basic_setup (void)

{

/ * drivers will send hotplug events * /

Init_workqueues ()

Usermodehelper_init ()

Driver_init ()

Init_irq_proc ()

Do_initcalls ()

}

Do_initcalls () is used to start all functions in the _ _ initcall_start and _ _ initcall_end sections, and modules statically compiled into the kernel places its entry in this interval.

All initialization functions related to the root file system are referenced by rootfs_initcall (). Notice the following initialization functions:

Rootfs_initcall (populate_rootfs)

In other words, populate_rootfs will be called for initialization when the system is initialized. The code is as follows:

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 is\ n")

Unpack_to_rootfs ((char *) initrd_start)

Initrd_end-initrd_start, 0)

Free_initrd ()

Return 0

}

Printk ("it isn't (% s); looks like an initrd\ n", 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...")

Err = unpack_to_rootfs ((char *) initrd_start)

Initrd_end-initrd_start, 0)

If (err)

Panic (err)

Printk ("done\ n")

Free_initrd ()

# endif

}

Return 0

}

Unpack_to_rootfs: as the name implies, unpack the package and release it to rootfs. It actually has two functions, one is to release the package, and the other is to check the package to see if it belongs to the cpio structure of the package. Function selection is distinguished according to the last parameter.

In this function, it corresponds to the three virtual root file systems we analyzed earlier. One is initramfs, which is integrated with kernel. When compiling kernel, store it in the area from _ _ initramfs_start to _ _ initramfs_end by linking the script. In this case, call unpack_to_rootfs directly to release it to the root directory. If it doesn't belong to this form. That is, the values of _ _ initramfs_start and _ _ initramfs_end are equal and the length is zero. Won't do anything about it. Quit.

Corresponding to the latter two cases. As you can see from the code, CONFIG_BLK_DEV_RAM must be configured to support image-initrd. Otherwise, it will all be treated as cpio-initrd.

In the case of cpio-initrd. Release it directly to the root directory. In the case of image-initrd. Release it to / initrd.image. Finally, the initrd memory area is classified into the partner system. This memory can be used for other purposes by the operating system.

Next, how does the kernel deal with these situations? Don't worry. Look down:

Go back to the function 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: used when kernel parses boot parameters. If the user specifies the path to the init file, even if "init=" is used, the parameter value will be stored here.

If no init file path is specified. Default is / init

Corresponding to the analysis in the previous paragraph, we know that in the case of both initramdisk and cpio-initrd, the virtual root file system is released to the root directory. If there is a / init file in these virtual file systems. It will be transferred to init_post ().

The Init_post () code is as follows:

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% 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")

Panic ("No init found. Try passing init= option to kernel.")

}

As you can see from the code, the specified init file will be executed in turn. If it fails, / sbin/init, / etc/init, / bin/init,/bin/sh will be executed.

Note that run_init_process uses kernel_execve when calling the corresponding program to run. That is, the calling process replaces the current process. As long as any of the above files are successfully called, it will not be returned to this function. If none of the above files can be executed. Print out the error that the init file was not found.

For cases where / init is not included in the image-hdr or virtual file system, it is handled by prepare_namespace (). The code is as follows:

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 * /

While (driver_probe_done ()! = 0)

Msleep (100)

/ / processing of 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 (.)

}

Here are some interesting processes. First, the user can use root= to specify the root file system. Its value is stored in saved_root_name. If the user specifies a string that starts with mtd as its root file system. It will be mounted directly. This file is the device file for mtdblock.

Otherwise, convert the device node file to ROOT_DEV, that is, the device node number.

Then, go to initrd_load () to perform initrd preprocessing, and then mount the specific root file system.

Notice that at the end of this function. Sys_mount () is called to move the current file system mount point to the "/" directory. Then change the root directory to the current directory. In this way, the mount point of the root file system becomes the "/" we see in user space.

In the case of other root file systems, it will be processed by initrd first. That is,

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

}

Set up a device node of ROOT_RAM) and release / initrd/.image to this node. The content of / initrd.image is the image-initrd we analyzed earlier.

If the root file device number is not ROOT_RAM0 (the root file system specified by the user is not / dev/ram0, it will be transferred to handle_initrd ()

If the current root file system is / dev/ram0. Just mount it directly.

The handle_initrd () code is as follows:

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

}

ROOT_DEV = new_decode_dev (real_root_dev)

Mount_root ()

Printk (KERN_NOTICE "Trying to move old root to / initrd...")

Error = sys_mount ("/ old", "/ root/initrd", NULL, MS_MOVE, NULL)

If (! error)

Printk ("okay\ n")

Else {

Int fd = sys_open ("/ dev/root.old", O_RDWR, 0)

If (error =-ENOENT)

Printk ("/ initrd does not exist. Ignored.\ n")

Else

Printk ("failed\ n")

Printk (KERN_NOTICE "Unmounting old root\ n")

Sys_umount ("/ old", MNT_DETACH)

Printk (KERN_NOTICE "Trying to free ramdisk memory...")

If (fd

Error = fd

} else {

Error = sys_ioctl (fd, BLKFLSBUF, 0)

Sys_close (fd)

}

Printk (! error? "okay\ n": "failed\ n")

}

}

Mount / dev/ram0 first, and then execute / linuxrc. When it's done. Switch to the root directory, and then mount the specific root file system.

Come here. All the contents of the file system mount are analyzed.

The above is all the contents of the article "sample Analysis of Root File system Mount in linux". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report