]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/super.c
Update bcachefs sources to 7bf1ac0d46 bcachefs: Correctly initialize new buckets...
[bcachefs-tools-debian] / libbcachefs / super.c
index 1347270e5045dce80566e3c8fdb98a88bee11c94..2014f7816f6679fd7436b33252cdfd3686618de2 100644 (file)
@@ -49,6 +49,7 @@
 #include "recovery.h"
 #include "replicas.h"
 #include "sb-clean.h"
+#include "sb-members.h"
 #include "snapshot.h"
 #include "subvolume.h"
 #include "super.h"
@@ -399,6 +400,10 @@ static int __bch2_fs_read_write(struct bch_fs *c, bool early)
 
        bch_info(c, "going read-write");
 
+       ret = bch2_members_v2_init(c);
+       if (ret)
+               goto err;
+
        ret = bch2_fs_mark_dirty(c);
        if (ret)
                goto err;
@@ -662,7 +667,6 @@ err:
 
 static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
 {
-       struct bch_sb_field_members *mi;
        struct bch_fs *c;
        struct printbuf name = PRINTBUF;
        unsigned i, iter_size;
@@ -858,9 +862,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
        if (ret)
                goto err;
 
-       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.sb, mi, i) &&
+               if (bch2_dev_exists(c->disk_sb.sb, i) &&
                    bch2_dev_alloc(c, i)) {
                        ret = -EEXIST;
                        goto err;
@@ -925,7 +928,6 @@ static void print_mount_opts(struct bch_fs *c)
 
 int bch2_fs_start(struct bch_fs *c)
 {
-       struct bch_sb_field_members *mi;
        struct bch_dev *ca;
        time64_t now = ktime_get_real_seconds();
        unsigned i;
@@ -939,12 +941,17 @@ int bch2_fs_start(struct bch_fs *c)
 
        mutex_lock(&c->sb_lock);
 
+       ret = bch2_members_v2_init(c);
+       if (ret) {
+               mutex_unlock(&c->sb_lock);
+               goto err;
+       }
+
        for_each_online_member(ca, c, i)
                bch2_sb_from_fs(c, ca);
 
-       mi = bch2_sb_get_members(c->disk_sb.sb);
        for_each_online_member(ca, c, i)
-               mi->members[ca->dev_idx].last_mount = cpu_to_le64(now);
+               bch2_members_v2_get_mut(c->disk_sb.sb, i)->last_mount = cpu_to_le64(now);
 
        mutex_unlock(&c->sb_lock);
 
@@ -997,16 +1004,12 @@ err:
 
 static int bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c)
 {
-       struct bch_sb_field_members *sb_mi;
-
-       sb_mi = bch2_sb_get_members(sb);
-       if (!sb_mi)
-               return -BCH_ERR_member_info_missing;
+       struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
 
        if (le16_to_cpu(sb->block_size) != block_sectors(c))
                return -BCH_ERR_mismatched_block_size;
 
-       if (le16_to_cpu(sb_mi->members[sb->dev_idx].bucket_size) <
+       if (le16_to_cpu(m.bucket_size) <
            BCH_SB_BTREE_NODE_SIZE(c->disk_sb.sb))
                return -BCH_ERR_bucket_size_too_small;
 
@@ -1017,12 +1020,11 @@ static int bch2_dev_in_fs(struct bch_sb *fs, struct bch_sb *sb)
 {
        struct bch_sb *newest =
                le64_to_cpu(fs->seq) > le64_to_cpu(sb->seq) ? fs : sb;
-       struct bch_sb_field_members *mi = bch2_sb_get_members(newest);
 
        if (!uuid_equal(&fs->uuid, &sb->uuid))
                return -BCH_ERR_device_not_a_member_of_filesystem;
 
-       if (!bch2_dev_exists(newest, mi, sb->dev_idx))
+       if (!bch2_dev_exists(newest, sb->dev_idx))
                return -BCH_ERR_device_has_been_removed;
 
        if (fs->block_size != sb->block_size)
@@ -1192,15 +1194,14 @@ 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.sb)->members + dev_idx;
+       struct bch_member member = bch2_sb_member_get(c->disk_sb.sb, dev_idx);
        struct bch_dev *ca = NULL;
        int ret = 0;
 
        if (bch2_fs_init_fault("dev_alloc"))
                goto err;
 
-       ca = __bch2_dev_alloc(c, member);
+       ca = __bch2_dev_alloc(c, &member);
        if (!ca)
                goto err;
 
@@ -1335,7 +1336,6 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca,
 
 static bool bch2_fs_may_start(struct bch_fs *c)
 {
-       struct bch_sb_field_members *mi;
        struct bch_dev *ca;
        unsigned i, flags = 0;
 
@@ -1348,10 +1348,9 @@ static bool bch2_fs_may_start(struct bch_fs *c)
        if (!c->opts.degraded &&
            !c->opts.very_degraded) {
                mutex_lock(&c->sb_lock);
-               mi = bch2_sb_get_members(c->disk_sb.sb);
 
                for (i = 0; i < c->disk_sb.sb->nr_devices; i++) {
-                       if (!bch2_dev_exists(c->disk_sb.sb, mi, i))
+                       if (!bch2_dev_exists(c->disk_sb.sb, i))
                                continue;
 
                        ca = bch_dev_locked(c, i);
@@ -1391,7 +1390,7 @@ static void __bch2_dev_read_write(struct bch_fs *c, struct bch_dev *ca)
 int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca,
                         enum bch_member_state new_state, int flags)
 {
-       struct bch_sb_field_members *mi;
+       struct bch_member *m;
        int ret = 0;
 
        if (ca->mi.state == new_state)
@@ -1406,8 +1405,8 @@ int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca,
        bch_notice(ca, "%s", bch2_member_states[new_state]);
 
        mutex_lock(&c->sb_lock);
-       mi = bch2_sb_get_members(c->disk_sb.sb);
-       SET_BCH_MEMBER_STATE(&mi->members[ca->dev_idx], new_state);
+       m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
+       SET_BCH_MEMBER_STATE(m, new_state);
        bch2_write_super(c);
        mutex_unlock(&c->sb_lock);
 
@@ -1463,7 +1462,7 @@ static int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
 
 int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
 {
-       struct bch_sb_field_members *mi;
+       struct bch_member *m;
        unsigned dev_idx = ca->dev_idx, data;
        int ret;
 
@@ -1551,8 +1550,8 @@ 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.sb);
-       memset(&mi->members[dev_idx].uuid, 0, sizeof(mi->members[dev_idx].uuid));
+       m = bch2_members_v2_get_mut(c->disk_sb.sb, dev_idx);
+       memset(&m->uuid, 0, sizeof(m->uuid));
 
        bch2_write_super(c);
 
@@ -1575,7 +1574,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
        struct bch_opts opts = bch2_opts_empty();
        struct bch_sb_handle sb;
        struct bch_dev *ca = NULL;
-       struct bch_sb_field_members *mi;
+       struct bch_sb_field_members_v2 *mi;
        struct bch_member dev_mi;
        unsigned dev_idx, nr_devices, u64s;
        struct printbuf errbuf = PRINTBUF;
@@ -1588,7 +1587,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
                goto err;
        }
 
-       dev_mi = bch2_sb_get_members(sb.sb)->members[sb.sb->dev_idx];
+       dev_mi = bch2_sb_member_get(sb.sb, sb.sb->dev_idx);
 
        if (BCH_MEMBER_GROUP(&dev_mi)) {
                bch2_disk_path_to_text(&label, sb.sb, BCH_MEMBER_GROUP(&dev_mi) - 1);
@@ -1631,9 +1630,9 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
                goto err_unlock;
        }
 
-       mi = bch2_sb_get_members(ca->disk_sb.sb);
+       mi = bch2_sb_get_members_v2(ca->disk_sb.sb);
 
-       if (!bch2_sb_resize_members(&ca->disk_sb,
+       if (!bch2_sb_resize_members_v2(&ca->disk_sb,
                                le32_to_cpu(mi->field.u64s) +
                                sizeof(dev_mi) / sizeof(u64))) {
                ret = -BCH_ERR_ENOSPC_sb_members;
@@ -1644,9 +1643,8 @@ 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.sb);
        for (dev_idx = 0; dev_idx < BCH_SB_MEMBERS_MAX; dev_idx++)
-               if (!bch2_dev_exists(c->disk_sb.sb, mi, dev_idx))
+               if (!bch2_dev_exists(c->disk_sb.sb, dev_idx))
                        goto have_slot;
 no_slot:
        ret = -BCH_ERR_ENOSPC_sb_members;
@@ -1655,20 +1653,21 @@ no_slot:
 
 have_slot:
        nr_devices = max_t(unsigned, dev_idx + 1, c->sb.nr_devices);
-       u64s = (sizeof(struct bch_sb_field_members) +
-               sizeof(struct bch_member) * nr_devices) / sizeof(u64);
+       u64s = DIV_ROUND_UP(sizeof(struct bch_sb_field_members_v2) +
+                           le16_to_cpu(mi->member_bytes) * nr_devices, sizeof(u64));
 
-       mi = bch2_sb_resize_members(&c->disk_sb, u64s);
+       mi = bch2_sb_resize_members_v2(&c->disk_sb, u64s);
        if (!mi) {
                ret = -BCH_ERR_ENOSPC_sb_members;
                bch_err_msg(c, ret, "setting up new superblock");
                goto err_unlock;
        }
+       struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, dev_idx);
 
        /* success: */
 
-       mi->members[dev_idx] = dev_mi;
-       mi->members[dev_idx].last_mount = cpu_to_le64(ktime_get_real_seconds());
+       *m = dev_mi;
+       m->last_mount = cpu_to_le64(ktime_get_real_seconds());
        c->disk_sb.sb->nr_devices       = nr_devices;
 
        ca->disk_sb.sb->dev_idx = dev_idx;
@@ -1728,7 +1727,6 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
 {
        struct bch_opts opts = bch2_opts_empty();
        struct bch_sb_handle sb = { NULL };
-       struct bch_sb_field_members *mi;
        struct bch_dev *ca;
        unsigned dev_idx;
        int ret;
@@ -1765,9 +1763,9 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
                __bch2_dev_read_write(c, ca);
 
        mutex_lock(&c->sb_lock);
-       mi = bch2_sb_get_members(c->disk_sb.sb);
+       struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
 
-       mi->members[ca->dev_idx].last_mount =
+       m->last_mount =
                cpu_to_le64(ktime_get_real_seconds());
 
        bch2_write_super(c);
@@ -1809,10 +1807,12 @@ int bch2_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags)
 
 int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
 {
-       struct bch_member *mi;
+       struct bch_member *m;
+       u64 old_nbuckets;
        int ret = 0;
 
        down_write(&c->state_lock);
+       old_nbuckets = ca->mi.nbuckets;
 
        if (nbuckets < ca->mi.nbuckets) {
                bch_err(ca, "Cannot shrink yet");
@@ -1839,12 +1839,24 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
                goto err;
 
        mutex_lock(&c->sb_lock);
-       mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
-       mi->nbuckets = cpu_to_le64(nbuckets);
+       m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
+       m->nbuckets = cpu_to_le64(nbuckets);
 
        bch2_write_super(c);
        mutex_unlock(&c->sb_lock);
 
+       if (ca->mi.freespace_initialized) {
+               ret = bch2_dev_freespace_init(c, ca, old_nbuckets, nbuckets);
+               if (ret)
+                       goto err;
+
+               /*
+                * XXX: this is all wrong transactionally - we'll be able to do
+                * this correctly after the disk space accounting rewrite
+                */
+               ca->usage_base->d[BCH_DATA_free].buckets += nbuckets - old_nbuckets;
+       }
+
        bch2_recalc_capacity(c);
 err:
        up_write(&c->state_lock);
@@ -1875,7 +1887,6 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
 {
        struct bch_sb_handle *sb = NULL;
        struct bch_fs *c = NULL;
-       struct bch_sb_field_members *mi;
        unsigned i, best_sb = 0;
        struct printbuf errbuf = PRINTBUF;
        int ret = 0;
@@ -1906,12 +1917,10 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
                    le64_to_cpu(sb[best_sb].sb->seq))
                        best_sb = i;
 
-       mi = bch2_sb_get_members(sb[best_sb].sb);
-
        i = 0;
        while (i < nr_devices) {
                if (i != best_sb &&
-                   !bch2_dev_exists(sb[best_sb].sb, mi, sb[i].sb->dev_idx)) {
+                   !bch2_dev_exists(sb[best_sb].sb, sb[i].sb->dev_idx)) {
                        pr_info("%pg has been removed, skipping", sb[i].bdev);
                        bch2_free_super(&sb[i]);
                        array_remove_item(sb, nr_devices, i);