summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-04-10 15:40:04 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2018-04-10 19:14:31 -0400
commitedf5f38218f699e53913a549465f35d36c4418f7 (patch)
tree5a59764865c3dd5921c3dd16a3c51ae4a99845ba
parentb5f4f54df802e4bd97b90b5d1955fc1d021106f4 (diff)
bcachefs: Refactor superblock code
this is so more code can be used by bcachefs format
-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, 193 insertions, 212 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index 362dfbdccb1e..bc10324f4e4a 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -519,8 +519,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 9ab04afa1a45..ad51f29c9a38 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -1038,8 +1038,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 ab5adca496bb..8403bae64038 100644
--- a/fs/bcachefs/chardev.c
+++ b/fs/bcachefs/chardev.c
@@ -463,7 +463,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 56bd99fd8b71..6d8543eb6500 100644
--- a/fs/bcachefs/checksum.c
+++ b/fs/bcachefs/checksum.c
@@ -569,7 +569,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;
@@ -623,7 +623,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;
@@ -639,7 +639,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);
@@ -657,7 +657,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);
@@ -668,7 +668,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;
@@ -685,7 +685,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;
@@ -694,7 +694,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);
@@ -728,7 +728,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 18c945985636..1af62621da1b 100644
--- a/fs/bcachefs/compress.c
+++ b/fs/bcachefs/compress.c
@@ -500,7 +500,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 4a7b1587914b..c129a33eb759 100644
--- a/fs/bcachefs/disk_groups.c
+++ b/fs/bcachefs/disk_groups.c
@@ -124,8 +124,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)
@@ -146,7 +146,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)];
@@ -218,11 +218,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;
@@ -240,11 +240,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);
}
@@ -263,14 +261,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;
@@ -282,22 +278,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;
@@ -335,48 +356,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);
@@ -403,7 +406,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;
@@ -444,7 +450,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 0ee3144912fa..9da9805af91c 100644
--- a/fs/bcachefs/disk_groups.h
+++ b/fs/bcachefs/disk_groups.h
@@ -82,13 +82,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 80178a29f7e6..bb03d83a53e4 100644
--- a/fs/bcachefs/quota.c
+++ b/fs/bcachefs/quota.c
@@ -409,7 +409,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;
@@ -486,13 +486,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);
@@ -509,13 +509,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);
@@ -626,9 +626,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 0e48e5ca4502..6c52d1d456c5 100644
--- a/fs/bcachefs/replicas.c
+++ b/fs/bcachefs/replicas.c
@@ -406,7 +406,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;
@@ -435,7 +435,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;
@@ -601,7 +601,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);
@@ -617,7 +617,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 5104dda42673..a2b981a3c9c5 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -36,14 +36,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;
@@ -54,13 +58,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;
}
@@ -78,26 +82,42 @@ 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) {
+ char buf[BDEVNAME_SIZE];
+
+ pr_err("%s: superblock too big: want %zu but have %llu",
+ bdevname(sb->bdev, buf), 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(GFP_KERNEL, 1 << order);
- if (!bio)
- return -ENOMEM;
+ if (sb->have_bio) {
+ bio = bio_kmalloc(GFP_KERNEL, 1 << order);
+ if (!bio)
+ return -ENOMEM;
- if (sb->bio)
- bio_put(sb->bio);
- sb->bio = bio;
+ if (sb->bio)
+ bio_put(sb->bio);
+ sb->bio = bio;
+ }
- new_sb = (void *) __get_free_pages(GFP_KERNEL, order);
+ new_sb = (void *) __get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
if (!new_sb)
return -ENOMEM;
@@ -112,45 +132,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) {
- char buf[BDEVNAME_SIZE];
-
- pr_err("%s: superblock too big: want %llu but have %llu",
- bdevname(sb->bdev, buf), 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)
@@ -162,38 +143,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;
-}
+ if (sb->fs_sb) {
+ struct bch_fs *c = container_of(sb, struct bch_fs, disk_sb);
+ struct bch_dev *ca;
+ unsigned i;
-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;
-
- 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;
}
@@ -354,7 +323,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;
@@ -377,9 +346,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;
@@ -403,8 +373,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));
}
@@ -421,11 +391,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)
@@ -441,7 +412,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
@@ -454,7 +425,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;
}
@@ -464,7 +435,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);
bio_set_dev(sb->bio, sb->bdev);
@@ -488,9 +458,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;
}
@@ -520,7 +489,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;
@@ -545,7 +515,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;
@@ -614,6 +584,7 @@ got_super:
bdev_get_queue(sb->bdev)->backing_dev_info->capabilities
|= BDI_CAP_STABLE_WRITES;
ret = 0;
+ sb->have_layout = true;
out:
pr_verbose_init(*opts, "ret %i", ret);
return ret;
@@ -681,7 +652,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 ed351a201813..f407c205b93b 100644
--- a/fs/bcachefs/super-io.h
+++ b/fs/bcachefs/super-io.h
@@ -11,8 +11,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)
@@ -30,13 +28,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()
@@ -96,7 +87,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 8b78ac3e4f5d..05910c404aec 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -124,7 +124,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;
@@ -205,7 +205,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);
}
@@ -424,7 +424,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);
}
@@ -550,6 +551,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);
@@ -661,9 +663,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;
@@ -719,7 +721,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;
@@ -875,14 +877,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);
@@ -939,7 +941,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;
@@ -1123,7 +1125,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;
@@ -1202,7 +1204,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 ||
@@ -1292,10 +1294,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);
@@ -1363,7 +1365,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);
@@ -1473,7 +1475,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);
@@ -1551,9 +1553,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";
@@ -1568,7 +1570,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;
@@ -1576,7 +1578,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);
@@ -1627,7 +1629,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;
@@ -1702,7 +1704,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);
@@ -1841,7 +1843,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 a402c107aa71..ab83ade959e4 100644
--- a/fs/bcachefs/super_types.h
+++ b/fs/bcachefs/super_types.h
@@ -7,6 +7,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 95127cd35cb3..e8089db9a1bd 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -548,7 +548,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);
}
@@ -812,11 +812,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;
@@ -880,7 +883,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);
@@ -896,7 +899,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 a7be2d8222d8..a34574ca8b0c 100644
--- a/include/trace/events/bcachefs.h
+++ b/include/trace/events/bcachefs.h
@@ -319,7 +319,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)