btrfs: introduce "rescue=" mount option
authorQu Wenruo <wqu@suse.com>
Thu, 4 Jun 2020 07:18:06 +0000 (15:18 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 27 Jul 2020 10:55:22 +0000 (12:55 +0200)
This patch introduces a new "rescue=" mount option group for all mount
options for data recovery.

Different rescue sub options are seperated by ':'. E.g
"ro,rescue=nologreplay:usebackuproot".

The original plan was to use ';', but ';' needs to be escaped/quoted,
or it will be interpreted by bash, similar to '|'.

And obviously, user can specify rescue options one by one like:
"ro,rescue=nologreplay,rescue=usebackuproot".

The following mount options are converted to "rescue=", old mount
options are deprecated but still available for compatibility purpose:

- usebackuproot
  Now it's "rescue=usebackuproot"

- nologreplay
  Now it's "rescue=nologreplay"

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/super.c

index c3826ae..76ab6d5 100644 (file)
@@ -326,7 +326,6 @@ enum {
        Opt_defrag, Opt_nodefrag,
        Opt_discard, Opt_nodiscard,
        Opt_discard_mode,
-       Opt_nologreplay,
        Opt_norecovery,
        Opt_ratio,
        Opt_rescan_uuid_tree,
@@ -340,9 +339,13 @@ enum {
        Opt_subvolid,
        Opt_thread_pool,
        Opt_treelog, Opt_notreelog,
-       Opt_usebackuproot,
        Opt_user_subvol_rm_allowed,
 
+       /* Rescue options */
+       Opt_rescue,
+       Opt_usebackuproot,
+       Opt_nologreplay,
+
        /* Deprecated options */
        Opt_alloc_start,
        Opt_recovery,
@@ -390,7 +393,6 @@ static const match_table_t tokens = {
        {Opt_discard, "discard"},
        {Opt_discard_mode, "discard=%s"},
        {Opt_nodiscard, "nodiscard"},
-       {Opt_nologreplay, "nologreplay"},
        {Opt_norecovery, "norecovery"},
        {Opt_ratio, "metadata_ratio=%u"},
        {Opt_rescan_uuid_tree, "rescan_uuid_tree"},
@@ -408,9 +410,15 @@ static const match_table_t tokens = {
        {Opt_thread_pool, "thread_pool=%u"},
        {Opt_treelog, "treelog"},
        {Opt_notreelog, "notreelog"},
-       {Opt_usebackuproot, "usebackuproot"},
        {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
 
+       /* Rescue options */
+       {Opt_rescue, "rescue=%s"},
+       /* Deprecated, with alias rescue=nologreplay */
+       {Opt_nologreplay, "nologreplay"},
+       /* Deprecated, with alias rescue=usebackuproot */
+       {Opt_usebackuproot, "usebackuproot"},
+
        /* Deprecated options */
        {Opt_alloc_start, "alloc_start=%s"},
        {Opt_recovery, "recovery"},
@@ -433,6 +441,55 @@ static const match_table_t tokens = {
        {Opt_err, NULL},
 };
 
+static const match_table_t rescue_tokens = {
+       {Opt_usebackuproot, "usebackuproot"},
+       {Opt_nologreplay, "nologreplay"},
+       {Opt_err, NULL},
+};
+
+static int parse_rescue_options(struct btrfs_fs_info *info, const char *options)
+{
+       char *opts;
+       char *orig;
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int ret = 0;
+
+       opts = kstrdup(options, GFP_KERNEL);
+       if (!opts)
+               return -ENOMEM;
+       orig = opts;
+
+       while ((p = strsep(&opts, ":")) != NULL) {
+               int token;
+
+               if (!*p)
+                       continue;
+               token = match_token(p, rescue_tokens, args);
+               switch (token){
+               case Opt_usebackuproot:
+                       btrfs_info(info,
+                                  "trying to use backup root at mount time");
+                       btrfs_set_opt(info->mount_opt, USEBACKUPROOT);
+                       break;
+               case Opt_nologreplay:
+                       btrfs_set_and_info(info, NOLOGREPLAY,
+                                          "disabling log replay at mount time");
+                       break;
+               case Opt_err:
+                       btrfs_info(info, "unrecognized rescue option '%s'", p);
+                       ret = -EINVAL;
+                       goto out;
+               default:
+                       break;
+               }
+
+       }
+out:
+       kfree(orig);
+       return ret;
+}
+
 /*
  * Regular mount options parser.  Everything that is needed only when
  * reading in a new superblock is parsed here.
@@ -689,6 +746,8 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                        break;
                case Opt_norecovery:
                case Opt_nologreplay:
+                       btrfs_warn(info,
+               "'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
                        btrfs_set_and_info(info, NOLOGREPLAY,
                                           "disabling log replay at mount time");
                        break;
@@ -791,10 +850,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                                             "disabling auto defrag");
                        break;
                case Opt_recovery:
-                       btrfs_warn(info,
-                                  "'recovery' is deprecated, use 'usebackuproot' instead");
-                       fallthrough;
                case Opt_usebackuproot:
+                       btrfs_warn(info,
+                       "'%s' is deprecated, use 'rescue=usebackuproot' instead",
+                                  token == Opt_recovery ? "recovery" :
+                                  "usebackuproot");
                        btrfs_info(info,
                                   "trying to use backup root at mount time");
                        btrfs_set_opt(info->mount_opt, USEBACKUPROOT);
@@ -859,6 +919,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                        }
                        info->commit_interval = intarg;
                        break;
+               case Opt_rescue:
+                       ret = parse_rescue_options(info, args[0].from);
+                       if (ret < 0)
+                               goto out;
+                       break;
 #ifdef CONFIG_BTRFS_DEBUG
                case Opt_fragment_all:
                        btrfs_info(info, "fragmenting all space");
@@ -1344,7 +1409,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
        if (btrfs_test_opt(info, NOTREELOG))
                seq_puts(seq, ",notreelog");
        if (btrfs_test_opt(info, NOLOGREPLAY))
-               seq_puts(seq, ",nologreplay");
+               seq_puts(seq, ",rescue=nologreplay");
        if (btrfs_test_opt(info, FLUSHONCOMMIT))
                seq_puts(seq, ",flushoncommit");
        if (btrfs_test_opt(info, DISCARD_SYNC))