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;
g = BCH_MEMBER_GROUP(m) - 1;
if (g >= nr_groups) {
- pr_buf(err, "disk %u has invalid label %u (have %u)",
+ prt_printf(err, "disk %u has invalid label %u (have %u)",
i, g, nr_groups);
- return -EINVAL;
+ return -BCH_ERR_invalid_sb_disk_groups;
}
if (BCH_GROUP_DELETED(&groups->entries[g])) {
- pr_buf(err, "disk %u has deleted label %u", i, g);
- return -EINVAL;
+ prt_printf(err, "disk %u has deleted label %u", i, g);
+ return -BCH_ERR_invalid_sb_disk_groups;
}
}
len = strnlen(g->label, sizeof(g->label));
if (!len) {
- pr_buf(err, "label %u empty", i);
- return -EINVAL;
+ prt_printf(err, "label %u empty", i);
+ 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);
for (g = sorted; g + 1 < sorted + nr_groups; g++)
if (!BCH_GROUP_DELETED(g) &&
!group_cmp(&g[0], &g[1])) {
- pr_buf(err, "duplicate label %llu.%.*s",
+ 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,
g < groups->entries + nr_groups;
g++) {
if (g != groups->entries)
- pr_buf(out, " ");
+ prt_printf(out, " ");
if (BCH_GROUP_DELETED(g))
- pr_buf(out, "[deleted]");
+ prt_printf(out, "[deleted]");
else
- pr_buf(out, "[parent %llu name %s]",
+ prt_printf(out, "[parent %llu name %s]",
BCH_GROUP_PARENT(g), g->label);
}
}
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;
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)
groups = bch2_sb_resize_disk_groups(sb, u64s);
if (!groups)
- return -ENOSPC;
+ return -BCH_ERR_ENOSPC_disk_label_add;
nr_groups = disk_groups_nr(groups);
}
v = path[--nr];
g = groups->entries + v;
- pr_buf(out, "%.*s", (int) sizeof(g->label), g->label);
+ prt_printf(out, "%.*s", (int) sizeof(g->label), g->label);
if (nr)
- pr_buf(out, ".");
+ prt_printf(out, ".");
}
return;
inval:
- pr_buf(out, "invalid label %u", v);
+ prt_printf(out, "invalid label %u", v);
}
-int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
+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);
+ int ret, v = -1;
if (!strlen(name) || !strcmp(name, "none"))
- goto write_sb;
+ return 0;
v = bch2_disk_path_find_or_create(&c->disk_sb, name);
- if (v < 0) {
- mutex_unlock(&c->sb_lock);
+ if (v < 0)
return v;
- }
ret = bch2_sb_disk_groups_to_cpu(c);
if (ret)
- goto unlock;
-write_sb:
+ return ret;
+
mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
SET_BCH_MEMBER_GROUP(mi, v + 1);
+ return 0;
+}
- bch2_write_super(c);
-unlock:
+int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
+{
+ int ret;
+
+ mutex_lock(&c->sb_lock);
+ ret = __bch2_dev_group_set(c, ca, name) ?:
+ bch2_write_super(c);
mutex_unlock(&c->sb_lock);
return ret;
switch (t.type) {
case TARGET_NULL:
- pr_buf(out, "none");
+ prt_printf(out, "none");
break;
case TARGET_DEV:
if (c) {
: NULL;
if (ca && percpu_ref_tryget(&ca->io_ref)) {
- char b[BDEVNAME_SIZE];
-
- pr_buf(out, "/dev/%s",
- bdevname(ca->disk_sb.bdev, b));
+ prt_printf(out, "/dev/%pg", ca->disk_sb.bdev);
percpu_ref_put(&ca->io_ref);
} else if (ca) {
- pr_buf(out, "offline device %u", t.dev);
+ prt_printf(out, "offline device %u", t.dev);
} else {
- pr_buf(out, "invalid device %u", t.dev);
+ prt_printf(out, "invalid device %u", t.dev);
}
rcu_read_unlock();
struct bch_member *m = mi->members + t.dev;
if (bch2_dev_exists(sb, mi, t.dev)) {
- pr_buf(out, "Device ");
+ prt_printf(out, "Device ");
pr_uuid(out, m->uuid.b);
- pr_buf(out, " (%u)", t.dev);
+ prt_printf(out, " (%u)", t.dev);
} else {
- pr_buf(out, "Bad device %u", t.dev);
+ prt_printf(out, "Bad device %u", t.dev);
}
}
break;