summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2020-10-23 21:07:17 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2020-11-05 12:45:13 -0500
commit782ce6a818cff960b20d82f6a42dbf5deb9617c6 (patch)
tree81451b764fbe0c18e10a150799ec67ae08ef8323
parent524562a525d8b3f076b211e2b487ebeef31a2587 (diff)
bcachefs: Fix for passing target= opts as mount opts
Some options can't be parsed until the filesystem initialized; previously, passing these options to mount or remount would cause mount to fail. This changes the mount path so that we parse the options passed in twice, and just ignore any options that can't be parsed the first time. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/fs.c25
-rw-r--r--fs/bcachefs/opts.c7
-rw-r--r--fs/bcachefs/opts.h2
3 files changed, 24 insertions, 10 deletions
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 3af1acdbee5e..fcef87f8f2f2 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -1332,7 +1332,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
opt_set(opts, read_only, (*flags & SB_RDONLY) != 0);
- ret = bch2_parse_mount_opts(&opts, data);
+ ret = bch2_parse_mount_opts(c, &opts, data);
if (ret)
return ret;
@@ -1473,7 +1473,7 @@ static struct dentry *bch2_mount(struct file_system_type *fs_type,
opt_set(opts, read_only, (flags & SB_RDONLY) != 0);
- ret = bch2_parse_mount_opts(&opts, data);
+ ret = bch2_parse_mount_opts(NULL, &opts, data);
if (ret)
return ERR_PTR(ret);
@@ -1496,11 +1496,24 @@ static struct dentry *bch2_mount(struct file_system_type *fs_type,
goto got_sb;
c = bch2_fs_open(devs, nr_devs, opts);
-
- if (!IS_ERR(c))
- sb = sget(fs_type, NULL, bch2_set_super, flags|SB_NOSEC, c);
- else
+ if (IS_ERR(c)) {
sb = ERR_CAST(c);
+ goto got_sb;
+ }
+
+ /* Some options can't be parsed until after the fs is started: */
+ ret = bch2_parse_mount_opts(c, &opts, data);
+ if (ret) {
+ bch2_fs_stop(c);
+ sb = ERR_PTR(ret);
+ goto got_sb;
+ }
+
+ bch2_opts_apply(&c->opts, opts);
+
+ sb = sget(fs_type, NULL, bch2_set_super, flags|SB_NOSEC, c);
+ if (IS_ERR(sb))
+ bch2_fs_stop(c);
got_sb:
kfree(devs_to_fs);
kfree(devs[0]);
diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c
index afe25cd26c06..97a36ac0beea 100644
--- a/fs/bcachefs/opts.c
+++ b/fs/bcachefs/opts.c
@@ -247,7 +247,7 @@ int bch2_opt_parse(struct bch_fs *c, const struct bch_option *opt,
break;
case BCH_OPT_FN:
if (!c)
- return -EINVAL;
+ return 0;
return opt->parse(c, val, res);
}
@@ -325,7 +325,8 @@ int bch2_opts_check_may_set(struct bch_fs *c)
return 0;
}
-int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
+int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
+ char *options)
{
char *opt, *name, *val;
int ret, id;
@@ -340,7 +341,7 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
if (id < 0)
goto bad_opt;
- ret = bch2_opt_parse(NULL, &bch2_opt_table[id], val, &v);
+ ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v);
if (ret < 0)
goto bad_val;
} else {
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index 014c608ca0c6..1dd8d47c0972 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -418,7 +418,7 @@ void bch2_opt_to_text(struct printbuf *, struct bch_fs *,
int bch2_opt_check_may_set(struct bch_fs *, int, u64);
int bch2_opts_check_may_set(struct bch_fs *);
-int bch2_parse_mount_opts(struct bch_opts *, char *);
+int bch2_parse_mount_opts(struct bch_fs *, struct bch_opts *, char *);
/* inode opts: */