summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2015-08-21 23:43:07 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-10-07 12:34:46 -0800
commit6f8726f2b69aca632110b5732ea4f8bff77fb45a (patch)
tree6cf0ce1b93ef84f85e633a4aa5173f155f1eddee
parentaac1d61f6a55af9956ea7487e16734994f724e6c (diff)
bcache: Rework mount options
-rw-r--r--drivers/md/bcache/Makefile4
-rw-r--r--drivers/md/bcache/alloc.c2
-rw-r--r--drivers/md/bcache/bcache.h1
-rw-r--r--drivers/md/bcache/btree_io.c2
-rw-r--r--drivers/md/bcache/error.c2
-rw-r--r--drivers/md/bcache/fs.c115
-rw-r--r--drivers/md/bcache/io.c4
-rw-r--r--drivers/md/bcache/journal.c2
-rw-r--r--drivers/md/bcache/opts.c138
-rw-r--r--drivers/md/bcache/opts.h104
-rw-r--r--drivers/md/bcache/super.c27
-rw-r--r--drivers/md/bcache/super.h5
-rw-r--r--drivers/md/bcache/sysfs.c184
13 files changed, 362 insertions, 228 deletions
diff --git a/drivers/md/bcache/Makefile b/drivers/md/bcache/Makefile
index 6306ae3612e4..aa67393cd0a8 100644
--- a/drivers/md/bcache/Makefile
+++ b/drivers/md/bcache/Makefile
@@ -5,5 +5,5 @@ bcache-y := acl.o alloc.o bkey.o bkey_methods.o blockdev.o\
bset.o btree_cache.o btree_gc.o btree_io.o btree_iter.o btree_update.o\
buckets.o chardev.o clock.o closure.o debug.o dirent.o error.o\
extents.o fs.o fs-gc.o inode.o io.o journal.o keybuf.o keylist.o\
- migrate.o move.o movinggc.o notify.o request.o siphash.o six.o stats.o\
- super.o sysfs.o tier.o trace.o util.o writeback.o xattr.o
+ migrate.o move.o movinggc.o notify.o opts.o request.o siphash.o six.o\
+ stats.o super.o sysfs.o tier.o trace.o util.o writeback.o xattr.o
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 57c8482d4d65..53dc0d4a5a95 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -265,7 +265,7 @@ static int bch_prio_write(struct cache *ca)
p->next_bucket = ca->prio_buckets[i + 1];
p->magic = pset_magic(&c->sb);
- SET_PSET_CSUM_TYPE(p, c->opts.meta_csum_type);
+ SET_PSET_CSUM_TYPE(p, c->opts.metadata_checksum);
p->csum = bch_checksum(PSET_CSUM_TYPE(p),
&p->magic,
bucket_bytes(ca) - 8);
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 8d1b0c0a8491..61b5213c9aba 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -461,6 +461,7 @@ struct cache_set {
struct list_head list;
struct kobject kobj;
struct kobject internal;
+ struct kobject opts_dir;
struct kobject time_stats;
struct completion *stop_completion;
unsigned long flags;
diff --git a/drivers/md/bcache/btree_io.c b/drivers/md/bcache/btree_io.c
index f3cc396cbb69..d901d144eb6d 100644
--- a/drivers/md/bcache/btree_io.c
+++ b/drivers/md/bcache/btree_io.c
@@ -528,7 +528,7 @@ static void do_btree_node_write(struct closure *cl)
i->version = BCACHE_BSET_VERSION;
- SET_BSET_CSUM_TYPE(i, c->opts.meta_csum_type);
+ SET_BSET_CSUM_TYPE(i, c->opts.metadata_checksum);
if (!b->written) {
BUG_ON(b->data->magic != bset_magic(&c->sb));
diff --git a/drivers/md/bcache/error.c b/drivers/md/bcache/error.c
index a0ca5ecbba7b..0a316ffd6966 100644
--- a/drivers/md/bcache/error.c
+++ b/drivers/md/bcache/error.c
@@ -6,7 +6,7 @@
void bch_inconsistent_error(struct cache_set *c)
{
- switch (c->opts.on_error_action) {
+ switch (c->opts.errors) {
case BCH_ON_ERROR_CONTINUE:
break;
case BCH_ON_ERROR_RO:
diff --git a/drivers/md/bcache/fs.c b/drivers/md/bcache/fs.c
index edd596a6900c..2ada741ecb11 100644
--- a/drivers/md/bcache/fs.c
+++ b/drivers/md/bcache/fs.c
@@ -18,7 +18,6 @@
#include <linux/migrate.h>
#include <linux/module.h>
#include <linux/mount.h>
-#include <linux/parser.h>
#include <linux/statfs.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/uio.h>
@@ -938,6 +937,9 @@ out:
if (ret)
return ret;
+ if (c->opts.journal_flush_disabled)
+ return 0;
+
return bch_journal_flush_seq(&c->journal, ei->journal_seq);
}
@@ -2021,6 +2023,9 @@ static int bch_vfs_write_inode(struct inode *inode,
ret = bch_write_inode(c, ei);
mutex_unlock(&ei->update_lock);
+ if (c->opts.journal_flush_disabled)
+ return ret;
+
if (!ret && wbc->sync_mode == WB_SYNC_ALL)
ret = bch_journal_flush_seq(&c->journal, ei->journal_seq);
@@ -2179,106 +2184,15 @@ err_unlock:
goto err;
}
-enum {
- Opt_err_action,
- Opt_meta_checksum,
- Opt_data_checksum,
- Opt_compression,
- Opt_acl, Opt_noacl,
- Opt_verbose_recovery,
- Opt_err
-};
-
-static const match_table_t tokens = {
- {Opt_err_action, "errors=%s"},
- {Opt_meta_checksum, "metadata_checksum=%s"},
- {Opt_data_checksum, "data_checksum=%s"},
- {Opt_compression, "compression=%s"},
- {Opt_verbose_recovery, "verbose_recovery"},
- {Opt_acl, "acl"},
- {Opt_noacl, "noacl"},
- {Opt_err, NULL}
-};
-
-static int parse_options(struct cache_set_opts *opts, int flags, char *options)
-{
- char *p;
- substring_t args[MAX_OPT_ARGS];
- char arg[80];
- ssize_t v;
-
- *opts = cache_set_opts_empty();
-
- opts->read_only = (flags & MS_RDONLY) != 0;
-
- if (!options)
- return 1;
-
- while ((p = strsep(&options, ",")) != NULL) {
- int token;
-
- if (!*p)
- continue;
-
- token = match_token(p, tokens, args);
- switch (token) {
- case Opt_err_action:
- match_strlcpy(arg, &args[0], sizeof(arg));
- v = bch_read_string_list(arg, bch_error_actions);
- if (v < 0)
- return 0;
-
- opts->on_error_action = v;
- break;
- case Opt_meta_checksum:
- match_strlcpy(arg, &args[0], sizeof(arg));
- v = bch_read_string_list(arg, bch_csum_types);
- if (v < 0)
- return 0;
-
- opts->meta_csum_type = v;
- break;
- case Opt_data_checksum:
- match_strlcpy(arg, &args[0], sizeof(arg));
- v = bch_read_string_list(arg, bch_csum_types);
- if (v < 0)
- return 0;
-
- opts->data_csum_type = v;
- break;
- case Opt_compression:
- match_strlcpy(arg, &args[0], sizeof(arg));
- v = bch_read_string_list(arg, bch_compression_types);
- if (v < 0)
- return 0;
-
- opts->compression_type = v;
- break;
- case Opt_verbose_recovery:
- opts->verbose_recovery = true;
- break;
- case Opt_acl:
- opts->posix_acl = true;
- break;
- case Opt_noacl:
- 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;
+ int ret;
- if (!parse_options(&opts, *flags, data))
- return EINVAL;
+ ret = bch_parse_options(&opts, *flags, data);
+ if (ret)
+ return ret;
mutex_lock(&bch_register_lock);
@@ -2304,8 +2218,8 @@ static int bch_remount(struct super_block *sb, int *flags, char *data)
c->opts.read_only = opts.read_only;
}
- if (opts.on_error_action >= 0)
- c->opts.on_error_action = opts.on_error_action;
+ if (opts.errors >= 0)
+ c->opts.errors = opts.errors;
unlock:
mutex_unlock(&bch_register_lock);
@@ -2351,8 +2265,9 @@ static struct dentry *bch_mount(struct file_system_type *fs_type,
unsigned i;
int ret;
- if (!parse_options(&opts, flags, data))
- return ERR_PTR(-EINVAL);
+ ret = bch_parse_options(&opts, flags, data);
+ if (ret)
+ return ERR_PTR(ret);
c = bch_open_as_blockdevs(dev_name, opts);
if (!c)
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index 9bf6766a90a1..ea00dbbc7242 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -691,8 +691,8 @@ static void bch_write_extent(struct bch_write_op *op,
struct bkey_i_extent *e = bkey_i_to_extent(k);
struct bch_extent_ptr *ptr;
unsigned ptrs_from = 0;
- unsigned csum_type = c->opts.data_csum_type;
- unsigned compression_type = c->opts.compression_type;
+ unsigned csum_type = c->opts.data_checksum;
+ unsigned compression_type = c->opts.compression;
/* don't refetch csum type/compression type */
barrier();
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index e432ee534ac7..8a7deb62c93e 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -1432,7 +1432,7 @@ static void journal_write_locked(struct closure *cl)
w->data->version = BCACHE_JSET_VERSION;
w->data->last_seq = last_seq(j);
- SET_JSET_CSUM_TYPE(w->data, c->opts.meta_csum_type);
+ SET_JSET_CSUM_TYPE(w->data, c->opts.metadata_checksum);
w->data->csum = csum_set(w->data, JSET_CSUM_TYPE(w->data));
sectors = set_blocks(w->data, block_bytes(c)) * c->sb.block_size;
diff --git a/drivers/md/bcache/opts.c b/drivers/md/bcache/opts.c
new file mode 100644
index 000000000000..d2b3a525aaf8
--- /dev/null
+++ b/drivers/md/bcache/opts.c
@@ -0,0 +1,138 @@
+
+#include <linux/kernel.h>
+
+#include "opts.h"
+#include "util.h"
+
+const char * const bch_bool_opt[] = {
+ "0",
+ "1",
+ NULL
+};
+
+const char * const bch_error_actions[] = {
+ "continue",
+ "remount-ro",
+ "panic",
+ NULL
+};
+
+const char * const bch_csum_types[] = {
+ "none",
+ "crc32c",
+ "crc64",
+ NULL
+};
+
+const char * const bch_compression_types[] = {
+ "none",
+ "lzo1x",
+ "gzip",
+ "xz",
+ NULL
+};
+
+enum bch_opts {
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ Opt_##_name,
+
+ CACHE_SET_VISIBLE_OPTS()
+#undef CACHE_SET_OPT
+
+ Opt_bad_opt,
+};
+
+struct bch_option {
+ const char *name;
+ const char * const *opts;
+};
+
+struct bch_opt_result {
+ enum bch_opts opt;
+ unsigned val;
+};
+
+static int parse_bool_opt(const struct bch_option *opt, const char *s)
+{
+ if (!strcmp(opt->name, s))
+ return true;
+
+ if (!strncmp("no", s, 2) && !strcmp(opt->name, s + 2))
+ return false;
+
+ return -1;
+}
+
+static int parse_string_opt(const struct bch_option *opt, const char *s)
+{
+ if (strncmp(opt->name, s, strlen(opt->name)))
+ return -1;
+
+ s += strlen(opt->name);
+
+ if (*s != '=')
+ return -1;
+
+ s++;
+
+ return bch_read_string_list(s, opt->opts);
+}
+
+static struct bch_opt_result parse_one_opt(const char *opt)
+{
+ static const struct bch_option opt_table[] = {
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ [Opt_##_name] = { .name = #_name, .opts = _options },
+
+ CACHE_SET_VISIBLE_OPTS()
+#undef CACHE_SET_OPT
+ }, *i;
+
+ for (i = opt_table;
+ i < opt_table + ARRAY_SIZE(opt_table);
+ i++) {
+ int res = i->opts == bch_bool_opt
+ ? parse_bool_opt(i, opt)
+ : parse_string_opt(i, opt);
+
+ if (res >= 0)
+ return (struct bch_opt_result) {
+ i - opt_table, res
+ };
+ }
+
+ return (struct bch_opt_result) { Opt_bad_opt };
+}
+
+int bch_parse_options(struct cache_set_opts *opts, int flags, char *options)
+{
+ char *p;
+
+ *opts = cache_set_opts_empty();
+
+ opts->read_only = (flags & MS_RDONLY) != 0;
+
+ if (!options)
+ return 0;
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ struct bch_opt_result res = parse_one_opt(p);
+
+ switch (res.opt) {
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ case Opt_##_name: \
+ opts->_name = res.val; \
+ break;
+
+ CACHE_SET_VISIBLE_OPTS()
+#undef CACHE_SET_OPT
+
+ case Opt_bad_opt:
+ return -EINVAL;
+ default:
+ BUG();
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/md/bcache/opts.h b/drivers/md/bcache/opts.h
index 9e919292a9f3..3a0a0daf95d0 100644
--- a/drivers/md/bcache/opts.h
+++ b/drivers/md/bcache/opts.h
@@ -1,25 +1,88 @@
#ifndef _BCACHE_OPTS_H
#define _BCACHE_OPTS_H
+#include <linux/bcache.h>
+#include <linux/string.h>
+
/*
+ * Mount options; we also store defaults in the superblock.
+ *
+ * Also exposed via sysfs: if an option is writeable, and it's also stored in
+ * the superblock, changing it via sysfs (currently? might change this) also
+ * updates the superblock.
+ *
* We store options as signed integers, where -1 means undefined. This means we
* can pass the mount options to cache_set_alloc() as a whole struct, and then
* only apply the options from that struct that are defined.
*/
-#define CACHE_SET_OPTS() \
- DEF_CACHE_SET_OPT(read_only, 2) \
- DEF_CACHE_SET_OPT(on_error_action, 3) \
- DEF_CACHE_SET_OPT(meta_csum_type, 4) \
- DEF_CACHE_SET_OPT(data_csum_type, 4) \
- DEF_CACHE_SET_OPT(compression_type, 4) \
- DEF_CACHE_SET_OPT(verbose_recovery, 2) \
- DEF_CACHE_SET_OPT(posix_acl, 2)
+extern const char * const bch_bool_opt[];
+extern const char * const bch_error_actions[];
+extern const char * const bch_csum_types[];
+extern const char * const bch_compression_types[];
+
+/* dummy option, for options that aren't stored in the superblock */
+BITMASK(NO_SB_OPT, struct cache_sb, flags, 0, 0);
+
+/**
+ * CACHE_SET_OPT(name, nr_bits, choices, sb_option, sysfs_writeable)
+ *
+ * @name - name of mount option, sysfs attribute, and struct cache_set_opts
+ * member
+ *
+ * @nr_bits - number of bits for cache_set_opts field, remember it's stored as a
+ * signed integer
+ *
+ * @choices - array of strings that the user can select from - option is by
+ * array index
+ *
+ * Booleans are special cased; if @choices is bch_bool_opt the mount
+ * options name and noname will work as expected.
+ *
+ * @sb_option - name of corresponding superblock option
+ *
+ * @sysfs_writeable - if true, option will be modifiable at runtime via sysfs
+ */
+
+#define CACHE_SET_VISIBLE_OPTS() \
+ CACHE_SET_OPT(errors, 3, \
+ bch_error_actions, \
+ CACHE_ERROR_ACTION, \
+ true) \
+ CACHE_SET_OPT(metadata_checksum, 4, \
+ bch_csum_types, \
+ CACHE_META_PREFERRED_CSUM_TYPE, \
+ true) \
+ CACHE_SET_OPT(data_checksum, 4, \
+ bch_csum_types, \
+ CACHE_DATA_PREFERRED_CSUM_TYPE, \
+ true) \
+ CACHE_SET_OPT(compression, 4, \
+ bch_compression_types, \
+ CACHE_COMPRESSION_TYPE, \
+ true) \
+ CACHE_SET_OPT(verbose_recovery, 2, \
+ bch_bool_opt, \
+ NO_SB_OPT, false) \
+ CACHE_SET_OPT(posix_acl, 2, \
+ bch_bool_opt, \
+ NO_SB_OPT, false) \
+ CACHE_SET_OPT(journal_flush_disabled, 2, \
+ bch_bool_opt, \
+ NO_SB_OPT, true)
+
+#define CACHE_SET_OPTS() \
+ CACHE_SET_OPT(read_only, 2, \
+ bch_bool_opt, \
+ NO_SB_OPT, 0) \
+ CACHE_SET_VISIBLE_OPTS()
struct cache_set_opts {
-#define DEF_CACHE_SET_OPT(opt, bits) int opt:bits;
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ int _name:_bits;
+
CACHE_SET_OPTS()
-#undef DEF_CACHE_SET_OPT
+#undef CACHE_SET_OPT
};
static inline struct cache_set_opts cache_set_opts_empty(void)
@@ -37,24 +100,25 @@ static inline struct cache_set_opts cache_set_opts_empty(void)
static inline struct cache_set_opts cache_superblock_opts(struct cache_sb *sb)
{
return (struct cache_set_opts) {
- .read_only = 0,
- .on_error_action = CACHE_ERROR_ACTION(sb),
- .meta_csum_type = CACHE_META_PREFERRED_CSUM_TYPE(sb),
- .data_csum_type = CACHE_DATA_PREFERRED_CSUM_TYPE(sb),
- .compression_type = CACHE_COMPRESSION_TYPE(sb),
- .verbose_recovery = 0,
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ ._name = _sb_opt##_BITS ? _sb_opt(sb) : 0,
+
+ CACHE_SET_OPTS()
+#undef CACHE_SET_OPT
};
}
static inline void cache_set_opts_apply(struct cache_set_opts *dst,
struct cache_set_opts src)
{
-#define DEF_CACHE_SET_OPT(opt, bits) \
- if (src.opt >= 0) \
- dst->opt = src.opt;
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ if (src._name >= 0) \
+ dst->_name = src._name;
CACHE_SET_OPTS()
-#undef DEF_CACHE_SET_OPT
+#undef CACHE_SET_OPT
}
+int bch_parse_options(struct cache_set_opts *, int, char *);
+
#endif /* _BCACHE_OPTS_H */
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 03f6d7891cf1..f093f9aa7289 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -47,28 +47,6 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kent Overstreet <kent.overstreet@gmail.com>");
-const char * const bch_error_actions[] = {
- "continue",
- "remount-ro",
- "panic",
- NULL
-};
-
-const char * const bch_csum_types[] = {
- "none",
- "crc32c",
- "crc64",
- NULL
-};
-
-const char * const bch_compression_types[] = {
- "none",
- "lzo1x",
- "gzip",
- "xz",
- NULL
-};
-
static const uuid_le invalid_uuid = {
.b = {
0xa0, 0x3e, 0xf8, 0xed, 0x3e, 0xe1, 0xb8, 0x78,
@@ -618,7 +596,7 @@ static void __bcache_write_super(struct cache_set *c)
cache_sb_from_cache_set(c, ca);
- SET_CACHE_SB_CSUM_TYPE(&ca->sb, c->opts.meta_csum_type);
+ SET_CACHE_SB_CSUM_TYPE(&ca->sb, c->opts.metadata_checksum);
bio_reset(bio);
bio->bi_bdev = ca->disk_sb.bdev;
@@ -925,6 +903,7 @@ static void cache_set_flush(struct closure *cl)
bch_cache_accounting_destroy(&c->accounting);
kobject_put(&c->time_stats);
+ kobject_put(&c->opts_dir);
kobject_put(&c->internal);
closure_return(cl);
@@ -1004,6 +983,7 @@ static struct cache_set *bch_cache_set_alloc(struct cache_sb *sb,
c->kobj.kset = bcache_kset;
kobject_init(&c->kobj, &bch_cache_set_ktype);
kobject_init(&c->internal, &bch_cache_set_internal_ktype);
+ kobject_init(&c->opts_dir, &bch_cache_set_opts_dir_ktype);
kobject_init(&c->time_stats, &bch_cache_set_time_stats_ktype);
bch_cache_accounting_init(&c->accounting, &c->cl);
@@ -1150,6 +1130,7 @@ static int bch_cache_set_online(struct cache_set *c)
if (kobject_add(&c->kobj, NULL, "%pU", c->sb.user_uuid.b) ||
kobject_add(&c->internal, &c->kobj, "internal") ||
+ kobject_add(&c->opts_dir, &c->kobj, "options") ||
kobject_add(&c->time_stats, &c->kobj, "time_stats") ||
bch_cache_accounting_add_kobjs(&c->accounting, &c->kobj))
return -1;
diff --git a/drivers/md/bcache/super.h b/drivers/md/bcache/super.h
index 5c5bfac42bd1..5493a5e4c9ee 100644
--- a/drivers/md/bcache/super.h
+++ b/drivers/md/bcache/super.h
@@ -109,10 +109,6 @@ u64 bch_checksum(unsigned, const void *, size_t);
bch_checksum(type, start, end - start); \
})
-extern const char * const bch_error_actions[];
-extern const char * const bch_csum_types[];
-extern const char * const bch_compression_types[];
-
void bch_check_mark_super_slowpath(struct cache_set *,
const struct bkey_i *, bool);
@@ -185,6 +181,7 @@ extern wait_queue_head_t unregister_wait;
extern struct kobj_type bch_cache_set_ktype;
extern struct kobj_type bch_cache_set_internal_ktype;
extern struct kobj_type bch_cache_set_time_stats_ktype;
+extern struct kobj_type bch_cache_set_opts_dir_ktype;
extern struct kobj_type bch_cache_ktype;
#endif /* _BCACHE_SUPER_H */
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 0ea4e22dee11..809d5a01ba8a 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -17,6 +17,7 @@
#include "journal.h"
#include "keylist.h"
#include "move.h"
+#include "opts.h"
#include "request.h"
#include "writeback.h"
@@ -109,6 +110,8 @@ read_attribute(cache_read_races);
read_attribute(writeback_keys_done);
read_attribute(writeback_keys_failed);
read_attribute(io_errors);
+rw_attribute(io_error_limit);
+rw_attribute(io_error_halflife);
read_attribute(congested);
rw_attribute(congested_read_threshold_us);
rw_attribute(congested_write_threshold_us);
@@ -128,13 +131,9 @@ rw_attribute(discard);
rw_attribute(running);
rw_attribute(label);
rw_attribute(readahead);
-rw_attribute(errors);
-rw_attribute(io_error_limit);
-rw_attribute(io_error_halflife);
rw_attribute(verify);
rw_attribute(bypass_torture_test);
rw_attribute(cache_replacement_policy);
-rw_attribute(checksum_type);
rw_attribute(foreground_write_ratelimit_enabled);
rw_attribute(copy_gc_enabled);
@@ -162,10 +161,21 @@ rw_attribute(data_replicas_want);
read_attribute(data_replicas_have);
read_attribute(tier);
-#define BCH_DEBUG_PARAM(name, description) rw_attribute(name);
+#define BCH_DEBUG_PARAM(name, description) \
+ rw_attribute(name);
+
BCH_DEBUG_PARAMS()
#undef BCH_DEBUG_PARAM
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _writeable) \
+ static struct attribute sysfs_opt_##_name = { \
+ .name = #_name, \
+ .mode = S_IRUGO|(_writeable ? S_IWUSR : 0) \
+ };
+
+ CACHE_SET_VISIBLE_OPTS()
+#undef CACHE_SET_OPT
+
#define BCH_TIME_STAT(name, frequency_units, duration_units) \
sysfs_time_stats_attribute(name, frequency_units, duration_units);
BCH_TIME_STATS()
@@ -666,15 +676,6 @@ SHOW(bch_cache_set)
sysfs_print(writeback_keys_failed,
atomic_long_read(&c->writeback_keys_failed));
- if (attr == &sysfs_checksum_type)
- return bch_snprint_string_list(buf, PAGE_SIZE,
- bch_csum_types,
- CACHE_META_PREFERRED_CSUM_TYPE(&c->sb));
-
- if (attr == &sysfs_errors)
- return bch_snprint_string_list(buf, PAGE_SIZE, bch_error_actions,
- CACHE_ERROR_ACTION(&c->sb));
-
/* See count_io_errors for why 88 */
sysfs_print(io_error_halflife, c->error_decay * 88);
sysfs_print(io_error_limit, c->error_limit >> IO_ERROR_SHIFT);
@@ -720,12 +721,6 @@ SHOW(bch_cache_set)
BCH_DEBUG_PARAMS()
#undef BCH_DEBUG_PARAM
-#define BCH_TIME_STAT(name, frequency_units, duration_units) \
- sysfs_print_time_stats(&c->name##_time, name, \
- frequency_units, duration_units);
- BCH_TIME_STATS()
-#undef BCH_TIME_STAT
-
if (!test_bit(CACHE_SET_RUNNING, &c->flags))
return -EPERM;
@@ -772,20 +767,6 @@ STORE(__bch_cache_set)
sysfs_strtoul(congested_write_threshold_us,
c->congested_write_threshold_us);
- if (attr == &sysfs_errors) {
- ssize_t v = bch_read_string_list(buf, bch_error_actions);
-
- if (v < 0)
- return v;
-
- if (v != CACHE_ERROR_ACTION(&c->sb)) {
- SET_CACHE_ERROR_ACTION(&c->sb, v);
- bcache_write_super(c);
- }
-
- return size;
- }
-
if (attr == &sysfs_io_error_limit) {
c->error_limit = strtoul_or_return(buf) << IO_ERROR_SHIFT;
return size;
@@ -797,11 +778,6 @@ STORE(__bch_cache_set)
return size;
}
-#define BCH_TIME_STAT(name, frequency_units, duration_units) \
- sysfs_clear_time_stats(&c->name##_time, name);
- BCH_TIME_STATS()
-#undef BCH_TIME_STAT
-
sysfs_strtoul(journal_delay_ms, c->journal.delay_ms);
sysfs_strtoul(foreground_write_ratelimit_enabled,
c->foreground_write_ratelimit_enabled);
@@ -877,20 +853,6 @@ STORE(__bch_cache_set)
if (test_bit(CACHE_SET_STOPPING, &c->flags))
return -EINTR;
- if (attr == &sysfs_checksum_type) {
- ssize_t v = bch_read_string_list(buf, bch_csum_types);
-
- if (v < 0)
- return v;
-
- if (v != CACHE_META_PREFERRED_CSUM_TYPE(&c->sb)) {
- SET_CACHE_META_PREFERRED_CSUM_TYPE(&c->sb, v);
- bcache_write_super(c);
- }
-
- return size;
- }
-
if (attr == &sysfs_blockdev_volume_create) {
u64 v = strtoi_h_or_return(buf);
int r = bch_blockdev_volume_create(c, v);
@@ -935,22 +897,6 @@ STORE(bch_cache_set)
return size;
}
-SHOW(bch_cache_set_internal)
-{
- struct cache_set *c = container_of(kobj, struct cache_set, internal);
- return bch_cache_set_show(&c->kobj, attr, buf);
-}
-
-STORE(bch_cache_set_internal)
-{
- struct cache_set *c = container_of(kobj, struct cache_set, internal);
- return bch_cache_set_store(&c->kobj, attr, buf, size);
-}
-
-static void bch_cache_set_internal_release(struct kobject *k)
-{
-}
-
static struct attribute *bch_cache_set_files[] = {
&sysfs_unregister,
&sysfs_stop,
@@ -970,7 +916,6 @@ static struct attribute *bch_cache_set_files[] = {
&sysfs_average_key_size,
- &sysfs_errors,
&sysfs_io_error_limit,
&sysfs_io_error_halflife,
&sysfs_congested,
@@ -978,7 +923,6 @@ static struct attribute *bch_cache_set_files[] = {
&sysfs_congested_write_threshold_us,
&sysfs_clear_stats,
- &sysfs_checksum_type,
&sysfs_meta_replicas_want,
&sysfs_meta_replicas_have,
&sysfs_data_replicas_want,
@@ -994,6 +938,24 @@ static struct attribute *bch_cache_set_files[] = {
};
KTYPE(bch_cache_set);
+/* internal dir - just a wrapper */
+
+SHOW(bch_cache_set_internal)
+{
+ struct cache_set *c = container_of(kobj, struct cache_set, internal);
+ return bch_cache_set_show(&c->kobj, attr, buf);
+}
+
+STORE(bch_cache_set_internal)
+{
+ struct cache_set *c = container_of(kobj, struct cache_set, internal);
+ return bch_cache_set_store(&c->kobj, attr, buf, size);
+}
+
+static void bch_cache_set_internal_release(struct kobject *k)
+{
+}
+
static struct attribute *bch_cache_set_internal_files[] = {
&sysfs_journal_debug,
@@ -1026,16 +988,92 @@ static struct attribute *bch_cache_set_internal_files[] = {
};
KTYPE(bch_cache_set_internal);
+/* options */
+
+SHOW(bch_cache_set_opts_dir)
+{
+ struct cache_set *c = container_of(kobj, struct cache_set, opts_dir);
+
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ if (attr == &sysfs_opt_##_name) \
+ return _options == bch_bool_opt \
+ ? snprintf(buf, PAGE_SIZE, "%i\n", c->opts._name)\
+ : bch_snprint_string_list(buf, PAGE_SIZE, \
+ _options, c->opts._name);\
+
+ CACHE_SET_VISIBLE_OPTS()
+#undef CACHE_SET_OPT
+
+ return 0;
+}
+
+STORE(bch_cache_set_opts_dir)
+{
+ struct cache_set *c = container_of(kobj, struct cache_set, opts_dir);
+
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ if (attr == &sysfs_opt_##_name) { \
+ ssize_t v = bch_read_string_list(buf, _options); \
+ \
+ if (v < 0) \
+ return v; \
+ \
+ c->opts._name = v; \
+ \
+ if (_sb_opt##_BITS && v != _sb_opt(&c->sb)) { \
+ SET_##_sb_opt(&c->sb, v); \
+ bcache_write_super(c); \
+ } \
+ \
+ return size; \
+ }
+
+ CACHE_SET_VISIBLE_OPTS()
+#undef CACHE_SET_OPT
+
+ return size;
+}
+
+static void bch_cache_set_opts_dir_release(struct kobject *k)
+{
+}
+
+static struct attribute *bch_cache_set_opts_dir_files[] = {
+#define CACHE_SET_OPT(_name, _bits, _options, _sb_opt, _perm) \
+ &sysfs_opt_##_name,
+
+ CACHE_SET_VISIBLE_OPTS()
+#undef CACHE_SET_OPT
+
+ NULL
+};
+KTYPE(bch_cache_set_opts_dir);
+
+/* time stats */
+
SHOW(bch_cache_set_time_stats)
{
struct cache_set *c = container_of(kobj, struct cache_set, time_stats);
- return bch_cache_set_show(&c->kobj, attr, buf);
+
+#define BCH_TIME_STAT(name, frequency_units, duration_units) \
+ sysfs_print_time_stats(&c->name##_time, name, \
+ frequency_units, duration_units);
+ BCH_TIME_STATS()
+#undef BCH_TIME_STAT
+
+ return 0;
}
STORE(bch_cache_set_time_stats)
{
struct cache_set *c = container_of(kobj, struct cache_set, time_stats);
- return bch_cache_set_store(&c->kobj, attr, buf, size);
+
+#define BCH_TIME_STAT(name, frequency_units, duration_units) \
+ sysfs_clear_time_stats(&c->name##_time, name);
+ BCH_TIME_STATS()
+#undef BCH_TIME_STAT
+
+ return size;
}
static void bch_cache_set_time_stats_release(struct kobject *k)