Hi, Any comments on this? It would help my life considerably as I have to deal with multiple bootloaders and royally hate initrds. -- Janne On Thu, Dec 3, 2015 at 8:35 AM, Janne Karhunen wrote: > Recovery option can be used to define a secondary rootfs > in case mounting of the primary root fails. While it has > been possible to solve the issue via bootloader and/or > initrd means, this solution is suitable for systems that > want to stay bootloader agnostic and operate without an > initrd. > > Signed-off-by: Janne Karhunen > --- > Documentation/kernel-parameters.txt | 3 ++ > init/do_mounts.c | 64 > +++++++++++++++++++++++++++++-------- > 2 files changed, 54 insertions(+), 13 deletions(-) > > diff --git a/Documentation/kernel-parameters.txt > b/Documentation/kernel-parameters.txt > index 742f69d..0d65a63 100644 > --- a/Documentation/kernel-parameters.txt > +++ b/Documentation/kernel-parameters.txt > @@ -3390,6 +3390,9 @@ bytes respectively. Such letter suffixes can also be > entirely omitted. > nocompress Don't compress/decompress hibernation > images. > no Disable hibernation and resume. > > + recovery= [KNL] Recovery root filesystem. This partition is > attempted as > + root in case default root filesystem does not > mount. > + > retain_initrd [RAM] Keep initrd memory after extraction > > rfkill.default_state= > diff --git a/init/do_mounts.c b/init/do_mounts.c > index dea5de9..994b2e5 100644 > --- a/init/do_mounts.c > +++ b/init/do_mounts.c > @@ -39,8 +39,11 @@ int __initdata rd_doload; /* 1 = load RAM disk, 0 = > don't load */ > > int root_mountflags = MS_RDONLY | MS_SILENT; > static char * __initdata root_device_name; > +static char * __initdata recovery_device_name; > static char __initdata saved_root_name[64]; > +static char __initdata saved_recovery_name[64]; > static int root_wait; > +static int recovery_attempt; > > dev_t ROOT_DEV; > > @@ -298,6 +301,15 @@ static int __init root_dev_setup(char *line) > > __setup("root=", root_dev_setup); > > +static int __init recovery_setup(char *line) > +{ > + strlcpy(saved_recovery_name, line, sizeof(saved_recovery_name)); > + recovery_attempt = 1; > + return 1; > +} > + > +__setup("recovery=", recovery_setup); > + > static int __init rootwait_setup(char *str) > { > if (*str) > @@ -384,6 +396,7 @@ void __init mount_block_root(char *name, int flags) > __GFP_NOTRACK_FALSE_POSITIVE); > char *fs_names = page_address(page); > char *p; > + int err; > #ifdef CONFIG_BLOCK > char b[BDEVNAME_SIZE]; > #else > @@ -393,7 +406,7 @@ void __init mount_block_root(char *name, int flags) > get_fs_names(fs_names); > retry: > for (p = fs_names; *p; p += strlen(p)+1) { > - int err = do_mount_root(name, p, flags, root_mount_data); > + err = do_mount_root(name, p, flags, root_mount_data); > switch (err) { > case 0: > goto out; > @@ -401,7 +414,33 @@ retry: > case -EINVAL: > continue; > } > - /* > + if (!(flags & MS_RDONLY)) { > + pr_warn("Retrying rootfs mount as read-only.\n"); > + flags |= MS_RDONLY; > + goto retry; > + } > + if (recovery_device_name && recovery_attempt) { > + recovery_attempt = 0; > + > + ROOT_DEV = name_to_dev_t(recovery_device_name); > + if (strncmp(recovery_device_name, "/dev/", 5) == 0) > + recovery_device_name += 5; > + > + pr_warn("Unable to mount rootfs at %s, error > %d.\n", > + root_device_name, err); > + pr_warn("Attempting %s for recovery as > requested.\n", > + recovery_device_name); > + > + err = create_dev("/dev/root", ROOT_DEV); > + if (err < 0) > + pr_emerg("Failed to re-create /dev/root: > %d\n", > + err); > + > + root_device_name = recovery_device_name; > + goto retry; > + } > + > + /* > * Allow the user to distinguish between failed sys_open > * and bad superblock on root device. > * and give them a list of the available devices > @@ -409,28 +448,24 @@ retry: > #ifdef CONFIG_BLOCK > __bdevname(ROOT_DEV, b); > #endif > - printk("VFS: Cannot open root device \"%s\" or %s: error > %d\n", > + pr_emerg("VFS: Cannot open root device \"%s\" or %s: error > %d\n", > root_device_name, b, err); > - printk("Please append a correct \"root=\" boot option; > here are the available partitions:\n"); > + pr_emerg("Please append a correct \"root=\" boot option; > here are the available partitions:\n"); > > printk_all_partitions(); > #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT > - printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to > specify " > + pr_emerg("DEBUG_BLOCK_EXT_DEVT is enabled, you need to > specify " > "explicit textual name for \"root=\" boot > option.\n"); > #endif > panic("VFS: Unable to mount root fs on %s", b); > } > - if (!(flags & MS_RDONLY)) { > - flags |= MS_RDONLY; > - goto retry; > - } > > - printk("List of all partitions:\n"); > + pr_emerg("List of all partitions:\n"); > printk_all_partitions(); > - printk("No filesystem could mount root, tried: "); > + pr_emerg("No filesystem could mount root, tried: "); > for (p = fs_names; *p; p += strlen(p)+1) > - printk(" %s", p); > - printk("\n"); > + pr_emerg(" %s", p); > + pr_emerg("\n"); > #ifdef CONFIG_BLOCK > __bdevname(ROOT_DEV, b); > #endif > @@ -567,6 +602,9 @@ void __init prepare_namespace(void) > > md_run_setup(); > > + if (saved_recovery_name[0]) > + recovery_device_name = saved_recovery_name; > + > if (saved_root_name[0]) { > root_device_name = saved_root_name; > if (!strncmp(root_device_name, "mtd", 3) || > -- > 1.9.1 > >