Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/unistd.h>
0003 #include <linux/kernel.h>
0004 #include <linux/fs.h>
0005 #include <linux/minix_fs.h>
0006 #include <linux/romfs_fs.h>
0007 #include <linux/initrd.h>
0008 #include <linux/sched.h>
0009 #include <linux/freezer.h>
0010 #include <linux/kmod.h>
0011 #include <uapi/linux/mount.h>
0012 
0013 #include "do_mounts.h"
0014 
0015 unsigned long initrd_start, initrd_end;
0016 int initrd_below_start_ok;
0017 static unsigned int real_root_dev;  /* do_proc_dointvec cannot handle kdev_t */
0018 static int __initdata mount_initrd = 1;
0019 
0020 phys_addr_t phys_initrd_start __initdata;
0021 unsigned long phys_initrd_size __initdata;
0022 
0023 #ifdef CONFIG_SYSCTL
0024 static struct ctl_table kern_do_mounts_initrd_table[] = {
0025     {
0026         .procname       = "real-root-dev",
0027         .data           = &real_root_dev,
0028         .maxlen         = sizeof(int),
0029         .mode           = 0644,
0030         .proc_handler   = proc_dointvec,
0031     },
0032     { }
0033 };
0034 
0035 static __init int kernel_do_mounts_initrd_sysctls_init(void)
0036 {
0037     register_sysctl_init("kernel", kern_do_mounts_initrd_table);
0038     return 0;
0039 }
0040 late_initcall(kernel_do_mounts_initrd_sysctls_init);
0041 #endif /* CONFIG_SYSCTL */
0042 
0043 static int __init no_initrd(char *str)
0044 {
0045     mount_initrd = 0;
0046     return 1;
0047 }
0048 
0049 __setup("noinitrd", no_initrd);
0050 
0051 static int __init early_initrdmem(char *p)
0052 {
0053     phys_addr_t start;
0054     unsigned long size;
0055     char *endp;
0056 
0057     start = memparse(p, &endp);
0058     if (*endp == ',') {
0059         size = memparse(endp + 1, NULL);
0060 
0061         phys_initrd_start = start;
0062         phys_initrd_size = size;
0063     }
0064     return 0;
0065 }
0066 early_param("initrdmem", early_initrdmem);
0067 
0068 static int __init early_initrd(char *p)
0069 {
0070     return early_initrdmem(p);
0071 }
0072 early_param("initrd", early_initrd);
0073 
0074 static int __init init_linuxrc(struct subprocess_info *info, struct cred *new)
0075 {
0076     ksys_unshare(CLONE_FS | CLONE_FILES);
0077     console_on_rootfs();
0078     /* move initrd over / and chdir/chroot in initrd root */
0079     init_chdir("/root");
0080     init_mount(".", "/", NULL, MS_MOVE, NULL);
0081     init_chroot(".");
0082     ksys_setsid();
0083     return 0;
0084 }
0085 
0086 static void __init handle_initrd(void)
0087 {
0088     struct subprocess_info *info;
0089     static char *argv[] = { "linuxrc", NULL, };
0090     extern char *envp_init[];
0091     int error;
0092 
0093     pr_warn("using deprecated initrd support, will be removed in 2021.\n");
0094 
0095     real_root_dev = new_encode_dev(ROOT_DEV);
0096     create_dev("/dev/root.old", Root_RAM0);
0097     /* mount initrd on rootfs' /root */
0098     mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
0099     init_mkdir("/old", 0700);
0100     init_chdir("/old");
0101 
0102     /*
0103      * In case that a resume from disk is carried out by linuxrc or one of
0104      * its children, we need to tell the freezer not to wait for us.
0105      */
0106     current->flags |= PF_FREEZER_SKIP;
0107 
0108     info = call_usermodehelper_setup("/linuxrc", argv, envp_init,
0109                      GFP_KERNEL, init_linuxrc, NULL, NULL);
0110     if (!info)
0111         return;
0112     call_usermodehelper_exec(info, UMH_WAIT_PROC);
0113 
0114     current->flags &= ~PF_FREEZER_SKIP;
0115 
0116     /* move initrd to rootfs' /old */
0117     init_mount("..", ".", NULL, MS_MOVE, NULL);
0118     /* switch root and cwd back to / of rootfs */
0119     init_chroot("..");
0120 
0121     if (new_decode_dev(real_root_dev) == Root_RAM0) {
0122         init_chdir("/old");
0123         return;
0124     }
0125 
0126     init_chdir("/");
0127     ROOT_DEV = new_decode_dev(real_root_dev);
0128     mount_root();
0129 
0130     printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
0131     error = init_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
0132     if (!error)
0133         printk("okay\n");
0134     else {
0135         if (error == -ENOENT)
0136             printk("/initrd does not exist. Ignored.\n");
0137         else
0138             printk("failed\n");
0139         printk(KERN_NOTICE "Unmounting old root\n");
0140         init_umount("/old", MNT_DETACH);
0141     }
0142 }
0143 
0144 bool __init initrd_load(void)
0145 {
0146     if (mount_initrd) {
0147         create_dev("/dev/ram", Root_RAM0);
0148         /*
0149          * Load the initrd data into /dev/ram0. Execute it as initrd
0150          * unless /dev/ram0 is supposed to be our actual root device,
0151          * in that case the ram disk is just set up here, and gets
0152          * mounted in the normal path.
0153          */
0154         if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {
0155             init_unlink("/initrd.image");
0156             handle_initrd();
0157             return true;
0158         }
0159     }
0160     init_unlink("/initrd.image");
0161     return false;
0162 }