]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/disk_groups.c
Update bcachefs sources to f9c612bbf82d bcachefs: Fixes for building in userspace
[bcachefs-tools-debian] / libbcachefs / disk_groups.c
index 6b81f35861aca327dd6b50e42b2194edf8fc7cec..b292dbef799211ca71bf132152c9d9d5ff464d70 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "bcachefs.h"
 #include "disk_groups.h"
+#include "sb-members.h"
 #include "super-io.h"
 
 #include <linux/sort.h>
@@ -27,26 +28,26 @@ static int bch2_sb_disk_groups_validate(struct bch_sb *sb,
        struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
        unsigned nr_groups = disk_groups_nr(groups);
        unsigned i, len;
-       int ret = -EINVAL;
+       int ret = 0;
 
        for (i = 0; i < sb->nr_devices; i++) {
                struct bch_member *m = mi->members + i;
-               unsigned g;
+               unsigned group_id;
 
                if (!BCH_MEMBER_GROUP(m))
                        continue;
 
-               g = BCH_MEMBER_GROUP(m) - 1;
+               group_id = BCH_MEMBER_GROUP(m) - 1;
 
-               if (g >= nr_groups) {
+               if (group_id >= nr_groups) {
                        prt_printf(err, "disk %u has invalid label %u (have %u)",
-                              i, g, nr_groups);
-                       return -EINVAL;
+                                  i, group_id, nr_groups);
+                       return -BCH_ERR_invalid_sb_disk_groups;
                }
 
-               if (BCH_GROUP_DELETED(&groups->entries[g])) {
-                       prt_printf(err, "disk %u has deleted label %u", i, g);
-                       return -EINVAL;
+               if (BCH_GROUP_DELETED(&groups->entries[group_id])) {
+                       prt_printf(err, "disk %u has deleted label %u", i, group_id);
+                       return -BCH_ERR_invalid_sb_disk_groups;
                }
        }
 
@@ -62,13 +63,13 @@ static int bch2_sb_disk_groups_validate(struct bch_sb *sb,
                len = strnlen(g->label, sizeof(g->label));
                if (!len) {
                        prt_printf(err, "label %u empty", i);
-                       return -EINVAL;
+                       return -BCH_ERR_invalid_sb_disk_groups;
                }
        }
 
        sorted = kmalloc_array(nr_groups, sizeof(*sorted), GFP_KERNEL);
        if (!sorted)
-               return -ENOMEM;
+               return -BCH_ERR_ENOMEM_disk_groups_validate;
 
        memcpy(sorted, groups->entries, nr_groups * sizeof(*sorted));
        sort(sorted, nr_groups, sizeof(*sorted), group_cmp, NULL);
@@ -79,13 +80,46 @@ static int bch2_sb_disk_groups_validate(struct bch_sb *sb,
                        prt_printf(err, "duplicate label %llu.%.*s",
                               BCH_GROUP_PARENT(g),
                               (int) sizeof(g->label), g->label);
+                       ret = -BCH_ERR_invalid_sb_disk_groups;
                        goto err;
                }
-
-       ret = 0;
 err:
        kfree(sorted);
-       return 0;
+       return ret;
+}
+
+void bch2_disk_groups_to_text(struct printbuf *out, struct bch_fs *c)
+{
+       struct bch_disk_groups_cpu *g;
+       struct bch_dev *ca;
+       int i;
+       unsigned iter;
+
+       out->atomic++;
+       rcu_read_lock();
+
+       g = rcu_dereference(c->disk_groups);
+       if (!g)
+               goto out;
+
+       for (i = 0; i < g->nr; i++) {
+               if (i)
+                       prt_printf(out, " ");
+
+               if (g->entries[i].deleted) {
+                       prt_printf(out, "[deleted]");
+                       continue;
+               }
+
+               prt_printf(out, "[parent %d devs", g->entries[i].parent);
+               for_each_member_device_rcu(ca, c, iter, &g->entries[i].devs)
+                       prt_printf(out, " %s", ca->name);
+               prt_printf(out, "]");
+       }
+
+out:
+       rcu_read_unlock();
+       out->atomic--;
 }
 
 static void bch2_sb_disk_groups_to_text(struct printbuf *out,
@@ -135,7 +169,7 @@ int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
        cpu_g = kzalloc(sizeof(*cpu_g) +
                        sizeof(cpu_g->entries[0]) * nr_groups, GFP_KERNEL);
        if (!cpu_g)
-               return -ENOMEM;
+               return -BCH_ERR_ENOMEM_disk_groups_to_cpu;
 
        cpu_g->nr = nr_groups;
 
@@ -149,8 +183,7 @@ int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
 
        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)];
+               struct bch_disk_group_cpu *dst;
 
                if (!bch2_member_exists(m))
                        continue;
@@ -175,26 +208,36 @@ int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
 const struct bch_devs_mask *bch2_target_to_mask(struct bch_fs *c, unsigned target)
 {
        struct target t = target_decode(target);
+       struct bch_devs_mask *devs;
+
+       rcu_read_lock();
 
        switch (t.type) {
        case TARGET_NULL:
-               return NULL;
+               devs = NULL;
+               break;
        case TARGET_DEV: {
                struct bch_dev *ca = t.dev < c->sb.nr_devices
                        ? rcu_dereference(c->devs[t.dev])
                        : NULL;
-               return ca ? &ca->self : NULL;
+               devs = ca ? &ca->self : NULL;
+               break;
        }
        case TARGET_GROUP: {
                struct bch_disk_groups_cpu *g = rcu_dereference(c->disk_groups);
 
-               return g && t.group < g->nr && !g->entries[t.group].deleted
+               devs = g && t.group < g->nr && !g->entries[t.group].deleted
                        ? &g->entries[t.group].devs
                        : NULL;
+               break;
        }
        default:
                BUG();
        }
+
+       rcu_read_unlock();
+
+       return devs;
 }
 
 bool bch2_dev_in_target(struct bch_fs *c, unsigned dev, unsigned target)
@@ -417,30 +460,37 @@ int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
        return ret;
 }
 
-int bch2_opt_target_parse(struct bch_fs *c, const char *buf, u64 *v)
+int bch2_opt_target_parse(struct bch_fs *c, const char *val, u64 *res,
+                         struct printbuf *err)
 {
        struct bch_dev *ca;
        int g;
 
-       if (!strlen(buf) || !strcmp(buf, "none")) {
-               *v = 0;
+       if (!val)
+               return -EINVAL;
+
+       if (!c)
+               return 0;
+
+       if (!strlen(val) || !strcmp(val, "none")) {
+               *res = 0;
                return 0;
        }
 
        /* Is it a device? */
-       ca = bch2_dev_lookup(c, buf);
+       ca = bch2_dev_lookup(c, val);
        if (!IS_ERR(ca)) {
-               *v = dev_to_target(ca->dev_idx);
+               *res = dev_to_target(ca->dev_idx);
                percpu_ref_put(&ca->ref);
                return 0;
        }
 
        mutex_lock(&c->sb_lock);
-       g = bch2_disk_path_find(&c->disk_sb, buf);
+       g = bch2_disk_path_find(&c->disk_sb, val);
        mutex_unlock(&c->sb_lock);
 
        if (g >= 0) {
-               *v = group_to_target(g);
+               *res = group_to_target(g);
                return 0;
        }