summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2017-10-09 11:59:09 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2018-01-30 20:40:37 -0500
commit8e8ede1b090e86d34af8ecaebc0e4af5e8093cb4 (patch)
treed398ed87727279e6275af02fcdb2519035258446
parent261286b854e2bafb0517b58a6b989f9f2e00f8b7 (diff)
bcachefs: Option code improvements
-rw-r--r--fs/bcachefs/Kconfig11
-rw-r--r--fs/bcachefs/acl.c4
-rw-r--r--fs/bcachefs/acl.h11
-rw-r--r--fs/bcachefs/bcachefs.h5
-rw-r--r--fs/bcachefs/bcachefs_format.h36
-rw-r--r--fs/bcachefs/btree_cache.h4
-rw-r--r--fs/bcachefs/btree_gc.c4
-rw-r--r--fs/bcachefs/btree_io.c8
-rw-r--r--fs/bcachefs/btree_update_interior.c18
-rw-r--r--fs/bcachefs/btree_update_interior.h2
-rw-r--r--fs/bcachefs/compress.c2
-rw-r--r--fs/bcachefs/extents.c2
-rw-r--r--fs/bcachefs/fs.c56
-rw-r--r--fs/bcachefs/inode.c2
-rw-r--r--fs/bcachefs/journal.c6
-rw-r--r--fs/bcachefs/opts.c148
-rw-r--r--fs/bcachefs/opts.h241
-rw-r--r--fs/bcachefs/super-io.c13
-rw-r--r--fs/bcachefs/super.c16
-rw-r--r--fs/bcachefs/sysfs.c54
-rw-r--r--fs/bcachefs/sysfs.h4
21 files changed, 374 insertions, 273 deletions
diff --git a/fs/bcachefs/Kconfig b/fs/bcachefs/Kconfig
index ab11eeea98da..6401122ea1fb 100644
--- a/fs/bcachefs/Kconfig
+++ b/fs/bcachefs/Kconfig
@@ -20,11 +20,16 @@ config BCACHEFS_FS
The bcachefs filesystem - a modern, copy on write filesystem, with
support for multiple devices, compression, checksumming, etc.
+config BCACHEFS_POSIX_ACL
+ bool "bcachefs POSIX ACL support"
+ depends on BCACHEFS_FS
+ select FS_POSIX_ACL
+
config BCACHEFS_DEBUG
bool "bcachefs debugging"
depends on BCACHEFS_FS
---help---
- Don't select this option unless you're a developer
+ Enables many extra debugging checks and assertions.
- Enables extra debugging tools, allows expensive runtime checks to be
- turned on.
+ The resulting code will be significantly slower than normal; you
+ probably shouldn't select this option unless you're a developer.
diff --git a/fs/bcachefs/acl.c b/fs/bcachefs/acl.c
index 6b155d8399ea..2dda0debaeb9 100644
--- a/fs/bcachefs/acl.c
+++ b/fs/bcachefs/acl.c
@@ -1,4 +1,4 @@
-#ifndef NO_BCACHEFS_FS
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
#include "bcachefs.h"
@@ -227,4 +227,4 @@ int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return ret;
}
-#endif /* NO_BCACHEFS_FS */
+#endif /* CONFIG_BCACHEFS_POSIX_ACL */
diff --git a/fs/bcachefs/acl.h b/fs/bcachefs/acl.h
index 539bca7ec4a0..b721330e2837 100644
--- a/fs/bcachefs/acl.h
+++ b/fs/bcachefs/acl.h
@@ -1,7 +1,7 @@
#ifndef _BCACHEFS_ACL_H
#define _BCACHEFS_ACL_H
-#ifndef NO_BCACHEFS_FS
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
#define BCH_ACL_VERSION 0x0001
@@ -54,6 +54,13 @@ struct posix_acl;
extern struct posix_acl *bch2_get_acl(struct inode *, int);
extern int bch2_set_acl(struct inode *, struct posix_acl *, int);
-#endif /* NO_BCACHEFS_FS */
+#else
+
+static inline int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+ return 0;
+}
+
+#endif /* CONFIG_BCACHEFS_POSIX_ACL */
#endif /* _BCACHEFS_ACL_H */
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index 06b1ee4447d6..945f03ca4c02 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -518,14 +518,11 @@ struct bch_fs {
uuid_le uuid;
uuid_le user_uuid;
- u16 block_size;
- u16 btree_node_size;
u16 encoded_extent_max;
u8 nr_devices;
u8 clean;
- u8 str_hash_type;
u8 encryption_type;
u64 time_base_lo;
@@ -795,7 +792,7 @@ static inline unsigned bucket_bytes(const struct bch_dev *ca)
static inline unsigned block_bytes(const struct bch_fs *c)
{
- return c->sb.block_size << 9;
+ return c->opts.block_size << 9;
}
#endif /* _BCACHEFS_H */
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h
index 463789d65b37..547a4e0bc8f0 100644
--- a/fs/bcachefs/bcachefs_format.h
+++ b/fs/bcachefs/bcachefs_format.h
@@ -9,45 +9,29 @@
#include <asm/byteorder.h>
#include <linux/uuid.h>
-#define LE32_BITMASK(name, type, field, offset, end) \
+#define LE_BITMASK(_bits, name, type, field, offset, end) \
static const unsigned name##_OFFSET = offset; \
static const unsigned name##_BITS = (end - offset); \
-static const __u64 name##_MAX = (1ULL << (end - offset)) - 1; \
+static const __u##_bits name##_MAX = (1ULL << (end - offset)) - 1; \
\
static inline __u64 name(const type *k) \
{ \
- return (__le32_to_cpu(k->field) >> offset) & \
+ return (__le##_bits##_to_cpu(k->field) >> offset) & \
~(~0ULL << (end - offset)); \
} \
\
static inline void SET_##name(type *k, __u64 v) \
{ \
- __u64 new = __le32_to_cpu(k->field); \
+ __u##_bits new = __le##_bits##_to_cpu(k->field); \
\
new &= ~(~(~0ULL << (end - offset)) << offset); \
new |= (v & ~(~0ULL << (end - offset))) << offset; \
- k->field = __cpu_to_le32(new); \
+ k->field = __cpu_to_le##_bits(new); \
}
-#define LE64_BITMASK(name, type, field, offset, end) \
-static const unsigned name##_OFFSET = offset; \
-static const unsigned name##_BITS = (end - offset); \
-static const __u64 name##_MAX = (1ULL << (end - offset)) - 1; \
- \
-static inline __u64 name(const type *k) \
-{ \
- return (__le64_to_cpu(k->field) >> offset) & \
- ~(~0ULL << (end - offset)); \
-} \
- \
-static inline void SET_##name(type *k, __u64 v) \
-{ \
- __u64 new = __le64_to_cpu(k->field); \
- \
- new &= ~(~(~0ULL << (end - offset)) << offset); \
- new |= (v & ~(~0ULL << (end - offset))) << offset; \
- k->field = __cpu_to_le64(new); \
-}
+#define LE16_BITMASK(n, t, f, o, e) LE_BITMASK(16, n, t, f, o, e)
+#define LE32_BITMASK(n, t, f, o, e) LE_BITMASK(32, n, t, f, o, e)
+#define LE64_BITMASK(n, t, f, o, e) LE_BITMASK(64, n, t, f, o, e)
struct bkey_format {
__u8 key_u64s;
@@ -960,6 +944,8 @@ struct bch_sb {
* algorithm in use, if/when we get more than one
*/
+LE16_BITMASK(BCH_SB_BLOCK_SIZE, struct bch_sb, block_size, 0, 16);
+
LE64_BITMASK(BCH_SB_INITIALIZED, struct bch_sb, flags[0], 0, 1);
LE64_BITMASK(BCH_SB_CLEAN, struct bch_sb, flags[0], 1, 2);
LE64_BITMASK(BCH_SB_CSUM_TYPE, struct bch_sb, flags[0], 2, 8);
@@ -976,7 +962,7 @@ LE64_BITMASK(BCH_SB_DATA_CSUM_TYPE, struct bch_sb, flags[0], 44, 48);
LE64_BITMASK(BCH_SB_META_REPLICAS_WANT, struct bch_sb, flags[0], 48, 52);
LE64_BITMASK(BCH_SB_DATA_REPLICAS_WANT, struct bch_sb, flags[0], 52, 56);
-/* 56-64 unused, was REPLICAS_HAVE */
+LE64_BITMASK(BCH_SB_POSIX_ACL, struct bch_sb, flags[0], 56, 57);
LE64_BITMASK(BCH_SB_STR_HASH_TYPE, struct bch_sb, flags[1], 0, 4);
LE64_BITMASK(BCH_SB_COMPRESSION_TYPE, struct bch_sb, flags[1], 4, 8);
diff --git a/fs/bcachefs/btree_cache.h b/fs/bcachefs/btree_cache.h
index ce10a4a9fb60..5e836acda5d6 100644
--- a/fs/bcachefs/btree_cache.h
+++ b/fs/bcachefs/btree_cache.h
@@ -51,7 +51,7 @@ static inline bool btree_node_hashed(struct btree *b)
static inline size_t btree_bytes(struct bch_fs *c)
{
- return c->sb.btree_node_size << 9;
+ return c->opts.btree_node_size << 9;
}
static inline size_t btree_max_u64s(struct bch_fs *c)
@@ -71,7 +71,7 @@ static inline size_t btree_pages(struct bch_fs *c)
static inline unsigned btree_blocks(struct bch_fs *c)
{
- return c->sb.btree_node_size >> c->block_bits;
+ return c->opts.btree_node_size >> c->block_bits;
}
#define BTREE_SPLIT_THRESHOLD(c) (btree_blocks(c) * 3 / 4)
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c
index 2bd2887a7b70..302546f2c2ab 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -116,7 +116,7 @@ static u8 bch2_btree_mark_key(struct bch_fs *c, enum bkey_type type,
{
switch (type) {
case BKEY_TYPE_BTREE:
- bch2_gc_mark_key(c, k, c->sb.btree_node_size, true, flags);
+ bch2_gc_mark_key(c, k, c->opts.btree_node_size, true, flags);
return 0;
case BKEY_TYPE_EXTENTS:
bch2_gc_mark_key(c, k, k.k->size, false, flags);
@@ -386,7 +386,7 @@ static void bch2_mark_pending_btree_node_frees(struct bch_fs *c)
for_each_pending_btree_node_free(c, as, d)
if (d->index_update_done)
__bch2_mark_key(c, bkey_i_to_s_c(&d->key),
- c->sb.btree_node_size, true,
+ c->opts.btree_node_size, true,
&stats, 0,
BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE);
/*
diff --git a/fs/bcachefs/btree_io.c b/fs/bcachefs/btree_io.c
index 4e9797f316b1..730ebc43d68d 100644
--- a/fs/bcachefs/btree_io.c
+++ b/fs/bcachefs/btree_io.c
@@ -916,7 +916,7 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
return 0;
}
- if (b->written + sectors > c->sb.btree_node_size) {
+ if (b->written + sectors > c->opts.btree_node_size) {
btree_node_error(c, b, "bset past end of btree node");
i->u64s = 0;
return 0;
@@ -1034,7 +1034,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b)
if (bch2_meta_read_fault("btree"))
goto err;
- while (b->written < c->sb.btree_node_size) {
+ while (b->written < c->opts.btree_node_size) {
unsigned sectors, whiteout_u64s = 0;
if (!b->written) {
@@ -1528,7 +1528,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
BUG_ON(!list_empty(&b->write_blocked));
BUG_ON((b->will_make_reachable != NULL) != !b->written);
- BUG_ON(b->written >= c->sb.btree_node_size);
+ BUG_ON(b->written >= c->opts.btree_node_size);
BUG_ON(bset_written(b, btree_bset_last(b)));
BUG_ON(le64_to_cpu(b->data->magic) != bset_magic(c));
BUG_ON(memcmp(&b->data->format, &b->format, sizeof(b->format)));
@@ -1612,7 +1612,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
memset(data + bytes_to_write, 0,
(sectors_to_write << 9) - bytes_to_write);
- BUG_ON(b->written + sectors_to_write > c->sb.btree_node_size);
+ BUG_ON(b->written + sectors_to_write > c->opts.btree_node_size);
BUG_ON(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN);
BUG_ON(i->seq != b->data->keys.seq);
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index 98e856274535..922a48635a6a 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -181,7 +181,7 @@ found:
*/
replicas = bch2_extent_nr_dirty_ptrs(k);
if (replicas)
- stats->s[replicas - 1].data[S_META] -= c->sb.btree_node_size;
+ stats->s[replicas - 1].data[S_META] -= c->opts.btree_node_size;
/*
* We're dropping @k from the btree, but it's still live until the
@@ -208,7 +208,7 @@ found:
struct bch_fs_usage tmp = { 0 };
bch2_mark_key(c, bkey_i_to_s_c(&d->key),
- -c->sb.btree_node_size, true, b
+ -c->opts.btree_node_size, true, b
? gc_pos_btree_node(b)
: gc_pos_btree_root(as->btree_id),
&tmp, 0);
@@ -285,7 +285,7 @@ static void bch2_btree_node_free_ondisk(struct bch_fs *c,
BUG_ON(!pending->index_update_done);
bch2_mark_key(c, bkey_i_to_s_c(&pending->key),
- -c->sb.btree_node_size, true,
+ -c->opts.btree_node_size, true,
gc_phase(GC_PHASE_PENDING_DELETE),
&stats, 0);
/*
@@ -337,7 +337,7 @@ static struct btree *__bch2_btree_node_alloc(struct bch_fs *c,
retry:
/* alloc_sectors is weird, I suppose */
bkey_extent_init(&tmp.k);
- tmp.k.k.size = c->sb.btree_node_size,
+ tmp.k.k.size = c->opts.btree_node_size,
ob = bch2_alloc_sectors(c, &c->btree_write_point,
bkey_i_to_extent(&tmp.k),
@@ -347,7 +347,7 @@ retry:
if (IS_ERR(ob))
return ERR_CAST(ob);
- if (tmp.k.k.size < c->sb.btree_node_size) {
+ if (tmp.k.k.size < c->opts.btree_node_size) {
bch2_open_bucket_put(c, ob);
goto retry;
}
@@ -491,7 +491,7 @@ static struct btree_reserve *bch2_btree_reserve_get(struct bch_fs *c,
struct btree_reserve *reserve;
struct btree *b;
struct disk_reservation disk_res = { 0, 0 };
- unsigned sectors = nr_nodes * c->sb.btree_node_size;
+ unsigned sectors = nr_nodes * c->opts.btree_node_size;
int ret, disk_res_flags = BCH_DISK_RESERVATION_GC_LOCK_HELD|
BCH_DISK_RESERVATION_METADATA;
@@ -1035,7 +1035,7 @@ static void bch2_btree_set_root_inmem(struct btree_update *as, struct btree *b)
__bch2_btree_set_root_inmem(c, b);
bch2_mark_key(c, bkey_i_to_s_c(&b->key),
- c->sb.btree_node_size, true,
+ c->opts.btree_node_size, true,
gc_pos_btree_root(b->btree_id),
&stats, 0);
@@ -1120,7 +1120,7 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as, struct btree *b
if (bkey_extent_is_data(&insert->k))
bch2_mark_key(c, bkey_i_to_s_c(insert),
- c->sb.btree_node_size, true,
+ c->opts.btree_node_size, true,
gc_pos_btree_node(b), &stats, 0);
while ((k = bch2_btree_node_iter_peek_all(node_iter, b)) &&
@@ -1901,7 +1901,7 @@ retry:
bch2_btree_node_lock_write(b, &iter);
bch2_mark_key(c, bkey_i_to_s_c(&new_key->k_i),
- c->sb.btree_node_size, true,
+ c->opts.btree_node_size, true,
gc_pos_btree_root(b->btree_id),
&stats, 0);
bch2_btree_node_free_index(as, NULL,
diff --git a/fs/bcachefs/btree_update_interior.h b/fs/bcachefs/btree_update_interior.h
index 8f75963bb3ba..e129b24ece76 100644
--- a/fs/bcachefs/btree_update_interior.h
+++ b/fs/bcachefs/btree_update_interior.h
@@ -263,7 +263,7 @@ static inline size_t bch_btree_keys_u64s_remaining(struct bch_fs *c,
unsigned used = bset_byte_offset(b, vstruct_end(i)) / sizeof(u64) +
b->whiteout_u64s +
b->uncompacted_whiteout_u64s;
- unsigned total = c->sb.btree_node_size << 6;
+ unsigned total = c->opts.btree_node_size << 6;
EBUG_ON(used > total);
diff --git a/fs/bcachefs/compress.c b/fs/bcachefs/compress.c
index fba36c8276a5..c8a03c7f9971 100644
--- a/fs/bcachefs/compress.c
+++ b/fs/bcachefs/compress.c
@@ -423,7 +423,7 @@ void bch2_bio_compress(struct bch_fs *c,
/* If it's only one block, don't bother trying to compress: */
if (*compression_type != BCH_COMPRESSION_NONE &&
- bio_sectors(src) > c->sb.block_size &&
+ bio_sectors(src) > c->opts.block_size &&
!__bio_compress(c, dst, dst_len, src, src_len, compression_type))
goto out;
diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c
index 33d7e9e28b90..7c641bdab2e2 100644
--- a/fs/bcachefs/extents.c
+++ b/fs/bcachefs/extents.c
@@ -575,7 +575,7 @@ static const char *bch2_btree_ptr_invalid(const struct bch_fs *c,
extent_for_each_ptr_crc(e, ptr, crc) {
reason = extent_ptr_invalid(c, e, ptr,
- c->sb.btree_node_size,
+ c->opts.btree_node_size,
true);
if (reason)
return reason;
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 72132a8e90fe..6a62ec86b262 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -219,11 +219,13 @@ static struct inode *bch2_vfs_inode_create(struct bch_fs *c,
inode_init_owner(inode, parent, mode);
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
ret = posix_acl_create(parent, &inode->i_mode, &default_acl, &acl);
if (ret) {
make_bad_inode(inode);
goto err;
}
+#endif
ei = to_bch_ei(inode);
@@ -957,8 +959,10 @@ static const struct inode_operations bch_file_inode_operations = {
.setattr = bch2_setattr,
.fiemap = bch2_fiemap,
.listxattr = bch2_xattr_list,
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
.get_acl = bch2_get_acl,
.set_acl = bch2_set_acl,
+#endif
};
static const struct inode_operations bch_dir_inode_operations = {
@@ -974,8 +978,10 @@ static const struct inode_operations bch_dir_inode_operations = {
.setattr = bch2_setattr,
.tmpfile = bch2_tmpfile,
.listxattr = bch2_xattr_list,
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
.get_acl = bch2_get_acl,
.set_acl = bch2_set_acl,
+#endif
};
static const struct file_operations bch_dir_file_operations = {
@@ -993,15 +999,19 @@ static const struct inode_operations bch_symlink_inode_operations = {
.get_link = page_get_link,
.setattr = bch2_setattr,
.listxattr = bch2_xattr_list,
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
.get_acl = bch2_get_acl,
.set_acl = bch2_set_acl,
+#endif
};
static const struct inode_operations bch_special_inode_operations = {
.setattr = bch2_setattr,
.listxattr = bch2_xattr_list,
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
.get_acl = bch2_get_acl,
.set_acl = bch2_set_acl,
+#endif
};
static const struct address_space_operations bch_address_space_operations = {
@@ -1305,14 +1315,13 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
struct bch_opts opts = bch2_opts_empty();
int ret;
- opts.read_only = (*flags & MS_RDONLY) != 0;
+ opt_set(opts, read_only, (*flags & MS_RDONLY) != 0);
ret = bch2_parse_mount_opts(&opts, data);
if (ret)
return ret;
- if (opts.read_only >= 0 &&
- opts.read_only != c->opts.read_only) {
+ if (opts.read_only != c->opts.read_only) {
const char *err = NULL;
mutex_lock(&c->state_lock);
@@ -1342,6 +1351,38 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
return ret;
}
+static int bch2_show_options(struct seq_file *seq, struct dentry *root)
+{
+ struct bch_fs *c = root->d_sb->s_fs_info;
+ enum bch_opt_id i;
+
+ for (i = 0; i < bch2_opts_nr; i++) {
+ const struct bch_option *opt = &bch2_opt_table[i];
+ u64 v = bch2_opt_get_by_id(&c->opts, i);
+
+ if (opt->mode < OPT_MOUNT)
+ continue;
+
+ if (v == bch2_opt_get_by_id(&bch2_opts_default, i))
+ continue;
+
+ switch (opt->type) {
+ case BCH_OPT_BOOL:
+ seq_printf(seq, ",%s%s", v ? "" : "no", opt->attr.name);
+ break;
+ case BCH_OPT_UINT:
+ seq_printf(seq, ",%s=%llu", opt->attr.name, v);
+ break;
+ case BCH_OPT_STR:
+ seq_printf(seq, ",%s=%s", opt->attr.name, opt->choices[v]);
+ break;
+ }
+ }
+
+ return 0;
+
+}
+
static const struct super_operations bch_super_operations = {
.alloc_inode = bch2_alloc_inode,
.destroy_inode = bch2_destroy_inode,
@@ -1349,6 +1390,7 @@ static const struct super_operations bch_super_operations = {
.evict_inode = bch2_evict_inode,
.sync_fs = bch2_sync_fs,
.statfs = bch2_statfs,
+ .show_options = bch2_show_options,
.remount_fs = bch2_remount,
#if 0
.put_super = bch2_put_super,
@@ -1379,7 +1421,7 @@ static struct dentry *bch2_mount(struct file_system_type *fs_type,
unsigned i;
int ret;
- opts.read_only = (flags & MS_RDONLY) != 0;
+ opt_set(opts, read_only, (flags & MS_RDONLY) != 0);
ret = bch2_parse_mount_opts(&opts, data);
if (ret)
@@ -1437,10 +1479,10 @@ static struct dentry *bch2_mount(struct file_system_type *fs_type,
break;
}
- if (opts.posix_acl < 0)
+#ifdef CONFIG_BCACHEFS_POSIX_ACL
+ if (c->opts.acl)
sb->s_flags |= MS_POSIXACL;
- else
- sb->s_flags |= opts.posix_acl ? MS_POSIXACL : 0;
+#endif
inode = bch2_vfs_inode_get(sb, BCACHEFS_ROOT_INO);
if (IS_ERR(inode)) {
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index 2fb7760cb7de..511ce803782d 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -251,7 +251,7 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
memset(inode_u, 0, sizeof(*inode_u));
/* ick */
- inode_u->i_flags |= c->sb.str_hash_type << INODE_STR_HASH_OFFSET;
+ inode_u->i_flags |= c->opts.str_hash << INODE_STR_HASH_OFFSET;
get_random_bytes(&inode_u->i_hash_seed, sizeof(inode_u->i_hash_seed));
inode_u->i_mode = mode;
diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c
index b10714697f46..7018b9738a6e 100644
--- a/fs/bcachefs/journal.c
+++ b/fs/bcachefs/journal.c
@@ -700,11 +700,11 @@ reread: sectors_read = min_t(unsigned,
case JOURNAL_ENTRY_NONE:
if (!saw_bad)
return 0;
- sectors = c->sb.block_size;
+ sectors = c->opts.block_size;
goto next_block;
case JOURNAL_ENTRY_BAD:
saw_bad = true;
- sectors = c->sb.block_size;
+ sectors = c->opts.block_size;
goto next_block;
default:
return ret;
@@ -1192,7 +1192,7 @@ static enum {
j->prev_buf_sectors =
vstruct_blocks_plus(buf->data, c->block_bits,
journal_entry_u64s_reserve(buf)) *
- c->sb.block_size;
+ c->opts.block_size;
BUG_ON(j->prev_buf_sectors > j->cur_buf_sectors);
diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c
index b5ae5aeb8bfc..c9482151d425 100644
--- a/fs/bcachefs/opts.c
+++ b/fs/bcachefs/opts.c
@@ -66,42 +66,24 @@ const char * const bch2_dev_state[] = {
NULL
};
-const struct bch_option bch2_opt_table[] = {
-#define OPT_BOOL() .type = BCH_OPT_BOOL
-#define OPT_UINT(_min, _max) .type = BCH_OPT_UINT, .min = _min, .max = _max
-#define OPT_STR(_choices) .type = BCH_OPT_STR, .choices = _choices
-
-#define BCH_OPT(_name, _mode, _sb_opt, _bits, _type) \
- [Opt_##_name] = { \
- .name = #_name, \
- .set_sb = SET_##_sb_opt, \
- _type \
- },
- BCH_VISIBLE_OPTS()
-#undef BCH_OPT
-};
-
-static int bch2_opt_lookup(const char *name)
+void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
{
- const struct bch_option *i;
-
- for (i = bch2_opt_table;
- i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);
- i++)
- if (!strcmp(name, i->name))
- return i - bch2_opt_table;
+#define BCH_OPT(_name, ...) \
+ if (opt_defined(src, _name)) \
+ opt_set(*dst, _name, src._name);
- return -1;
+ BCH_OPTS()
+#undef BCH_OPT
}
-static u64 bch2_opt_get(struct bch_opts *opts, enum bch_opt_id id)
+u64 bch2_opt_get_by_id(const struct bch_opts *opts, enum bch_opt_id id)
{
switch (id) {
#define BCH_OPT(_name, ...) \
case Opt_##_name: \
return opts->_name; \
- BCH_VISIBLE_OPTS()
+ BCH_OPTS()
#undef BCH_OPT
default:
@@ -109,15 +91,15 @@ static u64 bch2_opt_get(struct bch_opts *opts, enum bch_opt_id id)
}
}
-void bch2_opt_set(struct bch_opts *opts, enum bch_opt_id id, u64 v)
+void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
{
switch (id) {
#define BCH_OPT(_name, ...) \
case Opt_##_name: \
- opts->_name = v; \
+ opt_set(*opts, _name, v); \
break;
- BCH_VISIBLE_OPTS()
+ BCH_OPTS()
#undef BCH_OPT
default:
@@ -129,13 +111,13 @@ void bch2_opt_set(struct bch_opts *opts, enum bch_opt_id id, u64 v)
* Initial options from superblock - here we don't want any options undefined,
* any options the superblock doesn't specify are set to 0:
*/
-struct bch_opts bch2_sb_opts(struct bch_sb *sb)
+struct bch_opts bch2_opts_from_sb(struct bch_sb *sb)
{
struct bch_opts opts = bch2_opts_empty();
-#define BCH_OPT(_name, _mode, _sb_opt, ...) \
+#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default) \
if (_sb_opt != NO_SB_OPT) \
- opts._name = _sb_opt(sb);
+ opt_set(opts, _name, _sb_opt(sb));
BCH_OPTS()
#undef BCH_OPT
@@ -143,9 +125,41 @@ struct bch_opts bch2_sb_opts(struct bch_sb *sb)
return opts;
}
-static int parse_one_opt(enum bch_opt_id id, const char *val, u64 *res)
+const struct bch_option bch2_opt_table[] = {
+#define OPT_BOOL() .type = BCH_OPT_BOOL
+#define OPT_UINT(_min, _max) .type = BCH_OPT_UINT, .min = _min, .max = _max
+#define OPT_STR(_choices) .type = BCH_OPT_STR, .choices = _choices
+
+#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default) \
+ [Opt_##_name] = { \
+ .attr = { \
+ .name = #_name, \
+ .mode = _mode == OPT_RUNTIME ? 0644 : 0444, \
+ }, \
+ .mode = _mode, \
+ .set_sb = SET_##_sb_opt, \
+ _type \
+ },
+
+ BCH_OPTS()
+#undef BCH_OPT
+};
+
+static int bch2_opt_lookup(const char *name)
+{
+ const struct bch_option *i;
+
+ for (i = bch2_opt_table;
+ i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);
+ i++)
+ if (!strcmp(name, i->attr.name))
+ return i - bch2_opt_table;
+
+ return -1;
+}
+
+int bch2_opt_parse(const struct bch_option *opt, const char *val, u64 *res)
{
- const struct bch_option *opt = &bch2_opt_table[id];
ssize_t ret;
switch (opt->type) {
@@ -190,11 +204,11 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
if (val) {
id = bch2_opt_lookup(name);
if (id < 0)
- continue;
+ goto bad_opt;
- ret = parse_one_opt(id, val, &v);
+ ret = bch2_opt_parse(&bch2_opt_table[id], val, &v);
if (ret < 0)
- return ret;
+ goto bad_val;
} else {
id = bch2_opt_lookup(name);
v = 1;
@@ -205,47 +219,31 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
v = 0;
}
- if (id < 0 ||
- bch2_opt_table[id].type != BCH_OPT_BOOL)
- continue;
- }
-
- bch2_opt_set(opts, id, v);
- }
-
- return 0;
-}
-
-enum bch_opt_id bch2_parse_sysfs_opt(const char *name, const char *val,
- u64 *res)
-{
- int id = bch2_opt_lookup(name);
- int ret;
-
- if (id < 0)
- return -EINVAL;
-
- ret = parse_one_opt(id, val, res);
- if (ret < 0)
- return ret;
+ if (id < 0)
+ goto bad_opt;
- return id;
-}
+ if (bch2_opt_table[id].type != BCH_OPT_BOOL)
+ goto no_val;
+ }
-ssize_t bch2_opt_show(struct bch_opts *opts, const char *name,
- char *buf, size_t size)
-{
- int id = bch2_opt_lookup(name);
- const struct bch_option *opt;
- u64 v;
+ if (bch2_opt_table[id].mode < OPT_MOUNT)
+ goto bad_opt;
- if (id < 0)
- return -EINVAL;
+ if (id == Opt_acl &&
+ !IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))
+ goto bad_opt;
- v = bch2_opt_get(opts, id);
- opt = &bch2_opt_table[id];
+ bch2_opt_set_by_id(opts, id, v);
+ }
- return opt->type == BCH_OPT_STR
- ? bch2_scnprint_string_list(buf, size, opt->choices, v)
- : scnprintf(buf, size, "%lli", v);
+ return 0;
+bad_opt:
+ pr_err("Bad mount option %s", name);
+ return -1;
+bad_val:
+ pr_err("Invalid value %s for mount option %s", val, name);
+ return -1;
+no_val:
+ pr_err("Mount option %s requires a value", name);
+ return -1;
}
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index 667f629e9ae5..33e3a2c89f1b 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -4,6 +4,7 @@
#include <linux/bug.h>
#include <linux/log2.h>
#include <linux/string.h>
+#include <linux/sysfs.h>
#include "bcachefs_format.h"
extern const char * const bch2_error_actions[];
@@ -30,101 +31,175 @@ extern const char * const bch2_dev_state[];
/* dummy option, for options that aren't stored in the superblock */
LE64_BITMASK(NO_SB_OPT, struct bch_sb, flags[0], 0, 0);
+enum opt_mode {
+ OPT_INTERNAL,
+ OPT_FORMAT,
+ OPT_MOUNT,
+ OPT_RUNTIME,
+};
+
+enum opt_type {
+ BCH_OPT_BOOL,
+ BCH_OPT_UINT,
+ BCH_OPT_STR,
+};
+
/**
- * BCH_OPT(name, mode, sb_opt, type, ...)
+ * BCH_OPT(name, type, in mem type, mode, sb_opt)
*
* @name - name of mount option, sysfs attribute, and struct bch_opts
* member
*
- * @mode - sysfs attr permissions
+ * @mode - when opt may be set
*
* @sb_option - name of corresponding superblock option
*
* @type - one of OPT_BOOL, OPT_UINT, OPT_STR
*/
-enum opt_type {
- BCH_OPT_BOOL,
- BCH_OPT_UINT,
- BCH_OPT_STR,
-};
-
-#define BCH_VISIBLE_OPTS() \
- BCH_OPT(errors, 0644, BCH_SB_ERROR_ACTION, \
- s8, OPT_STR(bch2_error_actions)) \
- BCH_OPT(metadata_replicas, 0444, BCH_SB_META_REPLICAS_WANT,\
- s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
- BCH_OPT(data_replicas, 0444, BCH_SB_DATA_REPLICAS_WANT,\
- s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
- BCH_OPT(metadata_replicas_required, 0444, BCH_SB_META_REPLICAS_REQ,\
- s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
- BCH_OPT(data_replicas_required, 0444, BCH_SB_DATA_REPLICAS_REQ,\
- s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
- BCH_OPT(degraded, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(metadata_checksum, 0644, BCH_SB_META_CSUM_TYPE, \
- s8, OPT_STR(bch2_csum_types)) \
- BCH_OPT(data_checksum, 0644, BCH_SB_DATA_CSUM_TYPE, \
- s8, OPT_STR(bch2_csum_types)) \
- BCH_OPT(compression, 0644, BCH_SB_COMPRESSION_TYPE,\
- s8, OPT_STR(bch2_compression_types)) \
- BCH_OPT(str_hash, 0644, BCH_SB_STR_HASH_TYPE, \
- s8, OPT_STR(bch2_str_hash_types)) \
- BCH_OPT(inodes_32bit, 0644, BCH_SB_INODE_32BIT, \
- s8, OPT_BOOL()) \
- BCH_OPT(gc_reserve_percent, 0444, BCH_SB_GC_RESERVE, \
- s8, OPT_UINT(5, 21)) \
- BCH_OPT(root_reserve_percent, 0444, BCH_SB_ROOT_RESERVE, \
- s8, OPT_UINT(0, 100)) \
- BCH_OPT(wide_macs, 0644, BCH_SB_128_BIT_MACS, \
- s8, OPT_BOOL()) \
- BCH_OPT(verbose_recovery, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(posix_acl, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(journal_flush_disabled, 0644, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(nofsck, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(fix_errors, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(nochanges, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(noreplay, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(norecovery, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(noexcl, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(sb, 0444, NO_SB_OPT, \
- s64, OPT_UINT(0, S64_MAX)) \
+/*
+ * XXX: add fields for
+ * - default value
+ * - helptext
+ */
#define BCH_OPTS() \
- BCH_OPT(read_only, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_OPT(nostart, 0444, NO_SB_OPT, \
- s8, OPT_BOOL()) \
- BCH_VISIBLE_OPTS()
+ BCH_OPT(block_size, u16, OPT_FORMAT, \
+ OPT_UINT(1, 128), \
+ BCH_SB_BLOCK_SIZE, 8) \
+ BCH_OPT(btree_node_size, u16, OPT_FORMAT, \
+ OPT_UINT(1, 128), \
+ BCH_SB_BTREE_NODE_SIZE, 512) \
+ BCH_OPT(errors, u8, OPT_RUNTIME, \
+ OPT_STR(bch2_error_actions), \
+ BCH_SB_ERROR_ACTION, BCH_ON_ERROR_RO) \
+ BCH_OPT(metadata_replicas, u8, OPT_MOUNT, \
+ OPT_UINT(1, BCH_REPLICAS_MAX), \
+ BCH_SB_META_REPLICAS_WANT, 1) \
+ BCH_OPT(data_replicas, u8, OPT_MOUNT, \
+ OPT_UINT(1, BCH_REPLICAS_MAX), \
+ BCH_SB_DATA_REPLICAS_WANT, 1) \
+ BCH_OPT(metadata_replicas_required, u8, OPT_MOUNT, \
+ OPT_UINT(1, BCH_REPLICAS_MAX), \
+ BCH_SB_META_REPLICAS_REQ, 1) \
+ BCH_OPT(data_replicas_required, u8, OPT_MOUNT, \
+ OPT_UINT(1, BCH_REPLICAS_MAX), \
+ BCH_SB_DATA_REPLICAS_REQ, 1) \
+ BCH_OPT(metadata_checksum, u8, OPT_RUNTIME, \
+ OPT_STR(bch2_csum_types), \
+ BCH_SB_META_CSUM_TYPE, BCH_CSUM_OPT_CRC32C) \
+ BCH_OPT(data_checksum, u8, OPT_RUNTIME, \
+ OPT_STR(bch2_csum_types), \
+ BCH_SB_DATA_CSUM_TYPE, BCH_CSUM_OPT_CRC32C) \
+ BCH_OPT(compression, u8, OPT_RUNTIME, \
+ OPT_STR(bch2_compression_types), \
+ BCH_SB_COMPRESSION_TYPE, BCH_COMPRESSION_OPT_NONE)\
+ BCH_OPT(str_hash, u8, OPT_RUNTIME, \
+ OPT_STR(bch2_str_hash_types), \
+ BCH_SB_STR_HASH_TYPE, BCH_STR_HASH_SIPHASH) \
+ BCH_OPT(inodes_32bit, u8, OPT_RUNTIME, \
+ OPT_BOOL(), \
+ BCH_SB_INODE_32BIT, false) \
+ BCH_OPT(gc_reserve_percent, u8, OPT_MOUNT, \
+ OPT_UINT(5, 21), \
+ BCH_SB_GC_RESERVE, 8) \
+ BCH_OPT(root_reserve_percent, u8, OPT_MOUNT, \
+ OPT_UINT(0, 100), \
+ BCH_SB_ROOT_RESERVE, 0) \
+ BCH_OPT(wide_macs, u8, OPT_RUNTIME, \
+ OPT_BOOL(), \
+ BCH_SB_128_BIT_MACS, false) \
+ BCH_OPT(acl, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ BCH_SB_POSIX_ACL, true) \
+ BCH_OPT(degraded, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(verbose_recovery, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(journal_flush_disabled, u8, OPT_RUNTIME, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(nofsck, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(fix_errors, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(nochanges, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(noreplay, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(norecovery, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(noexcl, u8, OPT_MOUNT, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(sb, u64, OPT_MOUNT, \
+ OPT_UINT(0, S64_MAX), \
+ NO_SB_OPT, BCH_SB_SECTOR) \
+ BCH_OPT(read_only, u8, OPT_INTERNAL, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false) \
+ BCH_OPT(nostart, u8, OPT_INTERNAL, \
+ OPT_BOOL(), \
+ NO_SB_OPT, false)
struct bch_opts {
-#define BCH_OPT(_name, _mode, _sb_opt, _bits, ...) \
- _bits _name;
+#define BCH_OPT(_name, _bits, ...) unsigned _name##_defined:1;
+ BCH_OPTS()
+#undef BCH_OPT
+#define BCH_OPT(_name, _bits, ...) _bits _name;
BCH_OPTS()
#undef BCH_OPT
};
-enum bch_opt_id {
-#define BCH_OPT(_name, ...) \
- Opt_##_name,
+static const struct bch_opts bch2_opts_default = {
+#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default) \
+ ._name##_defined = true, \
+ ._name = _default, \
+
+ BCH_OPTS()
+#undef BCH_OPT
+};
- BCH_VISIBLE_OPTS()
+#define opt_defined(_opts, _name) ((_opts)._name##_defined)
+
+#define opt_get(_opts, _name) \
+ (opt_defined(_opts, _name) ? _opts._name : bch2_opts_default._name)
+
+#define opt_set(_opts, _name, _v) \
+do { \
+ (_opts)._name##_defined = true; \
+ (_opts)._name = _v; \
+} while (0)
+
+static inline struct bch_opts bch2_opts_empty(void)
+{
+ struct bch_opts opts;
+
+ memset(&opts, 0, sizeof(opts));
+ return opts;
+}
+
+void bch2_opts_apply(struct bch_opts *, struct bch_opts);
+
+enum bch_opt_id {
+#define BCH_OPT(_name, ...) Opt_##_name,
+ BCH_OPTS()
#undef BCH_OPT
+ bch2_opts_nr
};
struct bch_option {
- const char *name;
+ struct attribute attr;
void (*set_sb)(struct bch_sb *, u64);
+ enum opt_mode mode;
enum opt_type type;
union {
@@ -140,32 +215,12 @@ struct bch_option {
extern const struct bch_option bch2_opt_table[];
-static inline struct bch_opts bch2_opts_empty(void)
-{
- struct bch_opts ret;
-
- memset(&ret, 255, sizeof(ret));
- return ret;
-}
+u64 bch2_opt_get_by_id(const struct bch_opts *, enum bch_opt_id);
+void bch2_opt_set_by_id(struct bch_opts *, enum bch_opt_id, u64);
-static inline void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
-{
-#define BCH_OPT(_name, ...) \
- if (src._name >= 0) \
- dst->_name = src._name;
-
- BCH_OPTS()
-#undef BCH_OPT
-}
-
-#define opt_defined(_opt) ((_opt) >= 0)
-
-void bch2_opt_set(struct bch_opts *, enum bch_opt_id, u64);
-struct bch_opts bch2_sb_opts(struct bch_sb *);
+struct bch_opts bch2_opts_from_sb(struct bch_sb *);
+int bch2_opt_parse(const struct bch_option *, const char *, u64 *);
int bch2_parse_mount_opts(struct bch_opts *, char *);
-enum bch_opt_id bch2_parse_sysfs_opt(const char *, const char *, u64 *);
-
-ssize_t bch2_opt_show(struct bch_opts *, const char *, char *, size_t);
#endif /* _BCACHEFS_OPTS_H */
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index 5dce4e2d2101..7b6acbc5bb13 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -318,8 +318,10 @@ const char *bch2_sb_validate(struct bcache_superblock *disk_sb)
le64_to_cpu(sb->version) > BCH_SB_VERSION_MAX)
return"Unsupported superblock version";
- if (le64_to_cpu(sb->version) < BCH_SB_VERSION_EXTENT_MAX)
+ if (le64_to_cpu(sb->version) < BCH_SB_VERSION_EXTENT_MAX) {
SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb, 7);
+ SET_BCH_SB_POSIX_ACL(sb, 1);
+ }
block_size = le16_to_cpu(sb->block_size);
@@ -462,11 +464,8 @@ static void bch2_sb_update(struct bch_fs *c)
c->sb.uuid = src->uuid;
c->sb.user_uuid = src->user_uuid;
- c->sb.block_size = le16_to_cpu(src->block_size);
- c->sb.btree_node_size = BCH_SB_BTREE_NODE_SIZE(src);
c->sb.nr_devices = src->nr_devices;
c->sb.clean = BCH_SB_CLEAN(src);
- c->sb.str_hash_type = BCH_SB_STR_HASH_TYPE(src);
c->sb.encryption_type = BCH_SB_ENCRYPTION_TYPE(src);
c->sb.encoded_extent_max= 1 << BCH_SB_ENCODED_EXTENT_MAX_BITS(src);
c->sb.time_base_lo = le64_to_cpu(src->time_base_lo);
@@ -609,7 +608,7 @@ const char *bch2_read_super(struct bcache_superblock *sb,
struct bch_opts opts,
const char *path)
{
- u64 offset = opt_defined(opts.sb) ? opts.sb : BCH_SB_SECTOR;
+ u64 offset = opt_get(opts, sb);
struct bch_sb_layout layout;
const char *err;
unsigned i;
@@ -617,10 +616,10 @@ const char *bch2_read_super(struct bcache_superblock *sb,
memset(sb, 0, sizeof(*sb));
sb->mode = FMODE_READ;
- if (!(opt_defined(opts.noexcl) && opts.noexcl))
+ if (!opt_get(opts, noexcl))
sb->mode |= FMODE_EXCL;
- if (!(opt_defined(opts.nochanges) && opts.nochanges))
+ if (!opt_get(opts, nochanges))
sb->mode |= FMODE_WRITE;
err = bch2_blkdev_open(path, sb->mode, sb, &sb->bdev);
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 9f8df1813db4..9ef81f19c2a8 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -544,15 +544,16 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
goto err;
}
- c->block_bits = ilog2(c->sb.block_size);
-
mutex_unlock(&c->sb_lock);
scnprintf(c->name, sizeof(c->name), "%pU", &c->sb.user_uuid);
- bch2_opts_apply(&c->opts, bch2_sb_opts(sb));
+ c->opts = bch2_opts_default;
+ bch2_opts_apply(&c->opts, bch2_opts_from_sb(sb));
bch2_opts_apply(&c->opts, opts);
+ c->block_bits = ilog2(c->opts.block_size);
+
c->opts.nochanges |= c->opts.noreplay;
c->opts.read_only |= c->opts.nochanges;
@@ -583,7 +584,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
BIOSET_NEED_BVECS) ||
mempool_init_page_pool(&c->bio_bounce_pages,
max_t(unsigned,
- c->sb.btree_node_size,
+ c->opts.btree_node_size,
c->sb.encoded_extent_max) /
PAGE_SECTORS, 0) ||
!(c->usage_percpu = alloc_percpu(struct bch_fs_usage)) ||
@@ -645,7 +646,8 @@ static const char *__bch2_fs_online(struct bch_fs *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"))
+ kobject_add(&c->time_stats, &c->kobj, "time_stats") ||
+ bch2_opts_create_sysfs_files(&c->opts_dir))
return "error creating sysfs objects";
mutex_lock(&c->state_lock);
@@ -917,7 +919,7 @@ static const char *bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c)
if (!sb_mi)
return "Invalid superblock: member info area missing";
- if (le16_to_cpu(sb->block_size) != c->sb.block_size)
+ if (le16_to_cpu(sb->block_size) != c->opts.block_size)
return "mismatched block size";
if (le16_to_cpu(sb_mi->members[sb->dev_idx].bucket_size) <
@@ -1124,7 +1126,7 @@ static int bch2_dev_alloc(struct bch_fs *c, unsigned dev_idx)
btree_node_reserve_buckets =
DIV_ROUND_UP(BTREE_NODE_RESERVE,
- ca->mi.bucket_size / c->sb.btree_node_size);
+ ca->mi.bucket_size / c->opts.btree_node_size);
if (percpu_ref_init(&ca->ref, bch2_dev_ref_release,
0, GFP_KERNEL) ||
diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c
index ff3deba8dac2..07d9be751d6c 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -194,14 +194,6 @@ read_attribute(data_replicas_have);
BCH_DEBUG_PARAMS()
#undef BCH_DEBUG_PARAM
-#define BCH_OPT(_name, _mode, ...) \
- static struct attribute sysfs_opt_##_name = { \
- .name = #_name, .mode = _mode, \
- };
-
- BCH_VISIBLE_OPTS()
-#undef BCH_OPT
-
#define BCH_TIME_STAT(name, frequency_units, duration_units) \
sysfs_time_stats_attribute(name, frequency_units, duration_units);
BCH_TIME_STATS()
@@ -528,8 +520,13 @@ SHOW(bch2_fs_opts_dir)
{
char *out = buf, *end = buf + PAGE_SIZE;
struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
+ const struct bch_option *opt = container_of(attr, struct bch_option, attr);
+ int id = opt - bch2_opt_table;
+ u64 v = bch2_opt_get_by_id(&c->opts, id);
- out += bch2_opt_show(&c->opts, attr->name, out, end - out);
+ out += opt->type == BCH_OPT_STR
+ ? bch2_scnprint_string_list(out, end - out, opt->choices, v)
+ : scnprintf(out, end - out, "%lli", v);
out += scnprintf(out, end - out, "\n");
return out - buf;
@@ -538,15 +535,13 @@ SHOW(bch2_fs_opts_dir)
STORE(bch2_fs_opts_dir)
{
struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
- const struct bch_option *opt;
- int id;
+ const struct bch_option *opt = container_of(attr, struct bch_option, attr);
+ int ret, id = opt - bch2_opt_table;
u64 v;
- id = bch2_parse_sysfs_opt(attr->name, buf, &v);
- if (id < 0)
- return id;
-
- opt = &bch2_opt_table[id];
+ ret = bch2_opt_parse(opt, buf, &v);
+ if (ret < 0)
+ return ret;
mutex_lock(&c->sb_lock);
@@ -563,7 +558,7 @@ STORE(bch2_fs_opts_dir)
bch2_write_super(c);
}
- bch2_opt_set(&c->opts, id, v);
+ bch2_opt_set_by_id(&c->opts, id, v);
mutex_unlock(&c->sb_lock);
@@ -571,15 +566,26 @@ STORE(bch2_fs_opts_dir)
}
SYSFS_OPS(bch2_fs_opts_dir);
-struct attribute *bch2_fs_opts_dir_files[] = {
-#define BCH_OPT(_name, ...) \
- &sysfs_opt_##_name,
+struct attribute *bch2_fs_opts_dir_files[] = { NULL };
- BCH_VISIBLE_OPTS()
-#undef BCH_OPT
+int bch2_opts_create_sysfs_files(struct kobject *kobj)
+{
+ const struct bch_option *i;
+ int ret;
- NULL
-};
+ for (i = bch2_opt_table;
+ i < bch2_opt_table + bch2_opts_nr;
+ i++) {
+ if (i->mode == OPT_INTERNAL)
+ continue;
+
+ ret = sysfs_create_file(kobj, &i->attr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
/* time stats */
diff --git a/fs/bcachefs/sysfs.h b/fs/bcachefs/sysfs.h
index a4825056f01e..1ba759fd6e8c 100644
--- a/fs/bcachefs/sysfs.h
+++ b/fs/bcachefs/sysfs.h
@@ -20,6 +20,8 @@ extern struct sysfs_ops bch2_fs_opts_dir_sysfs_ops;
extern struct sysfs_ops bch2_fs_time_stats_sysfs_ops;
extern struct sysfs_ops bch2_dev_sysfs_ops;
+int bch2_opts_create_sysfs_files(struct kobject *);
+
#else
static struct attribute *bch2_fs_files[] = {};
@@ -34,6 +36,8 @@ static const struct sysfs_ops bch2_fs_opts_dir_sysfs_ops;
static const struct sysfs_ops bch2_fs_time_stats_sysfs_ops;
static const struct sysfs_ops bch2_dev_sysfs_ops;
+static inline int bch2_opts_create_sysfs_files(struct kobject *kobj) { return 0; }
+
#endif /* NO_BCACHEFS_SYSFS */
#endif /* _BCACHEFS_SYSFS_H_ */