]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/disk_groups.c
Add a subcommand for resizing the journal
[bcachefs-tools-debian] / libbcachefs / disk_groups.c
index c129a33eb7590cb1909144344099c57501df655c..c52b6faac9b4982c3a4e5b201b21de6ee3293f95 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 #include "bcachefs.h"
 #include "disk_groups.h"
 #include "super-io.h"
@@ -16,8 +17,8 @@ static int group_cmp(const void *_l, const void *_r)
                strncmp(l->label, r->label, sizeof(l->label));
 }
 
-const char *bch2_sb_disk_groups_validate(struct bch_sb *sb,
-                                        struct bch_sb_field *f)
+static const char *bch2_sb_disk_groups_validate(struct bch_sb *sb,
+                                               struct bch_sb_field *f)
 {
        struct bch_sb_field_disk_groups *groups =
                field_to_type(f, disk_groups);
@@ -82,11 +83,10 @@ err:
        return err;
 }
 
-static size_t bch2_sb_disk_groups_to_text(char *buf, size_t size,
+static void bch2_sb_disk_groups_to_text(struct printbuf *out,
                                        struct bch_sb *sb,
                                        struct bch_sb_field *f)
 {
-       char *out = buf, *end = buf + size;
        struct bch_sb_field_disk_groups *groups =
                field_to_type(f, disk_groups);
        struct bch_disk_group *g;
@@ -96,18 +96,14 @@ static size_t bch2_sb_disk_groups_to_text(char *buf, size_t size,
             g < groups->entries + nr_groups;
             g++) {
                if (g != groups->entries)
-                       out += scnprintf(out, end - out, " ");
+                       pr_buf(out, " ");
 
                if (BCH_GROUP_DELETED(g))
-                       out += scnprintf(out, end - out, "[deleted]");
+                       pr_buf(out, "[deleted]");
                else
-                       out += scnprintf(out, end - out,
-                                        "[parent %llu name %s]",
-                                        BCH_GROUP_PARENT(g),
-                                        g->label);
+                       pr_buf(out, "[parent %llu name %s]",
+                              BCH_GROUP_PARENT(g), g->label);
        }
-
-       return out - buf;
 }
 
 const struct bch_sb_field_ops bch_sb_field_ops_disk_groups = {
@@ -162,7 +158,8 @@ int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
                }
        }
 
-       old_g = c->disk_groups;
+       old_g = rcu_dereference_protected(c->disk_groups,
+                               lockdep_is_held(&c->sb_lock));
        rcu_assign_pointer(c->disk_groups, cpu_g);
        if (old_g)
                kfree_rcu(old_g, rcu);
@@ -175,6 +172,8 @@ const struct bch_devs_mask *bch2_target_to_mask(struct bch_fs *c, unsigned targe
        struct target t = target_decode(target);
 
        switch (t.type) {
+       case TARGET_NULL:
+               return NULL;
        case TARGET_DEV: {
                struct bch_dev *ca = t.dev < c->sb.nr_devices
                        ? rcu_dereference(c->devs[t.dev])
@@ -184,7 +183,7 @@ const struct bch_devs_mask *bch2_target_to_mask(struct bch_fs *c, unsigned targe
        case TARGET_GROUP: {
                struct bch_disk_groups_cpu *g = rcu_dereference(c->disk_groups);
 
-               return t.group < g->nr && !g->entries[t.group].deleted
+               return g && t.group < g->nr && !g->entries[t.group].deleted
                        ? &g->entries[t.group].devs
                        : NULL;
        }
@@ -193,6 +192,36 @@ const struct bch_devs_mask *bch2_target_to_mask(struct bch_fs *c, unsigned targe
        }
 }
 
+bool bch2_dev_in_target(struct bch_fs *c, unsigned dev, unsigned target)
+{
+       struct target t = target_decode(target);
+
+       switch (t.type) {
+       case TARGET_NULL:
+               return false;
+       case TARGET_DEV:
+               return dev == t.dev;
+       case TARGET_GROUP: {
+               struct bch_disk_groups_cpu *g;
+               const struct bch_devs_mask *m;
+               bool ret;
+
+               rcu_read_lock();
+               g = rcu_dereference(c->disk_groups);
+               m = g && t.group < g->nr && !g->entries[t.group].deleted
+                       ? &g->entries[t.group].devs
+                       : NULL;
+
+               ret = m ? test_bit(dev, m->d) : false;
+               rcu_read_unlock();
+
+               return ret;
+       }
+       default:
+               BUG();
+       }
+}
+
 static int __bch2_disk_group_find(struct bch_sb_field_disk_groups *groups,
                                  unsigned parent,
                                  const char *name, unsigned namelen)
@@ -309,10 +338,10 @@ int bch2_disk_path_find_or_create(struct bch_sb_handle *sb, const char *name)
        return v;
 }
 
-int bch2_disk_path_print(struct bch_sb_handle *sb,
-                        char *buf, size_t len, unsigned v)
+void bch2_disk_path_to_text(struct printbuf *out,
+                           struct bch_sb_handle *sb,
+                           unsigned v)
 {
-       char *out = buf, *end = out + len;
        struct bch_sb_field_disk_groups *groups =
                bch2_sb_get_disk_groups(sb->sb);
        struct bch_disk_group *g;
@@ -340,32 +369,25 @@ int bch2_disk_path_print(struct bch_sb_handle *sb,
        }
 
        while (nr) {
-               unsigned b = 0;
-
                v = path[--nr];
                g = groups->entries + v;
 
-               if (end != out)
-                       b = min_t(size_t, end - out,
-                                 strnlen(g->label, sizeof(g->label)));
-               memcpy(out, g->label, b);
-               if (b < end - out)
-                       out[b] = '\0';
-               out += b;
+               bch_scnmemcpy(out, g->label,
+                             strnlen(g->label, sizeof(g->label)));
 
                if (nr)
-                       out += scnprintf(out, end - out, ".");
+                       pr_buf(out, ".");
        }
-
-       return out - buf;
+       return;
 inval:
-       return scnprintf(buf, len, "invalid group %u", v);
+       pr_buf(out, "invalid group %u", v);
 }
 
 int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
 {
        struct bch_member *mi;
        int v = -1;
+       int ret = 0;
 
        mutex_lock(&c->sb_lock);
 
@@ -378,14 +400,18 @@ int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
                return v;
        }
 
+       ret = bch2_sb_disk_groups_to_cpu(c);
+       if (ret)
+               goto unlock;
 write_sb:
        mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
        SET_BCH_MEMBER_GROUP(mi, v + 1);
 
        bch2_write_super(c);
+unlock:
        mutex_unlock(&c->sb_lock);
 
-       return 0;
+       return ret;
 }
 
 int bch2_opt_target_parse(struct bch_fs *c, const char *buf, u64 *v)
@@ -418,14 +444,14 @@ int bch2_opt_target_parse(struct bch_fs *c, const char *buf, u64 *v)
        return -EINVAL;
 }
 
-int bch2_opt_target_print(struct bch_fs *c, char *buf, size_t len, u64 v)
+void bch2_opt_target_to_text(struct printbuf *out, struct bch_fs *c, u64 v)
 {
        struct target t = target_decode(v);
-       int ret;
 
        switch (t.type) {
        case TARGET_NULL:
-               return scnprintf(buf, len, "none");
+               pr_buf(out, "none");
+               break;
        case TARGET_DEV: {
                struct bch_dev *ca;
 
@@ -437,13 +463,13 @@ int bch2_opt_target_print(struct bch_fs *c, char *buf, size_t len, u64 v)
                if (ca && percpu_ref_tryget(&ca->io_ref)) {
                        char b[BDEVNAME_SIZE];
 
-                       ret = scnprintf(buf, len, "/dev/%s",
-                                       bdevname(ca->disk_sb.bdev, b));
+                       pr_buf(out, "/dev/%s",
+                            bdevname(ca->disk_sb.bdev, b));
                        percpu_ref_put(&ca->io_ref);
                } else if (ca) {
-                       ret = scnprintf(buf, len, "offline device %u", t.dev);
+                       pr_buf(out, "offline device %u", t.dev);
                } else {
-                       ret = scnprintf(buf, len, "invalid device %u", t.dev);
+                       pr_buf(out, "invalid device %u", t.dev);
                }
 
                rcu_read_unlock();
@@ -451,12 +477,10 @@ int bch2_opt_target_print(struct bch_fs *c, char *buf, size_t len, u64 v)
        }
        case TARGET_GROUP:
                mutex_lock(&c->sb_lock);
-               ret = bch2_disk_path_print(&c->disk_sb, buf, len, t.group);
+               bch2_disk_path_to_text(out, &c->disk_sb, t.group);
                mutex_unlock(&c->sb_lock);
                break;
        default:
                BUG();
        }
-
-       return ret;
 }