summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-01-07 19:02:15 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2018-01-10 03:04:44 -0500
commit3adb323966f54f9e371ec1c59c84b239b42bdc6c (patch)
treede2d88e22f6a4dc7def3a51afc75549b023d703e
parent6431e47fd52828ed94cfbf0ebed3a0a9f99326d9 (diff)
bcachefs: fix mounting read only block devices
-rw-r--r--fs/bcachefs/opts.h2
-rw-r--r--fs/bcachefs/super-io.c22
-rw-r--r--fs/bcachefs/super-io.h2
-rw-r--r--fs/bcachefs/super.c10
4 files changed, 24 insertions, 12 deletions
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index 126056e60543..bc8fd46aeb23 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -171,7 +171,7 @@ static const struct bch_opts bch2_opts_default = {
#define opt_defined(_opts, _name) ((_opts)._name##_defined)
#define opt_get(_opts, _name) \
- (opt_defined(_opts, _name) ? _opts._name : bch2_opts_default._name)
+ (opt_defined(_opts, _name) ? (_opts)._name : bch2_opts_default._name)
#define opt_set(_opts, _name, _v) \
do { \
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index e49437c276ac..6c7f4166d3dd 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -531,10 +531,10 @@ reread:
return NULL;
}
-int bch2_read_super(const char *path, struct bch_opts opts,
+int bch2_read_super(const char *path, struct bch_opts *opts,
struct bch_sb_handle *sb)
{
- u64 offset = opt_get(opts, sb);
+ u64 offset = opt_get(*opts, sb);
struct bch_sb_layout layout;
const char *err;
__le64 *i;
@@ -543,13 +543,23 @@ int bch2_read_super(const char *path, struct bch_opts opts,
memset(sb, 0, sizeof(*sb));
sb->mode = FMODE_READ;
- if (!opt_get(opts, noexcl))
+ if (!opt_get(*opts, noexcl))
sb->mode |= FMODE_EXCL;
- if (!opt_get(opts, nochanges))
+ if (!opt_get(*opts, nochanges))
sb->mode |= FMODE_WRITE;
sb->bdev = blkdev_get_by_path(path, sb->mode, sb);
+ if (IS_ERR(sb->bdev) &&
+ PTR_ERR(sb->bdev) == -EACCES &&
+ opt_get(*opts, read_only)) {
+ sb->mode &= ~FMODE_WRITE;
+
+ sb->bdev = blkdev_get_by_path(path, sb->mode, sb);
+ if (!IS_ERR(sb->bdev))
+ opt_set(*opts, nochanges, true);
+ }
+
if (IS_ERR(sb->bdev))
return PTR_ERR(sb->bdev);
@@ -568,7 +578,7 @@ int bch2_read_super(const char *path, struct bch_opts opts,
if (!err)
goto got_super;
- if (opt_defined(opts, sb))
+ if (opt_defined(*opts, sb))
goto err;
pr_err("error reading default superblock: %s", err);
@@ -601,7 +611,7 @@ int bch2_read_super(const char *path, struct bch_opts opts,
i < layout.sb_offset + layout.nr_superblocks; i++) {
offset = le64_to_cpu(*i);
- if (offset == opt_get(opts, sb))
+ if (offset == opt_get(*opts, sb))
continue;
err = read_one_super(sb, offset);
diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h
index 32ac0e875fa0..69366a6f9581 100644
--- a/fs/bcachefs/super-io.h
+++ b/fs/bcachefs/super-io.h
@@ -94,7 +94,7 @@ int bch2_super_realloc(struct bch_sb_handle *, unsigned);
const char *bch2_sb_validate(struct bch_sb_handle *);
-int bch2_read_super(const char *, struct bch_opts, struct bch_sb_handle *);
+int bch2_read_super(const char *, struct bch_opts *, struct bch_sb_handle *);
void bch2_write_super(struct bch_fs *);
/* BCH_SB_FIELD_journal: */
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 6f541ddd6aa0..4cc4301ceae7 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -1432,6 +1432,7 @@ err:
/* Add new device to running filesystem: */
int bch2_dev_add(struct bch_fs *c, const char *path)
{
+ struct bch_opts opts = bch2_opts_empty();
struct bch_sb_handle sb;
const char *err;
struct bch_dev *ca = NULL;
@@ -1440,7 +1441,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
unsigned dev_idx, nr_devices, u64s;
int ret;
- ret = bch2_read_super(path, bch2_opts_empty(), &sb);
+ ret = bch2_read_super(path, &opts, &sb);
if (ret)
return ret;
@@ -1542,6 +1543,7 @@ err:
/* Hot add existing device to running filesystem: */
int bch2_dev_online(struct bch_fs *c, const char *path)
{
+ struct bch_opts opts = bch2_opts_empty();
struct bch_sb_handle sb = { NULL };
struct bch_dev *ca;
unsigned dev_idx;
@@ -1550,7 +1552,7 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
mutex_lock(&c->state_lock);
- ret = bch2_read_super(path, bch2_opts_empty(), &sb);
+ ret = bch2_read_super(path, &opts, &sb);
if (ret) {
mutex_unlock(&c->state_lock);
return ret;
@@ -1708,7 +1710,7 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
goto err;
for (i = 0; i < nr_devices; i++) {
- ret = bch2_read_super(devices[i], opts, &sb[i]);
+ ret = bch2_read_super(devices[i], &opts, &sb[i]);
if (ret)
goto err;
@@ -1842,7 +1844,7 @@ const char *bch2_fs_open_incremental(const char *path)
struct bch_opts opts = bch2_opts_empty();
const char *err;
- if (bch2_read_super(path, opts, &sb))
+ if (bch2_read_super(path, &opts, &sb))
return "error reading superblock";
err = __bch2_fs_open_incremental(&sb, opts);