// 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>
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;
}
}
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);
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,
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;
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;
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)
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;
}