summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-04-10 15:40:04 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-03-13 11:32:48 -0400
commitc4a19869e64ab0e2e48f4f2dfda8a19198bd2473 (patch)
tree14fbc0f06dd55dce070d3266cd304fe5a446b181
parent777ac2e607263471040fc3c8c7d71d42c5c8f615 (diff)
bcachefs: Refactor superblock code
this is so more code can be used by bcachefs format Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/bcachefs.h3
-rw-r--r--fs/bcachefs/btree_gc.c4
-rw-r--r--fs/bcachefs/chardev.c2
-rw-r--r--fs/bcachefs/checksum.c16
-rw-r--r--fs/bcachefs/compress.c2
-rw-r--r--fs/bcachefs/disk_groups.c107
-rw-r--r--fs/bcachefs/disk_groups.h6
-rw-r--r--fs/bcachefs/quota.c19
-rw-r--r--fs/bcachefs/replicas.c8
-rw-r--r--fs/bcachefs/super-io.c157
-rw-r--r--fs/bcachefs/super-io.h11
-rw-r--r--fs/bcachefs/super.c50
-rw-r--r--fs/bcachefs/super_types.h3
-rw-r--r--fs/bcachefs/sysfs.c15
-rw-r--r--include/trace/events/bcachefs.h2
15 files changed, 194 insertions, 211 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index 1a1b3ba49cc9..ba91db9f8785 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -522,8 +522,7 @@ struct bch_fs {
u64 features;
} sb;
- struct bch_sb *disk_sb;
- unsigned disk_sb_order;
+ struct bch_sb_handle disk_sb;
unsigned short block_bits; /* ilog2(block_size) */
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c
index e5ee50fea6b1..e9ebe7cedc67 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -1045,8 +1045,8 @@ static int __bch2_initial_gc(struct bch_fs *c, struct list_head *journal)
int ret;
mutex_lock(&c->sb_lock);
- if (!bch2_sb_get_replicas(c->disk_sb)) {
- if (BCH_SB_INITIALIZED(c->disk_sb))
+ if (!bch2_sb_get_replicas(c->disk_sb.sb)) {
+ if (BCH_SB_INITIALIZED(c->disk_sb.sb))
bch_info(c, "building replicas info");
set_bit(BCH_FS_REBUILD_REPLICAS, &c->flags);
}
diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c
index 7fa01c16fa13..679107222721 100644
--- a/fs/bcachefs/chardev.c
+++ b/fs/bcachefs/chardev.c
@@ -464,7 +464,7 @@ static long bch2_ioctl_read_super(struct bch_fs *c,
sb = ca->disk_sb.sb;
} else {
- sb = c->disk_sb;
+ sb = c->disk_sb.sb;
}
if (vstruct_bytes(sb) > arg.size) {
diff --git a/fs/bcachefs/checksum.c b/fs/bcachefs/checksum.c
index 18f188293964..7a669d1511ba 100644
--- a/fs/bcachefs/checksum.c
+++ b/fs/bcachefs/checksum.c
@@ -571,7 +571,7 @@ int bch2_decrypt_sb_key(struct bch_fs *c,
if (!bch2_key_is_encrypted(&sb_key))
goto out;
- ret = bch2_request_key(c->disk_sb, &user_key);
+ ret = bch2_request_key(c->disk_sb.sb, &user_key);
if (ret) {
bch_err(c, "error requesting encryption key: %i", ret);
goto err;
@@ -625,7 +625,7 @@ int bch2_disable_encryption(struct bch_fs *c)
mutex_lock(&c->sb_lock);
- crypt = bch2_sb_get_crypt(c->disk_sb);
+ crypt = bch2_sb_get_crypt(c->disk_sb.sb);
if (!crypt)
goto out;
@@ -641,7 +641,7 @@ int bch2_disable_encryption(struct bch_fs *c)
crypt->key.magic = BCH_KEY_MAGIC;
crypt->key.key = key;
- SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb, 0);
+ SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 0);
bch2_write_super(c);
out:
mutex_unlock(&c->sb_lock);
@@ -659,7 +659,7 @@ int bch2_enable_encryption(struct bch_fs *c, bool keyed)
mutex_lock(&c->sb_lock);
/* Do we already have an encryption key? */
- if (bch2_sb_get_crypt(c->disk_sb))
+ if (bch2_sb_get_crypt(c->disk_sb.sb))
goto err;
ret = bch2_alloc_ciphers(c);
@@ -670,7 +670,7 @@ int bch2_enable_encryption(struct bch_fs *c, bool keyed)
get_random_bytes(&key.key, sizeof(key.key));
if (keyed) {
- ret = bch2_request_key(c->disk_sb, &user_key);
+ ret = bch2_request_key(c->disk_sb.sb, &user_key);
if (ret) {
bch_err(c, "error requesting encryption key: %i", ret);
goto err;
@@ -687,7 +687,7 @@ int bch2_enable_encryption(struct bch_fs *c, bool keyed)
if (ret)
goto err;
- crypt = bch2_fs_sb_resize_crypt(c, sizeof(*crypt) / sizeof(u64));
+ crypt = bch2_sb_resize_crypt(&c->disk_sb, sizeof(*crypt) / sizeof(u64));
if (!crypt) {
ret = -ENOMEM; /* XXX this technically could be -ENOSPC */
goto err;
@@ -696,7 +696,7 @@ int bch2_enable_encryption(struct bch_fs *c, bool keyed)
crypt->key = key;
/* write superblock */
- SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb, 1);
+ SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 1);
bch2_write_super(c);
err:
mutex_unlock(&c->sb_lock);
@@ -730,7 +730,7 @@ int bch2_fs_encryption_init(struct bch_fs *c)
goto out;
}
- crypt = bch2_sb_get_crypt(c->disk_sb);
+ crypt = bch2_sb_get_crypt(c->disk_sb.sb);
if (!crypt)
goto out;
diff --git a/fs/bcachefs/compress.c b/fs/bcachefs/compress.c
index c085dedbd565..c464d012eb3b 100644
--- a/fs/bcachefs/compress.c
+++ b/fs/bcachefs/compress.c
@@ -495,7 +495,7 @@ int __bch2_check_set_has_compressed_data(struct bch_fs *c, u64 f)
return ret;
}
- c->disk_sb->features[0] |= cpu_to_le64(f);
+ c->disk_sb.sb->features[0] |= cpu_to_le64(f);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
diff --git a/fs/bcachefs/disk_groups.c b/fs/bcachefs/disk_groups.c
index f3e2fc2bea63..24e8a45970c1 100644
--- a/fs/bcachefs/disk_groups.c
+++ b/fs/bcachefs/disk_groups.c
@@ -125,8 +125,8 @@ int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
lockdep_assert_held(&c->sb_lock);
- mi = bch2_sb_get_members(c->disk_sb);
- groups = bch2_sb_get_disk_groups(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
+ groups = bch2_sb_get_disk_groups(c->disk_sb.sb);
nr_groups = disk_groups_nr(groups);
if (!groups)
@@ -147,7 +147,7 @@ int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
dst->parent = BCH_GROUP_PARENT(src);
}
- for (i = 0; i < c->disk_sb->nr_devices; i++) {
+ for (i = 0; i < c->disk_sb.sb->nr_devices; i++) {
struct bch_member *m = mi->members + i;
struct bch_disk_group_cpu *dst =
&cpu_g->entries[BCH_MEMBER_GROUP(m)];
@@ -221,11 +221,11 @@ static int __bch2_disk_group_find(struct bch_sb_field_disk_groups *groups,
return -1;
}
-static int __bch2_disk_group_add(struct bch_fs *c, unsigned parent,
+static int __bch2_disk_group_add(struct bch_sb_handle *sb, unsigned parent,
const char *name, unsigned namelen)
{
struct bch_sb_field_disk_groups *groups =
- bch2_sb_get_disk_groups(c->disk_sb);
+ bch2_sb_get_disk_groups(sb->sb);
unsigned i, nr_groups = disk_groups_nr(groups);
struct bch_disk_group *g;
@@ -243,11 +243,9 @@ static int __bch2_disk_group_add(struct bch_fs *c, unsigned parent,
sizeof(struct bch_disk_group) * (nr_groups + 1)) /
sizeof(u64);
- groups = bch2_fs_sb_resize_disk_groups(c, u64s);
- if (!groups) {
- mutex_unlock(&c->sb_lock);
+ groups = bch2_sb_resize_disk_groups(sb, u64s);
+ if (!groups)
return -ENOSPC;
- }
nr_groups = disk_groups_nr(groups);
}
@@ -266,14 +264,12 @@ static int __bch2_disk_group_add(struct bch_fs *c, unsigned parent,
return i;
}
-static int bch2_disk_path_find(struct bch_fs *c, const char *name)
+int bch2_disk_path_find(struct bch_sb_handle *sb, const char *name)
{
- struct bch_sb_field_disk_groups *groups;
+ struct bch_sb_field_disk_groups *groups =
+ bch2_sb_get_disk_groups(sb->sb);
int v = -1;
- mutex_lock(&c->sb_lock);
- groups = bch2_sb_get_disk_groups(c->disk_sb);
-
do {
const char *next = strchrnul(name, '.');
unsigned len = next - name;
@@ -285,22 +281,47 @@ static int bch2_disk_path_find(struct bch_fs *c, const char *name)
name = next;
} while (*name && v >= 0);
- mutex_unlock(&c->sb_lock);
+ return v;
+}
+
+int bch2_disk_path_find_or_create(struct bch_sb_handle *sb, const char *name)
+{
+ struct bch_sb_field_disk_groups *groups;
+ unsigned parent = 0;
+ int v = -1;
+
+ do {
+ const char *next = strchrnul(name, '.');
+ unsigned len = next - name;
+
+ if (*next == '.')
+ next++;
+
+ groups = bch2_sb_get_disk_groups(sb->sb);
+
+ v = __bch2_disk_group_find(groups, parent, name, len);
+ if (v < 0)
+ v = __bch2_disk_group_add(sb, parent, name, len);
+ if (v < 0)
+ return v;
+
+ parent = v + 1;
+ name = next;
+ } while (*name && v >= 0);
return v;
}
-int bch2_disk_path_print(struct bch_fs *c, char *buf, size_t len, unsigned v)
+int bch2_disk_path_print(struct bch_sb_handle *sb,
+ char *buf, size_t len, unsigned v)
{
char *out = buf, *end = out + len;
- struct bch_sb_field_disk_groups *groups;
+ struct bch_sb_field_disk_groups *groups =
+ bch2_sb_get_disk_groups(sb->sb);
struct bch_disk_group *g;
unsigned nr = 0;
u16 path[32];
- mutex_lock(&c->sb_lock);
- groups = bch2_sb_get_disk_groups(c->disk_sb);
-
while (1) {
if (nr == ARRAY_SIZE(path))
goto inval;
@@ -338,48 +359,30 @@ int bch2_disk_path_print(struct bch_fs *c, char *buf, size_t len, unsigned v)
if (nr)
out += scnprintf(out, end - out, ".");
}
-out:
- mutex_unlock(&c->sb_lock);
+
return out - buf;
inval:
- out += scnprintf(out, end - out, "invalid group %u", v);
- goto out;
+ return scnprintf(buf, len, "invalid group %u", v);
}
int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
{
- struct bch_sb_field_disk_groups *groups;
struct bch_member *mi;
- unsigned parent = 0;
- int v;
+ int v = -1;
mutex_lock(&c->sb_lock);
if (!strlen(name) || !strcmp(name, "none"))
goto write_sb;
- do {
- const char *next = strchrnul(name, '.');
- unsigned len = next - name;
-
- if (*next == '.')
- next++;
-
- groups = bch2_sb_get_disk_groups(c->disk_sb);
-
- v = __bch2_disk_group_find(groups, parent, name, len);
- if (v < 0)
- v = __bch2_disk_group_add(c, parent, name, len);
- if (v < 0) {
- mutex_unlock(&c->sb_lock);
- return v;
- }
+ v = bch2_disk_path_find_or_create(&c->disk_sb, name);
+ if (v < 0) {
+ mutex_unlock(&c->sb_lock);
+ return v;
+ }
- parent = v + 1;
- name = next;
- } while (*name && v >= 0);
write_sb:
- mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
+ mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
SET_BCH_MEMBER_GROUP(mi, v + 1);
bch2_write_super(c);
@@ -406,7 +409,10 @@ int bch2_opt_target_parse(struct bch_fs *c, const char *buf, u64 *v)
return 0;
}
- g = bch2_disk_path_find(c, buf);
+ mutex_lock(&c->sb_lock);
+ g = bch2_disk_path_find(&c->disk_sb, buf);
+ mutex_unlock(&c->sb_lock);
+
if (g >= 0) {
*v = group_to_target(g);
return 0;
@@ -445,7 +451,10 @@ int bch2_opt_target_print(struct bch_fs *c, char *buf, size_t len, u64 v)
break;
}
case TARGET_GROUP:
- return bch2_disk_path_print(c, buf, len, t.group);
+ mutex_lock(&c->sb_lock);
+ ret = bch2_disk_path_print(&c->disk_sb, buf, len, t.group);
+ mutex_unlock(&c->sb_lock);
+ break;
default:
BUG();
}
diff --git a/fs/bcachefs/disk_groups.h b/fs/bcachefs/disk_groups.h
index f2f17d6416a0..3f006a4ffa6e 100644
--- a/fs/bcachefs/disk_groups.h
+++ b/fs/bcachefs/disk_groups.h
@@ -83,13 +83,15 @@ static inline bool dev_idx_in_target(struct bch_fs *c, unsigned dev, unsigned ta
const struct bch_devs_mask *bch2_target_to_mask(struct bch_fs *, unsigned);
+int bch2_disk_path_find(struct bch_sb_handle *, const char *);
+int bch2_disk_path_find_or_create(struct bch_sb_handle *, const char *);
+int bch2_disk_path_print(struct bch_sb_handle *, char *, size_t, unsigned);
+
int bch2_opt_target_parse(struct bch_fs *, const char *, u64 *);
int bch2_opt_target_print(struct bch_fs *, char *, size_t, u64);
int bch2_sb_disk_groups_to_cpu(struct bch_fs *);
-int bch2_disk_path_print(struct bch_fs *, char *, size_t, unsigned);
-
int bch2_dev_group_set(struct bch_fs *, struct bch_dev *, const char *);
const char *bch2_sb_validate_disk_groups(struct bch_sb *,
diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c
index 7fac52c7f7d0..0adbfe523f51 100644
--- a/fs/bcachefs/quota.c
+++ b/fs/bcachefs/quota.c
@@ -410,7 +410,7 @@ static void bch2_sb_quota_read(struct bch_fs *c)
struct bch_sb_field_quota *sb_quota;
unsigned i, j;
- sb_quota = bch2_sb_get_quota(c->disk_sb);
+ sb_quota = bch2_sb_get_quota(c->disk_sb.sb);
if (!sb_quota)
return;
@@ -487,13 +487,13 @@ static int bch2_quota_enable(struct super_block *sb, unsigned uflags)
mutex_lock(&c->sb_lock);
if (uflags & FS_QUOTA_UDQ_ENFD)
- SET_BCH_SB_USRQUOTA(c->disk_sb, true);
+ SET_BCH_SB_USRQUOTA(c->disk_sb.sb, true);
if (uflags & FS_QUOTA_GDQ_ENFD)
- SET_BCH_SB_GRPQUOTA(c->disk_sb, true);
+ SET_BCH_SB_GRPQUOTA(c->disk_sb.sb, true);
if (uflags & FS_QUOTA_PDQ_ENFD)
- SET_BCH_SB_PRJQUOTA(c->disk_sb, true);
+ SET_BCH_SB_PRJQUOTA(c->disk_sb.sb, true);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
@@ -510,13 +510,13 @@ static int bch2_quota_disable(struct super_block *sb, unsigned uflags)
mutex_lock(&c->sb_lock);
if (uflags & FS_QUOTA_UDQ_ENFD)
- SET_BCH_SB_USRQUOTA(c->disk_sb, false);
+ SET_BCH_SB_USRQUOTA(c->disk_sb.sb, false);
if (uflags & FS_QUOTA_GDQ_ENFD)
- SET_BCH_SB_GRPQUOTA(c->disk_sb, false);
+ SET_BCH_SB_GRPQUOTA(c->disk_sb.sb, false);
if (uflags & FS_QUOTA_PDQ_ENFD)
- SET_BCH_SB_PRJQUOTA(c->disk_sb, false);
+ SET_BCH_SB_PRJQUOTA(c->disk_sb.sb, false);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
@@ -627,9 +627,10 @@ static int bch2_quota_set_info(struct super_block *sb, int type,
q = &c->quotas[type];
mutex_lock(&c->sb_lock);
- sb_quota = bch2_sb_get_quota(c->disk_sb);
+ sb_quota = bch2_sb_get_quota(c->disk_sb.sb);
if (!sb_quota) {
- sb_quota = bch2_fs_sb_resize_quota(c, sizeof(*sb_quota) / sizeof(u64));
+ sb_quota = bch2_sb_resize_quota(&c->disk_sb,
+ sizeof(*sb_quota) / sizeof(u64));
if (!sb_quota)
return -ENOSPC;
}
diff --git a/fs/bcachefs/replicas.c b/fs/bcachefs/replicas.c
index 807fdc4c1e68..a70220bde8cc 100644
--- a/fs/bcachefs/replicas.c
+++ b/fs/bcachefs/replicas.c
@@ -407,7 +407,7 @@ int bch2_sb_replicas_to_cpu_replicas(struct bch_fs *c)
struct bch_sb_field_replicas *sb_r;
struct bch_replicas_cpu *cpu_r, *old_r;
- sb_r = bch2_sb_get_replicas(c->disk_sb);
+ sb_r = bch2_sb_get_replicas(c->disk_sb.sb);
cpu_r = __bch2_sb_replicas_to_cpu_replicas(sb_r);
if (!cpu_r)
return -ENOMEM;
@@ -436,7 +436,7 @@ static int bch2_cpu_replicas_to_sb_replicas(struct bch_fs *c,
bytes += hweight8(e->devs[i]);
}
- sb_r = bch2_fs_sb_resize_replicas(c,
+ sb_r = bch2_sb_resize_replicas(&c->disk_sb,
DIV_ROUND_UP(sizeof(*sb_r) + bytes, sizeof(u64)));
if (!sb_r)
return -ENOSPC;
@@ -602,7 +602,7 @@ struct replicas_status __bch2_replicas_status(struct bch_fs *c,
for (i = 0; i < ARRAY_SIZE(ret.replicas); i++)
ret.replicas[i].nr_online = UINT_MAX;
- mi = bch2_sb_get_members(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
rcu_read_lock();
r = rcu_dereference(c->replicas);
@@ -618,7 +618,7 @@ struct replicas_status __bch2_replicas_status(struct bch_fs *c,
if (!replicas_test_dev(e, dev))
continue;
- BUG_ON(!bch2_dev_exists(c->disk_sb, mi, dev));
+ BUG_ON(!bch2_dev_exists(c->disk_sb.sb, mi, dev));
if (test_bit(dev, online_devs.d))
nr_online++;
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index 5def02f903db..322e65cd5ef7 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -37,14 +37,18 @@ struct bch_sb_field *bch2_sb_field_get(struct bch_sb *sb,
return NULL;
}
-static struct bch_sb_field *__bch2_sb_field_resize(struct bch_sb *sb,
- struct bch_sb_field *f,
- unsigned u64s)
+static struct bch_sb_field *__bch2_sb_field_resize(struct bch_sb_handle *sb,
+ struct bch_sb_field *f,
+ unsigned u64s)
{
unsigned old_u64s = f ? le32_to_cpu(f->u64s) : 0;
+ unsigned sb_u64s = le32_to_cpu(sb->sb->u64s) + u64s - old_u64s;
+
+ BUG_ON(get_order(__vstruct_bytes(struct bch_sb, sb_u64s)) >
+ sb->page_order);
if (!f) {
- f = vstruct_last(sb);
+ f = vstruct_last(sb->sb);
memset(f, 0, sizeof(u64) * u64s);
f->u64s = cpu_to_le32(u64s);
f->type = 0;
@@ -55,13 +59,13 @@ static struct bch_sb_field *__bch2_sb_field_resize(struct bch_sb *sb,
f->u64s = cpu_to_le32(u64s);
dst = vstruct_end(f);
- memmove(dst, src, vstruct_end(sb) - src);
+ memmove(dst, src, vstruct_end(sb->sb) - src);
if (dst > src)
memset(src, 0, dst - src);
}
- le32_add_cpu(&sb->u64s, u64s - old_u64s);
+ sb->sb->u64s = cpu_to_le32(sb_u64s);
return f;
}
@@ -79,28 +83,44 @@ void bch2_free_super(struct bch_sb_handle *sb)
memset(sb, 0, sizeof(*sb));
}
-static int __bch2_super_realloc(struct bch_sb_handle *sb, unsigned order)
+int bch2_sb_realloc(struct bch_sb_handle *sb, unsigned u64s)
{
+ size_t new_bytes = __vstruct_bytes(struct bch_sb, u64s);
+ unsigned order = get_order(new_bytes);
struct bch_sb *new_sb;
struct bio *bio;
+ if (sb->have_layout) {
+ u64 max_bytes = 512 << sb->sb->layout.sb_max_size_bits;
+
+ if (new_bytes > max_bytes) {
+ pr_err("%pg: superblock too big: want %zu but have %llu",
+ sb->bdev, new_bytes, max_bytes);
+ return -ENOSPC;
+ }
+ }
+
if (sb->page_order >= order && sb->sb)
return 0;
if (dynamic_fault("bcachefs:add:super_realloc"))
return -ENOMEM;
- bio = bio_kmalloc(1 << order, GFP_KERNEL);
- if (!bio)
- return -ENOMEM;
+ if (sb->have_bio) {
+ unsigned nr_bvecs = 1 << order;
- bio_init(bio, NULL, bio->bi_inline_vecs, 1 << order, 0);
+ bio = bio_kmalloc(nr_bvecs, GFP_KERNEL);
+ if (!bio)
+ return -ENOMEM;
- if (sb->bio)
- kfree(sb->bio);
- sb->bio = bio;
+ bio_init(bio, NULL, bio->bi_inline_vecs, nr_bvecs, 0);
- new_sb = (void *) __get_free_pages(GFP_KERNEL, order);
+ if (sb->bio)
+ kfree(sb->bio);
+ sb->bio = bio;
+ }
+
+ new_sb = (void *) __get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
if (!new_sb)
return -ENOMEM;
@@ -115,43 +135,6 @@ static int __bch2_super_realloc(struct bch_sb_handle *sb, unsigned order)
return 0;
}
-static int bch2_sb_realloc(struct bch_sb_handle *sb, unsigned u64s)
-{
- u64 new_bytes = __vstruct_bytes(struct bch_sb, u64s);
- u64 max_bytes = 512 << sb->sb->layout.sb_max_size_bits;
-
- if (new_bytes > max_bytes) {
- pr_err("%pg: superblock too big: want %llu but have %llu",
- sb->bdev, new_bytes, max_bytes);
- return -ENOSPC;
- }
-
- return __bch2_super_realloc(sb, get_order(new_bytes));
-}
-
-static int bch2_fs_sb_realloc(struct bch_fs *c, unsigned u64s)
-{
- u64 bytes = __vstruct_bytes(struct bch_sb, u64s);
- struct bch_sb *sb;
- unsigned order = get_order(bytes);
-
- if (c->disk_sb && order <= c->disk_sb_order)
- return 0;
-
- sb = (void *) __get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
- if (!sb)
- return -ENOMEM;
-
- if (c->disk_sb)
- memcpy(sb, c->disk_sb, PAGE_SIZE << c->disk_sb_order);
-
- free_pages((unsigned long) c->disk_sb, c->disk_sb_order);
-
- c->disk_sb = sb;
- c->disk_sb_order = order;
- return 0;
-}
-
struct bch_sb_field *bch2_sb_field_resize(struct bch_sb_handle *sb,
enum bch_sb_field_type type,
unsigned u64s)
@@ -163,38 +146,26 @@ struct bch_sb_field *bch2_sb_field_resize(struct bch_sb_handle *sb,
if (bch2_sb_realloc(sb, le32_to_cpu(sb->sb->u64s) + d))
return NULL;
- f = __bch2_sb_field_resize(sb->sb, f, u64s);
- f->type = cpu_to_le32(type);
- return f;
-}
-
-struct bch_sb_field *bch2_fs_sb_field_resize(struct bch_fs *c,
- enum bch_sb_field_type type,
- unsigned u64s)
-{
- struct bch_sb_field *f = bch2_sb_field_get(c->disk_sb, type);
- ssize_t old_u64s = f ? le32_to_cpu(f->u64s) : 0;
- ssize_t d = -old_u64s + u64s;
- struct bch_dev *ca;
- unsigned i;
+ if (sb->fs_sb) {
+ struct bch_fs *c = container_of(sb, struct bch_fs, disk_sb);
+ struct bch_dev *ca;
+ unsigned i;
- lockdep_assert_held(&c->sb_lock);
+ lockdep_assert_held(&c->sb_lock);
- if (bch2_fs_sb_realloc(c, le32_to_cpu(c->disk_sb->u64s) + d))
- return NULL;
+ /* XXX: we're not checking that offline device have enough space */
- /* XXX: we're not checking that offline device have enough space */
+ for_each_online_member(ca, c, i) {
+ struct bch_sb_handle *sb = &ca->disk_sb;
- for_each_online_member(ca, c, i) {
- struct bch_sb_handle *sb = &ca->disk_sb;
-
- if (bch2_sb_realloc(sb, le32_to_cpu(sb->sb->u64s) + d)) {
- percpu_ref_put(&ca->ref);
- return NULL;
+ if (bch2_sb_realloc(sb, le32_to_cpu(sb->sb->u64s) + d)) {
+ percpu_ref_put(&ca->ref);
+ return NULL;
+ }
}
}
- f = __bch2_sb_field_resize(c->disk_sb, f, u64s);
+ f = __bch2_sb_field_resize(sb, f, u64s);
f->type = cpu_to_le32(type);
return f;
}
@@ -356,7 +327,7 @@ const char *bch2_sb_validate(struct bch_sb_handle *disk_sb)
static void bch2_sb_update(struct bch_fs *c)
{
- struct bch_sb *src = c->disk_sb;
+ struct bch_sb *src = c->disk_sb.sb;
struct bch_sb_field_members *mi = bch2_sb_get_members(src);
struct bch_dev *ca;
unsigned i;
@@ -379,9 +350,10 @@ static void bch2_sb_update(struct bch_fs *c)
}
/* doesn't copy member info */
-static void __copy_super(struct bch_sb *dst, struct bch_sb *src)
+static void __copy_super(struct bch_sb_handle *dst_handle, struct bch_sb *src)
{
struct bch_sb_field *src_f, *dst_f;
+ struct bch_sb *dst = dst_handle->sb;
dst->version = src->version;
dst->seq = src->seq;
@@ -405,8 +377,8 @@ static void __copy_super(struct bch_sb *dst, struct bch_sb *src)
continue;
dst_f = bch2_sb_field_get(dst, le32_to_cpu(src_f->type));
- dst_f = __bch2_sb_field_resize(dst, dst_f,
- le32_to_cpu(src_f->u64s));
+ dst_f = __bch2_sb_field_resize(dst_handle, dst_f,
+ le32_to_cpu(src_f->u64s));
memcpy(dst_f, src_f, vstruct_bytes(src_f));
}
@@ -423,11 +395,12 @@ int bch2_sb_to_fs(struct bch_fs *c, struct bch_sb *src)
lockdep_assert_held(&c->sb_lock);
- ret = bch2_fs_sb_realloc(c, le32_to_cpu(src->u64s) - journal_u64s);
+ ret = bch2_sb_realloc(&c->disk_sb,
+ le32_to_cpu(src->u64s) - journal_u64s);
if (ret)
return ret;
- __copy_super(c->disk_sb, src);
+ __copy_super(&c->disk_sb, src);
ret = bch2_sb_replicas_to_cpu_replicas(c);
if (ret)
@@ -443,7 +416,7 @@ int bch2_sb_to_fs(struct bch_fs *c, struct bch_sb *src)
int bch2_sb_from_fs(struct bch_fs *c, struct bch_dev *ca)
{
- struct bch_sb *src = c->disk_sb, *dst = ca->disk_sb.sb;
+ struct bch_sb *src = c->disk_sb.sb, *dst = ca->disk_sb.sb;
struct bch_sb_field_journal *journal_buckets =
bch2_sb_get_journal(dst);
unsigned journal_u64s = journal_buckets
@@ -456,7 +429,7 @@ int bch2_sb_from_fs(struct bch_fs *c, struct bch_dev *ca)
if (ret)
return ret;
- __copy_super(dst, src);
+ __copy_super(&ca->disk_sb, src);
return 0;
}
@@ -466,7 +439,6 @@ static const char *read_one_super(struct bch_sb_handle *sb, u64 offset)
{
struct bch_csum csum;
size_t bytes;
- unsigned order;
reread:
bio_reset(sb->bio, sb->bdev, REQ_OP_READ|REQ_SYNC|REQ_META);
sb->bio->bi_iter.bi_sector = offset;
@@ -489,9 +461,8 @@ reread:
if (bytes > 512 << sb->sb->layout.sb_max_size_bits)
return "Bad superblock: too big";
- order = get_order(bytes);
- if (order > sb->page_order) {
- if (__bch2_super_realloc(sb, order))
+ if (get_order(bytes) > sb->page_order) {
+ if (bch2_sb_realloc(sb, le32_to_cpu(sb->sb->u64s)))
return "cannot allocate memory";
goto reread;
}
@@ -521,7 +492,8 @@ int bch2_read_super(const char *path, struct bch_opts *opts,
pr_verbose_init(*opts, "");
memset(sb, 0, sizeof(*sb));
- sb->mode = FMODE_READ;
+ sb->mode = FMODE_READ;
+ sb->have_bio = true;
if (!opt_get(*opts, noexcl))
sb->mode |= FMODE_EXCL;
@@ -546,7 +518,7 @@ int bch2_read_super(const char *path, struct bch_opts *opts,
}
err = "cannot allocate memory";
- ret = __bch2_super_realloc(sb, 0);
+ ret = bch2_sb_realloc(sb, 0);
if (ret)
goto err;
@@ -610,6 +582,7 @@ got_super:
goto err;
ret = 0;
+ sb->have_layout = true;
out:
pr_verbose_init(*opts, "ret %i", ret);
return ret;
@@ -675,7 +648,7 @@ void bch2_write_super(struct bch_fs *c)
closure_init_stack(cl);
memset(&sb_written, 0, sizeof(sb_written));
- le64_add_cpu(&c->disk_sb->seq, 1);
+ le64_add_cpu(&c->disk_sb.sb->seq, 1);
for_each_online_member(ca, c, i)
bch2_sb_from_fs(c, ca);
diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h
index e6853fd6660f..6587a4d26429 100644
--- a/fs/bcachefs/super-io.h
+++ b/fs/bcachefs/super-io.h
@@ -12,8 +12,6 @@
struct bch_sb_field *bch2_sb_field_get(struct bch_sb *, enum bch_sb_field_type);
struct bch_sb_field *bch2_sb_field_resize(struct bch_sb_handle *,
enum bch_sb_field_type, unsigned);
-struct bch_sb_field *bch2_fs_sb_field_resize(struct bch_fs *,
- enum bch_sb_field_type, unsigned);
#define field_to_type(_f, _name) \
container_of_or_null(_f, struct bch_sb_field_##_name, field)
@@ -31,13 +29,6 @@ bch2_sb_resize_##_name(struct bch_sb_handle *sb, unsigned u64s) \
{ \
return field_to_type(bch2_sb_field_resize(sb, \
BCH_SB_FIELD_##_name, u64s), _name); \
-} \
- \
-static inline struct bch_sb_field_##_name * \
-bch2_fs_sb_resize_##_name(struct bch_fs *c, unsigned u64s) \
-{ \
- return field_to_type(bch2_fs_sb_field_resize(c, \
- BCH_SB_FIELD_##_name, u64s), _name); \
}
BCH_SB_FIELDS()
@@ -97,7 +88,7 @@ int bch2_sb_to_fs(struct bch_fs *, struct bch_sb *);
int bch2_sb_from_fs(struct bch_fs *, struct bch_dev *);
void bch2_free_super(struct bch_sb_handle *);
-int bch2_super_realloc(struct bch_sb_handle *, unsigned);
+int bch2_sb_realloc(struct bch_sb_handle *, unsigned);
const char *bch2_sb_validate(struct bch_sb_handle *);
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 62bf13b8e923..5c36fa61d4b6 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -133,7 +133,7 @@ static struct bch_fs *__bch2_uuid_to_fs(uuid_le uuid)
lockdep_assert_held(&bch_fs_list_lock);
list_for_each_entry(c, &bch_fs_list, list)
- if (!memcmp(&c->disk_sb->uuid, &uuid, sizeof(uuid_le)))
+ if (!memcmp(&c->disk_sb.sb->uuid, &uuid, sizeof(uuid_le)))
return c;
return NULL;
@@ -175,7 +175,7 @@ static void bch_fs_mark_clean(struct bch_fs *c)
!test_bit(BCH_FS_ERROR, &c->flags) &&
!test_bit(BCH_FS_EMERGENCY_RO, &c->flags)) {
mutex_lock(&c->sb_lock);
- SET_BCH_SB_CLEAN(c->disk_sb, true);
+ SET_BCH_SB_CLEAN(c->disk_sb.sb, true);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
}
@@ -394,7 +394,8 @@ static void bch2_fs_free(struct bch_fs *c)
if (c->wq)
destroy_workqueue(c->wq);
- free_pages((unsigned long) c->disk_sb, c->disk_sb_order);
+ free_pages((unsigned long) c->disk_sb.sb,
+ c->disk_sb.page_order);
kvpfree(c, sizeof(*c));
module_put(THIS_MODULE);
}
@@ -519,6 +520,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
__module_get(THIS_MODULE);
c->minor = -1;
+ c->disk_sb.fs_sb = true;
mutex_init(&c->state_lock);
mutex_init(&c->sb_lock);
@@ -630,9 +632,9 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
bch2_fs_fsio_init(c))
goto err;
- mi = bch2_sb_get_members(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
for (i = 0; i < c->sb.nr_devices; i++)
- if (bch2_dev_exists(c->disk_sb, mi, i) &&
+ if (bch2_dev_exists(c->disk_sb.sb, mi, i) &&
bch2_dev_alloc(c, i))
goto err;
@@ -688,7 +690,7 @@ const char *bch2_fs_start(struct bch_fs *c)
bch2_dev_allocator_add(c, ca);
bch2_recalc_capacity(c);
- if (BCH_SB_INITIALIZED(c->disk_sb)) {
+ if (BCH_SB_INITIALIZED(c->disk_sb.sb)) {
ret = bch2_journal_read(c, &journal);
if (ret)
goto err;
@@ -844,14 +846,14 @@ recovery_done:
}
mutex_lock(&c->sb_lock);
- mi = bch2_sb_get_members(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
now = ktime_get_seconds();
for_each_member_device(ca, c, i)
mi->members[ca->dev_idx].last_mount = cpu_to_le64(now);
- SET_BCH_SB_INITIALIZED(c->disk_sb, true);
- SET_BCH_SB_CLEAN(c->disk_sb, false);
+ SET_BCH_SB_INITIALIZED(c->disk_sb.sb, true);
+ SET_BCH_SB_CLEAN(c->disk_sb.sb, false);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
@@ -908,7 +910,7 @@ static const char *bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c)
return "mismatched block size";
if (le16_to_cpu(sb_mi->members[sb->dev_idx].bucket_size) <
- BCH_SB_BTREE_NODE_SIZE(c->disk_sb))
+ BCH_SB_BTREE_NODE_SIZE(c->disk_sb.sb))
return "new cache bucket size is too small";
return NULL;
@@ -1088,7 +1090,7 @@ static void bch2_dev_attach(struct bch_fs *c, struct bch_dev *ca,
static int bch2_dev_alloc(struct bch_fs *c, unsigned dev_idx)
{
struct bch_member *member =
- bch2_sb_get_members(c->disk_sb)->members + dev_idx;
+ bch2_sb_get_members(c->disk_sb.sb)->members + dev_idx;
struct bch_dev *ca = NULL;
int ret = 0;
@@ -1167,7 +1169,7 @@ static int bch2_dev_attach_bdev(struct bch_fs *c, struct bch_sb_handle *sb)
lockdep_assert_held(&c->state_lock);
if (le64_to_cpu(sb->sb->seq) >
- le64_to_cpu(c->disk_sb->seq))
+ le64_to_cpu(c->disk_sb.sb->seq))
bch2_sb_to_fs(c, sb->sb);
BUG_ON(sb->sb->dev_idx >= c->sb.nr_devices ||
@@ -1257,10 +1259,10 @@ static bool bch2_fs_may_start(struct bch_fs *c)
if (!c->opts.degraded) {
mutex_lock(&c->sb_lock);
- mi = bch2_sb_get_members(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
- for (i = 0; i < c->disk_sb->nr_devices; i++) {
- if (!bch2_dev_exists(c->disk_sb, mi, i))
+ for (i = 0; i < c->disk_sb.sb->nr_devices; i++) {
+ if (!bch2_dev_exists(c->disk_sb.sb, mi, i))
continue;
ca = bch_dev_locked(c, i);
@@ -1328,7 +1330,7 @@ int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca,
bch_notice(ca, "%s", bch2_dev_state[new_state]);
mutex_lock(&c->sb_lock);
- mi = bch2_sb_get_members(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
SET_BCH_MEMBER_STATE(&mi->members[ca->dev_idx], new_state);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
@@ -1438,7 +1440,7 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
* this device must be gone:
*/
mutex_lock(&c->sb_lock);
- mi = bch2_sb_get_members(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
memset(&mi->members[dev_idx].uuid, 0, sizeof(mi->members[dev_idx].uuid));
bch2_write_super(c);
@@ -1516,9 +1518,9 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
if (dynamic_fault("bcachefs:add:no_slot"))
goto no_slot;
- mi = bch2_sb_get_members(c->disk_sb);
+ mi = bch2_sb_get_members(c->disk_sb.sb);
for (dev_idx = 0; dev_idx < BCH_SB_MEMBERS_MAX; dev_idx++)
- if (!bch2_dev_exists(c->disk_sb, mi, dev_idx))
+ if (!bch2_dev_exists(c->disk_sb.sb, mi, dev_idx))
goto have_slot;
no_slot:
err = "no slots available in superblock";
@@ -1533,7 +1535,7 @@ have_slot:
err = "no space in superblock for member info";
ret = -ENOSPC;
- mi = bch2_fs_sb_resize_members(c, u64s);
+ mi = bch2_sb_resize_members(&c->disk_sb, u64s);
if (!mi)
goto err_unlock;
@@ -1541,7 +1543,7 @@ have_slot:
mi->members[dev_idx] = dev_mi;
mi->members[dev_idx].last_mount = cpu_to_le64(ktime_get_seconds());
- c->disk_sb->nr_devices = nr_devices;
+ c->disk_sb.sb->nr_devices = nr_devices;
ca->disk_sb.sb->dev_idx = dev_idx;
bch2_dev_attach(c, ca, dev_idx);
@@ -1592,7 +1594,7 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
dev_idx = sb.sb->dev_idx;
- err = bch2_dev_in_fs(c->disk_sb, sb.sb);
+ err = bch2_dev_in_fs(c->disk_sb.sb, sb.sb);
if (err)
goto err;
@@ -1667,7 +1669,7 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
}
mutex_lock(&c->sb_lock);
- mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
+ mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
mi->nbuckets = cpu_to_le64(nbuckets);
bch2_write_super(c);
@@ -1807,7 +1809,7 @@ static const char *__bch2_fs_open_incremental(struct bch_sb_handle *sb,
if (c) {
closure_get(&c->cl);
- err = bch2_dev_in_fs(c->disk_sb, sb->sb);
+ err = bch2_dev_in_fs(c->disk_sb.sb, sb->sb);
if (err)
goto err;
} else {
diff --git a/fs/bcachefs/super_types.h b/fs/bcachefs/super_types.h
index 2a4bd3ee1626..1023cd11e20a 100644
--- a/fs/bcachefs/super_types.h
+++ b/fs/bcachefs/super_types.h
@@ -8,6 +8,9 @@ struct bch_sb_handle {
struct bio *bio;
unsigned page_order;
fmode_t mode;
+ unsigned have_layout:1;
+ unsigned have_bio:1;
+ unsigned fs_sb:1;
};
struct bch_devs_mask {
diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c
index d4b9f0a6718b..c52f73f9c051 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -549,7 +549,7 @@ STORE(bch2_fs_opts_dir)
if (opt->set_sb != SET_NO_SB_OPT) {
mutex_lock(&c->sb_lock);
- opt->set_sb(c->disk_sb, v);
+ opt->set_sb(c->disk_sb.sb, v);
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
}
@@ -813,11 +813,14 @@ SHOW(bch2_dev)
sysfs_print(discard, ca->mi.discard);
if (attr == &sysfs_label) {
- if (ca->mi.group)
- out += bch2_disk_path_print(c, out, end - out,
+ if (ca->mi.group) {
+ mutex_lock(&c->sb_lock);
+ out += bch2_disk_path_print(&c->disk_sb, out, end - out,
ca->mi.group - 1);
- else
+ mutex_unlock(&c->sb_lock);
+ } else {
out += scnprintf(out, end - out, "none");
+ }
out += scnprintf(out, end - out, "\n");
return out - buf;
@@ -881,7 +884,7 @@ STORE(bch2_dev)
bool v = strtoul_or_return(buf);
mutex_lock(&c->sb_lock);
- mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
+ mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
if (v != BCH_MEMBER_DISCARD(mi)) {
SET_BCH_MEMBER_DISCARD(mi, v);
@@ -897,7 +900,7 @@ STORE(bch2_dev)
return v;
mutex_lock(&c->sb_lock);
- mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
+ mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
if ((unsigned) v != BCH_MEMBER_REPLACEMENT(mi)) {
SET_BCH_MEMBER_REPLACEMENT(mi, v);
diff --git a/include/trace/events/bcachefs.h b/include/trace/events/bcachefs.h
index 08f25c78818d..184e82028f0c 100644
--- a/include/trace/events/bcachefs.h
+++ b/include/trace/events/bcachefs.h
@@ -320,7 +320,7 @@ TRACE_EVENT(btree_gc_coalesce_fail,
TP_fast_assign(
__entry->reason = reason;
- memcpy(__entry->uuid, c->disk_sb->user_uuid.b, 16);
+ memcpy(__entry->uuid, c->disk_sb.sb->user_uuid.b, 16);
),
TP_printk("%pU: %u", __entry->uuid, __entry->reason)