summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/bcache.h2
-rw-r--r--drivers/md/bcache/chardev.c4
-rw-r--r--drivers/md/bcache/fs.c121
-rw-r--r--drivers/md/bcache/super.c35
-rw-r--r--drivers/md/bcache/super.h9
-rw-r--r--drivers/md/bcache/super_types.h10
6 files changed, 133 insertions, 48 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 3327dc490a5f..224858445b5e 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -414,6 +414,8 @@ struct cache_set {
struct cache_member_rcu *members;
unsigned long cache_slots_used[BITS_TO_LONGS(MAX_CACHES_PER_SET)];
+ struct cache_set_opts opts;
+
struct cache_sb sb;
unsigned short block_bits; /* ilog2(block_size) */
diff --git a/drivers/md/bcache/chardev.c b/drivers/md/bcache/chardev.c
index cffba0dc937d..5c6b2e6aeb91 100644
--- a/drivers/md/bcache/chardev.c
+++ b/drivers/md/bcache/chardev.c
@@ -52,7 +52,9 @@ static long bch_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
}
}
- err = bch_register_cache_set(devs, arg.nr_devs, NULL);
+ err = bch_register_cache_set(devs, arg.nr_devs,
+ cache_set_opts_empty(),
+ NULL);
if (err) {
pr_err("Could not register cache set: %s", err);
ret = -EINVAL;
diff --git a/drivers/md/bcache/fs.c b/drivers/md/bcache/fs.c
index 502a983dcc3f..80884f3adc96 100644
--- a/drivers/md/bcache/fs.c
+++ b/drivers/md/bcache/fs.c
@@ -1843,23 +1843,8 @@ static int bch_sync_fs(struct super_block *sb, int wait)
return 0;
}
-static const struct super_operations bch_super_operations = {
- .alloc_inode = bch_alloc_inode,
- .destroy_inode = bch_destroy_inode,
- .write_inode = bch_write_inode,
- .evict_inode = bch_evict_inode,
- .sync_fs = bch_sync_fs,
- .statfs = bch_statfs,
- .show_options = generic_show_options,
-#if 0
- .put_super = bch_put_super,
- .freeze_fs = bch_freeze,
- .unfreeze_fs = bch_unfreeze,
- .remount_fs = bch_remount,
-#endif
-};
-
-static struct cache_set *bch_open_as_blockdevs(const char *_dev_name)
+static struct cache_set *bch_open_as_blockdevs(const char *_dev_name,
+ struct cache_set_opts opts)
{
size_t nr_devs = 0, i = 0;
char *dev_name, *s, **devs;
@@ -1882,7 +1867,7 @@ static struct cache_set *bch_open_as_blockdevs(const char *_dev_name)
(s = strchr(s, ':')) && (*s++ = '\0'))
devs[i++] = s;
- err = bch_register_cache_set(devs, nr_devs, &c);
+ err = bch_register_cache_set(devs, nr_devs, opts, &c);
if (err) {
pr_err("register_cache_set err %s", err);
goto out;
@@ -1914,12 +1899,15 @@ static const match_table_t tokens = {
{Opt_err, NULL}
};
-static int parse_options(struct cache_set *c, struct super_block *sb,
- char *options)
+static int parse_options(struct cache_set_opts *opts, int flags, char *options)
{
char *p;
substring_t args[MAX_OPT_ARGS];
+ *opts = cache_set_opts_empty();
+
+ opts->read_only = (flags & MS_RDONLY) != 0;
+
if (!options)
return 1;
@@ -1932,43 +1920,102 @@ static int parse_options(struct cache_set *c, struct super_block *sb,
token = match_token(p, tokens, args);
switch (token) {
case Opt_err_panic:
- /*
- * XXX: this will get written to the superblock, don't
- * want this option to be persistent
- */
- SET_CACHE_ERROR_ACTION(&c->sb, BCH_ON_ERROR_PANIC);
+ opts->on_error_action = BCH_ON_ERROR_PANIC;
break;
case Opt_err_ro:
- SET_CACHE_ERROR_ACTION(&c->sb, BCH_ON_ERROR_RO);
+ opts->on_error_action = BCH_ON_ERROR_RO;
break;
case Opt_err_cont:
- SET_CACHE_ERROR_ACTION(&c->sb, BCH_ON_ERROR_CONTINUE);
+ opts->on_error_action = BCH_ON_ERROR_CONTINUE;
break;
case Opt_user_xattr:
case Opt_nouser_xattr:
break;
case Opt_acl:
- sb->s_flags |= MS_POSIXACL;
+ opts->posix_acl = true;
break;
case Opt_noacl:
- sb->s_flags &= ~MS_POSIXACL;
+ opts->posix_acl = false;
break;
default:
return 0;
}
}
+
return 1;
}
+static int bch_remount(struct super_block *sb, int *flags, char *data)
+{
+ struct cache_set *c = sb->s_fs_info;
+ struct cache_set_opts opts;
+ int ret = 0;
+
+ if (!parse_options(&opts, *flags, data))
+ return EINVAL;
+
+ mutex_lock(&bch_register_lock);
+
+ if (opts.read_only >= 0 &&
+ opts.read_only != c->opts.read_only) {
+ const char *err = NULL;
+
+ if (opts.read_only) {
+ bch_cache_set_read_only(c);
+
+ sb->s_flags |= MS_RDONLY;
+ } else {
+ err = bch_cache_set_read_write(c);
+ if (err) {
+ pr_info("error going rw");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ sb->s_flags &= ~MS_RDONLY;
+ }
+
+ c->opts.read_only = opts.read_only;
+ }
+
+ if (opts.on_error_action >= 0)
+ c->opts.on_error_action = opts.on_error_action;
+
+unlock:
+ mutex_unlock(&bch_register_lock);
+
+ return ret;
+}
+
+static const struct super_operations bch_super_operations = {
+ .alloc_inode = bch_alloc_inode,
+ .destroy_inode = bch_destroy_inode,
+ .write_inode = bch_write_inode,
+ .evict_inode = bch_evict_inode,
+ .sync_fs = bch_sync_fs,
+ .statfs = bch_statfs,
+ .show_options = generic_show_options,
+ .remount_fs = bch_remount,
+#if 0
+ .put_super = bch_put_super,
+ .freeze_fs = bch_freeze,
+ .unfreeze_fs = bch_unfreeze,
+#endif
+};
+
static struct dentry *bch_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
struct cache_set *c;
struct super_block *sb;
struct inode *inode;
+ struct cache_set_opts opts;
int ret;
- c = bch_open_as_blockdevs(dev_name);
+ if (!parse_options(&opts, flags, data))
+ return ERR_PTR(-EINVAL);
+
+ c = bch_open_as_blockdevs(dev_name, opts);
if (!c)
return ERR_PTR(-ENOENT);
@@ -1978,7 +2025,7 @@ static struct dentry *bch_mount(struct file_system_type *fs_type,
goto err;
}
- /* XXX: */
+ /* XXX: blocksize */
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_maxbytes = MAX_LFS_FILESIZE;
@@ -1988,17 +2035,15 @@ static struct dentry *bch_mount(struct file_system_type *fs_type,
sb->s_time_gran = 1;
sb->s_fs_info = c;
- sb->s_flags |= MS_POSIXACL;
+ if (opts.posix_acl < 0)
+ sb->s_flags |= MS_POSIXACL;
+ else
+ sb->s_flags |= opts.posix_acl ? MS_POSIXACL : 0;
- /* XXX */
+ /* XXX: do we even need s_bdev? */
sb->s_bdev = c->cache[0]->disk_sb.bdev;
sb->s_bdi = &c->bdi;
- if (!parse_options(c, sb, (char *) data)) {
- ret = -EINVAL;
- goto err_put_super;
- }
-
inode = bch_vfs_inode_get(sb, BCACHE_ROOT_INO);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index a434a6f07726..4b0e4167e3c8 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -809,7 +809,7 @@ static void bch_cache_set_read_only_work(struct work_struct *work)
void bch_cache_set_fail(struct cache_set *c)
{
- switch (CACHE_ERROR_ACTION(&c->sb)) {
+ switch (c->opts.on_error_action) {
case BCH_ON_ERROR_CONTINUE:
break;
case BCH_ON_ERROR_RO:
@@ -975,7 +975,8 @@ static unsigned cache_set_nr_online_devices(struct cache_set *c)
#define alloc_bucket_pages(gfp, ca) \
((void *) __get_free_pages(__GFP_ZERO|gfp, ilog2(bucket_pages(ca))))
-static struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
+static struct cache_set *bch_cache_set_alloc(struct cache_sb *sb,
+ struct cache_set_opts opts)
{
struct cache_set *c;
unsigned iter_size;
@@ -1005,6 +1006,16 @@ static struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
if (cache_sb_to_cache_set(c, sb))
goto err;
+ c->opts = (struct cache_set_opts) {
+ .read_only = 0,
+ .on_error_action = CACHE_ERROR_ACTION(&c->sb),
+ };
+
+ if (opts.read_only >= 0)
+ c->opts.read_only = opts.read_only;
+ if (opts.on_error_action >= 0)
+ c->opts.on_error_action = opts.on_error_action;
+
c->minor = -1;
c->block_bits = ilog2(c->sb.block_size);
@@ -1315,9 +1326,13 @@ static const char *run_cache_set(struct cache_set *c)
closure_sync(&cl);
- err = __bch_cache_set_read_write(c);
- if (err)
- goto err;
+ if (c->opts.read_only) {
+ bch_cache_set_read_only(c);
+ } else {
+ err = __bch_cache_set_read_write(c);
+ if (err)
+ goto err;
+ }
now = get_seconds();
mi = cache_member_info_get(c);
@@ -1966,7 +1981,8 @@ static struct cache_set *cache_set_lookup(uuid_le uuid)
return NULL;
}
-static const char *register_cache(struct bcache_superblock *sb)
+static const char *register_cache(struct bcache_superblock *sb,
+ struct cache_set_opts opts)
{
char name[BDEVNAME_SIZE];
const char *err = "cannot allocate memory";
@@ -1989,7 +2005,7 @@ static const char *register_cache(struct bcache_superblock *sb)
goto out;
}
- c = bch_cache_set_alloc(sb->sb);
+ c = bch_cache_set_alloc(sb->sb, opts);
if (!c)
goto err;
@@ -2136,6 +2152,7 @@ err:
}
const char *bch_register_cache_set(char * const *devices, unsigned nr_devices,
+ struct cache_set_opts opts,
struct cache_set **ret)
{
const char *err;
@@ -2173,7 +2190,7 @@ const char *bch_register_cache_set(char * const *devices, unsigned nr_devices,
goto err;
err = "cannot allocate memory";
- c = bch_cache_set_alloc(sb[0].sb);
+ c = bch_cache_set_alloc(sb[0].sb, opts);
if (!c)
goto err_unlock;
@@ -2231,7 +2248,7 @@ const char *bch_register_one(const char *path)
err = bch_register_bdev(&sb);
mutex_unlock(&bch_register_lock);
} else {
- err = register_cache(&sb);
+ err = register_cache(&sb, cache_set_opts_empty());
}
free_super(&sb);
diff --git a/drivers/md/bcache/super.h b/drivers/md/bcache/super.h
index 1e4f9d6d73c0..f3e0bd52d44d 100644
--- a/drivers/md/bcache/super.h
+++ b/drivers/md/bcache/super.h
@@ -160,8 +160,17 @@ void bch_cache_release(struct kobject *);
void bch_cache_set_unregister(struct cache_set *);
void bch_cache_set_stop(struct cache_set *);
+static inline struct cache_set_opts cache_set_opts_empty(void)
+{
+ struct cache_set_opts ret;
+
+ memset(&ret, 255, sizeof(ret));
+ return ret;
+}
+
const char *bch_register_one(const char *path);
const char *bch_register_cache_set(char * const *, unsigned,
+ struct cache_set_opts,
struct cache_set **);
void bch_cache_set_read_only(struct cache_set *);
diff --git a/drivers/md/bcache/super_types.h b/drivers/md/bcache/super_types.h
index d89f780f544f..25f0e203acf1 100644
--- a/drivers/md/bcache/super_types.h
+++ b/drivers/md/bcache/super_types.h
@@ -8,4 +8,14 @@ struct bcache_superblock {
unsigned page_order;
};
+struct cache_set_opts {
+ /* For each opt, -1 = undefined */
+
+ int read_only:2;
+ int on_error_action:3;
+
+ /* filesystem options: */
+ int posix_acl:2;
+};
+
#endif /* _BCACHE_SUPER_TYPES_H */