Messages in this thread Patch in this message | | | From | Janne Karhunen <> | Subject | [RFC PATCH] Introduce a 'recovery' command line option | Date | Tue, 16 Aug 2016 09:36:33 +0300 |
| |
Recovery option can be used to define a secondary rootfs in case mounting of the primary root fails. This allows the kernel to automatically switch to a recovery filesystem without the initrd or the bootloader support for the switch.
Signed-off-by: Janne Karhunen <Janne.Karhunen@gmail.com> --- Documentation/kernel-parameters.txt | 4 ++++ init/do_mounts.c | 47 +++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 46c030a..febbd3e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3587,6 +3587,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. reboot_cpu is s[mp]#### with #### being the processor to be used for rebooting. + recovery= [KNL] + Recovery root filesystem. This partition is attempted as + root in case default root filesystem does not mount. + relax_domain_level= [KNL, SMP] Set scheduler's default relax_domain_level. See Documentation/cgroup-v1/cpusets.txt. diff --git a/init/do_mounts.c b/init/do_mounts.c index dea5de9..c746dce 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,6 +414,31 @@ 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 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. @@ -420,10 +458,6 @@ retry: #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"); printk_all_partitions(); @@ -567,6 +601,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
| |