Merge tag 'armsoc-dt' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[sfrench/cifs-2.6.git] / init / initramfs.c
index 4749e1115eef3c8d079ab81c13a6a743314e1ef2..435a428c2af1cc3cdd021b08c5976e7e7ba9e64e 100644 (file)
@@ -513,42 +513,55 @@ static int __init retain_initrd_param(char *str)
 }
 __setup("retain_initrd", retain_initrd_param);
 
+#ifdef CONFIG_ARCH_HAS_KEEPINITRD
+static int __init keepinitrd_setup(char *__unused)
+{
+       do_retain_initrd = 1;
+       return 1;
+}
+__setup("keepinitrd", keepinitrd_setup);
+#endif
+
 extern char __initramfs_start[];
 extern unsigned long __initramfs_size;
 #include <linux/initrd.h>
 #include <linux/kexec.h>
 
-static void __init free_initrd(void)
+void __weak free_initrd_mem(unsigned long start, unsigned long end)
 {
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                       "initrd");
+}
+
 #ifdef CONFIG_KEXEC_CORE
+static bool kexec_free_initrd(void)
+{
        unsigned long crashk_start = (unsigned long)__va(crashk_res.start);
        unsigned long crashk_end   = (unsigned long)__va(crashk_res.end);
-#endif
-       if (do_retain_initrd)
-               goto skip;
 
-#ifdef CONFIG_KEXEC_CORE
        /*
         * If the initrd region is overlapped with crashkernel reserved region,
         * free only memory that is not part of crashkernel region.
         */
-       if (initrd_start < crashk_end && initrd_end > crashk_start) {
-               /*
-                * Initialize initrd memory region since the kexec boot does
-                * not do.
-                */
-               memset((void *)initrd_start, 0, initrd_end - initrd_start);
-               if (initrd_start < crashk_start)
-                       free_initrd_mem(initrd_start, crashk_start);
-               if (initrd_end > crashk_end)
-                       free_initrd_mem(crashk_end, initrd_end);
-       } else
-#endif
-               free_initrd_mem(initrd_start, initrd_end);
-skip:
-       initrd_start = 0;
-       initrd_end = 0;
+       if (initrd_start >= crashk_end || initrd_end <= crashk_start)
+               return false;
+
+       /*
+        * Initialize initrd memory region since the kexec boot does not do.
+        */
+       memset((void *)initrd_start, 0, initrd_end - initrd_start);
+       if (initrd_start < crashk_start)
+               free_initrd_mem(initrd_start, crashk_start);
+       if (initrd_end > crashk_end)
+               free_initrd_mem(crashk_end, initrd_end);
+       return true;
+}
+#else
+static inline bool kexec_free_initrd(void)
+{
+       return false;
 }
+#endif /* CONFIG_KEXEC_CORE */
 
 #ifdef CONFIG_BLK_DEV_RAM
 #define BUF_SIZE 1024
@@ -597,7 +610,38 @@ static void __init clean_rootfs(void)
        ksys_close(fd);
        kfree(buf);
 }
-#endif
+#else
+static inline void clean_rootfs(void)
+{
+}
+#endif /* CONFIG_BLK_DEV_RAM */
+
+#ifdef CONFIG_BLK_DEV_RAM
+static void populate_initrd_image(char *err)
+{
+       ssize_t written;
+       int fd;
+
+       unpack_to_rootfs(__initramfs_start, __initramfs_size);
+
+       printk(KERN_INFO "rootfs image is not initramfs (%s); looks like an initrd\n",
+                       err);
+       fd = ksys_open("/initrd.image", O_WRONLY | O_CREAT, 0700);
+       if (fd < 0)
+               return;
+
+       written = xwrite(fd, (char *)initrd_start, initrd_end - initrd_start);
+       if (written != initrd_end - initrd_start)
+               pr_err("/initrd.image: incomplete write (%zd != %ld)\n",
+                      written, initrd_end - initrd_start);
+       ksys_close(fd);
+}
+#else
+static void populate_initrd_image(char *err)
+{
+       printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
+}
+#endif /* CONFIG_BLK_DEV_RAM */
 
 static int __init populate_rootfs(void)
 {
@@ -605,46 +649,31 @@ static int __init populate_rootfs(void)
        char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
        if (err)
                panic("%s", err); /* Failed to decompress INTERNAL initramfs */
-       /* If available load the bootloader supplied initrd */
-       if (initrd_start && !IS_ENABLED(CONFIG_INITRAMFS_FORCE)) {
-#ifdef CONFIG_BLK_DEV_RAM
-               int fd;
+
+       if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE))
+               goto done;
+
+       if (IS_ENABLED(CONFIG_BLK_DEV_RAM))
                printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
-               err = unpack_to_rootfs((char *)initrd_start,
-                       initrd_end - initrd_start);
-               if (!err) {
-                       free_initrd();
-                       goto done;
-               } else {
-                       clean_rootfs();
-                       unpack_to_rootfs(__initramfs_start, __initramfs_size);
-               }
-               printk(KERN_INFO "rootfs image is not initramfs (%s)"
-                               "; looks like an initrd\n", err);
-               fd = ksys_open("/initrd.image",
-                             O_WRONLY|O_CREAT, 0700);
-               if (fd >= 0) {
-                       ssize_t written = xwrite(fd, (char *)initrd_start,
-                                               initrd_end - initrd_start);
-
-                       if (written != initrd_end - initrd_start)
-                               pr_err("/initrd.image: incomplete write (%zd != %ld)\n",
-                                      written, initrd_end - initrd_start);
-
-                       ksys_close(fd);
-                       free_initrd();
-               }
-       done:
-               /* empty statement */;
-#else
+       else
                printk(KERN_INFO "Unpacking initramfs...\n");
-               err = unpack_to_rootfs((char *)initrd_start,
-                       initrd_end - initrd_start);
-               if (err)
-                       printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
-               free_initrd();
-#endif
+
+       err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
+       if (err) {
+               clean_rootfs();
+               populate_initrd_image(err);
        }
+
+done:
+       /*
+        * If the initrd region is overlapped with crashkernel reserved region,
+        * free only memory that is not part of crashkernel region.
+        */
+       if (!do_retain_initrd && !kexec_free_initrd())
+               free_initrd_mem(initrd_start, initrd_end);
+       initrd_start = 0;
+       initrd_end = 0;
+
        flush_delayed_fput();
        return 0;
 }