Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : #include <linux/unistd.h>
3 : : #include <linux/kernel.h>
4 : : #include <linux/fs.h>
5 : : #include <linux/minix_fs.h>
6 : : #include <linux/romfs_fs.h>
7 : : #include <linux/initrd.h>
8 : : #include <linux/sched.h>
9 : : #include <linux/freezer.h>
10 : : #include <linux/kmod.h>
11 : : #include <uapi/linux/mount.h>
12 : :
13 : : #include "do_mounts.h"
14 : :
15 : : unsigned long initrd_start, initrd_end;
16 : : int initrd_below_start_ok;
17 : : unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */
18 : : static int __initdata mount_initrd = 1;
19 : :
20 : : phys_addr_t phys_initrd_start __initdata;
21 : : unsigned long phys_initrd_size __initdata;
22 : :
23 : 0 : static int __init no_initrd(char *str)
24 : : {
25 : 0 : mount_initrd = 0;
26 : 0 : return 1;
27 : : }
28 : :
29 : : __setup("noinitrd", no_initrd);
30 : :
31 : 0 : static int __init early_initrd(char *p)
32 : : {
33 : 0 : phys_addr_t start;
34 : 0 : unsigned long size;
35 : 0 : char *endp;
36 : :
37 : 0 : start = memparse(p, &endp);
38 [ # # ]: 0 : if (*endp == ',') {
39 : 0 : size = memparse(endp + 1, NULL);
40 : :
41 : 0 : phys_initrd_start = start;
42 : 0 : phys_initrd_size = size;
43 : : }
44 : 0 : return 0;
45 : : }
46 : : early_param("initrd", early_initrd);
47 : :
48 : : static int init_linuxrc(struct subprocess_info *info, struct cred *new)
49 : : {
50 : : ksys_unshare(CLONE_FS | CLONE_FILES);
51 : : console_on_rootfs();
52 : : /* move initrd over / and chdir/chroot in initrd root */
53 : : ksys_chdir("/root");
54 : : do_mount(".", "/", NULL, MS_MOVE, NULL);
55 : : ksys_chroot(".");
56 : : ksys_setsid();
57 : : return 0;
58 : : }
59 : :
60 : : static void __init handle_initrd(void)
61 : : {
62 : : struct subprocess_info *info;
63 : : static char *argv[] = { "linuxrc", NULL, };
64 : : extern char *envp_init[];
65 : : int error;
66 : :
67 : : real_root_dev = new_encode_dev(ROOT_DEV);
68 : : create_dev("/dev/root.old", Root_RAM0);
69 : : /* mount initrd on rootfs' /root */
70 : : mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
71 : : ksys_mkdir("/old", 0700);
72 : : ksys_chdir("/old");
73 : :
74 : : /*
75 : : * In case that a resume from disk is carried out by linuxrc or one of
76 : : * its children, we need to tell the freezer not to wait for us.
77 : : */
78 : : current->flags |= PF_FREEZER_SKIP;
79 : :
80 : : info = call_usermodehelper_setup("/linuxrc", argv, envp_init,
81 : : GFP_KERNEL, init_linuxrc, NULL, NULL);
82 : : if (!info)
83 : : return;
84 : : call_usermodehelper_exec(info, UMH_WAIT_PROC);
85 : :
86 : : current->flags &= ~PF_FREEZER_SKIP;
87 : :
88 : : /* move initrd to rootfs' /old */
89 : : do_mount("..", ".", NULL, MS_MOVE, NULL);
90 : : /* switch root and cwd back to / of rootfs */
91 : : ksys_chroot("..");
92 : :
93 : : if (new_decode_dev(real_root_dev) == Root_RAM0) {
94 : : ksys_chdir("/old");
95 : : return;
96 : : }
97 : :
98 : : ksys_chdir("/");
99 : : ROOT_DEV = new_decode_dev(real_root_dev);
100 : : mount_root();
101 : :
102 : : printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
103 : : error = do_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
104 : : if (!error)
105 : : printk("okay\n");
106 : : else {
107 : : int fd = ksys_open("/dev/root.old", O_RDWR, 0);
108 : : if (error == -ENOENT)
109 : : printk("/initrd does not exist. Ignored.\n");
110 : : else
111 : : printk("failed\n");
112 : : printk(KERN_NOTICE "Unmounting old root\n");
113 : : ksys_umount("/old", MNT_DETACH);
114 : : printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
115 : : if (fd < 0) {
116 : : error = fd;
117 : : } else {
118 : : error = ksys_ioctl(fd, BLKFLSBUF, 0);
119 : : ksys_close(fd);
120 : : }
121 : : printk(!error ? "okay\n" : "failed\n");
122 : : }
123 : : }
124 : :
125 : 28 : bool __init initrd_load(void)
126 : : {
127 [ + - ]: 28 : if (mount_initrd) {
128 : 28 : create_dev("/dev/ram", Root_RAM0);
129 : : /*
130 : : * Load the initrd data into /dev/ram0. Execute it as initrd
131 : : * unless /dev/ram0 is supposed to be our actual root device,
132 : : * in that case the ram disk is just set up here, and gets
133 : : * mounted in the normal path.
134 : : */
135 : 28 : if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {
136 : : ksys_unlink("/initrd.image");
137 : : handle_initrd();
138 : : return true;
139 : : }
140 : : }
141 : 28 : ksys_unlink("/initrd.image");
142 : 28 : return false;
143 : : }
|