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