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