summaryrefslogtreecommitdiff
path: root/libbcachefs/super-io.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/super-io.c')
-rw-r--r--libbcachefs/super-io.c167
1 files changed, 135 insertions, 32 deletions
diff --git a/libbcachefs/super-io.c b/libbcachefs/super-io.c
index 3f55c244..deff918a 100644
--- a/libbcachefs/super-io.c
+++ b/libbcachefs/super-io.c
@@ -877,10 +877,40 @@ static inline unsigned replicas_dev_slots(struct bch_replicas_cpu *r)
offsetof(struct bch_replicas_cpu_entry, devs)) * 8;
}
-static unsigned bkey_to_replicas(struct bkey_s_c_extent e,
- enum bch_data_type data_type,
- struct bch_replicas_cpu_entry *r,
- unsigned *max_dev)
+int bch2_cpu_replicas_to_text(struct bch_replicas_cpu *r,
+ char *buf, size_t size)
+{
+ char *out = buf, *end = out + size;
+ struct bch_replicas_cpu_entry *e;
+ bool first = true;
+ unsigned i;
+
+ for_each_cpu_replicas_entry(r, e) {
+ bool first_e = true;
+
+ if (!first)
+ out += scnprintf(out, end - out, " ");
+ first = false;
+
+ out += scnprintf(out, end - out, "%u: [", e->data_type);
+
+ for (i = 0; i < replicas_dev_slots(r); i++)
+ if (replicas_test_dev(e, i)) {
+ if (!first_e)
+ out += scnprintf(out, end - out, " ");
+ first_e = false;
+ out += scnprintf(out, end - out, "%u", i);
+ }
+ out += scnprintf(out, end - out, "]");
+ }
+
+ return out - buf;
+}
+
+static inline unsigned bkey_to_replicas(struct bkey_s_c_extent e,
+ enum bch_data_type data_type,
+ struct bch_replicas_cpu_entry *r,
+ unsigned *max_dev)
{
const struct bch_extent_ptr *ptr;
unsigned nr = 0;
@@ -903,6 +933,28 @@ static unsigned bkey_to_replicas(struct bkey_s_c_extent e,
return nr;
}
+static inline void devlist_to_replicas(struct bch_devs_list devs,
+ enum bch_data_type data_type,
+ struct bch_replicas_cpu_entry *r,
+ unsigned *max_dev)
+{
+ unsigned i;
+
+ BUG_ON(!data_type ||
+ data_type == BCH_DATA_SB ||
+ data_type >= BCH_DATA_NR);
+
+ memset(r, 0, sizeof(*r));
+ r->data_type = data_type;
+
+ *max_dev = 0;
+
+ for (i = 0; i < devs.nr; i++) {
+ *max_dev = max_t(unsigned, *max_dev, devs.devs[i]);
+ replicas_set_dev(r, devs.devs[i]);
+ }
+}
+
static struct bch_replicas_cpu *
cpu_replicas_add_entry(struct bch_replicas_cpu *old,
struct bch_replicas_cpu_entry new_entry,
@@ -952,7 +1004,7 @@ static int bch2_check_mark_super_slowpath(struct bch_fs *c,
struct bch_replicas_cpu_entry new_entry,
unsigned max_dev)
{
- struct bch_replicas_cpu *old_gc, *new_gc = NULL, *old_r, *new_r;
+ struct bch_replicas_cpu *old_gc, *new_gc = NULL, *old_r, *new_r = NULL;
int ret = -ENOMEM;
mutex_lock(&c->sb_lock);
@@ -967,31 +1019,37 @@ static int bch2_check_mark_super_slowpath(struct bch_fs *c,
old_r = rcu_dereference_protected(c->replicas,
lockdep_is_held(&c->sb_lock));
- /* recheck, might have raced */
- if (replicas_has_entry(old_r, new_entry, max_dev))
- goto out;
+ if (!replicas_has_entry(old_r, new_entry, max_dev)) {
+ new_r = cpu_replicas_add_entry(old_r, new_entry, max_dev);
+ if (!new_r)
+ goto err;
- new_r = cpu_replicas_add_entry(old_r, new_entry, max_dev);
- if (!new_r)
- goto err;
+ ret = bch2_cpu_replicas_to_sb_replicas(c, new_r);
+ if (ret)
+ goto err;
+ }
- ret = bch2_cpu_replicas_to_sb_replicas(c, new_r);
- if (ret)
- goto err;
+ /* allocations done, now commit: */
if (new_gc) {
rcu_assign_pointer(c->replicas_gc, new_gc);
kfree_rcu(old_gc, rcu);
}
- rcu_assign_pointer(c->replicas, new_r);
- kfree_rcu(old_r, rcu);
+ if (new_r) {
+ rcu_assign_pointer(c->replicas, new_r);
+ kfree_rcu(old_r, rcu);
+ bch2_write_super(c);
+ }
- bch2_write_super(c);
-out:
- ret = 0;
+ mutex_unlock(&c->sb_lock);
+ return 0;
err:
mutex_unlock(&c->sb_lock);
+ if (new_gc)
+ kfree(new_gc);
+ if (new_r)
+ kfree(new_r);
return ret;
}
@@ -1029,17 +1087,13 @@ int bch2_check_mark_super_devlist(struct bch_fs *c,
struct bch_devs_list *devs,
enum bch_data_type data_type)
{
- struct bch_replicas_cpu_entry search = { .data_type = data_type };
- unsigned i, max_dev = 0;
+ struct bch_replicas_cpu_entry search;
+ unsigned max_dev;
if (!devs->nr)
return 0;
- for (i = 0; i < devs->nr; i++) {
- max_dev = max_t(unsigned, max_dev, devs->devs[i]);
- replicas_set_dev(&search, devs->devs[i]);
- }
-
+ devlist_to_replicas(*devs, data_type, &search, &max_dev);
return __bch2_check_mark_super(c, search, max_dev);
}
@@ -1300,24 +1354,73 @@ err:
return err;
}
+int bch2_sb_replicas_to_text(struct bch_sb_field_replicas *r, char *buf, size_t size)
+{
+ char *out = buf, *end = out + size;
+ struct bch_replicas_entry *e;
+ bool first = true;
+ unsigned i;
+
+ if (!r) {
+ out += scnprintf(out, end - out, "(no replicas section found)");
+ return out - buf;
+ }
+
+ for_each_replicas_entry(r, e) {
+ if (!first)
+ out += scnprintf(out, end - out, " ");
+ first = false;
+
+ out += scnprintf(out, end - out, "%u: [", e->data_type);
+
+ for (i = 0; i < e->nr; i++)
+ out += scnprintf(out, end - out,
+ i ? " %u" : "%u", e->devs[i]);
+ out += scnprintf(out, end - out, "]");
+ }
+
+ return out - buf;
+}
+
/* Query replicas: */
+static bool __bch2_sb_has_replicas(struct bch_fs *c,
+ struct bch_replicas_cpu_entry search,
+ unsigned max_dev)
+{
+ bool ret;
+
+ rcu_read_lock();
+ ret = replicas_has_entry(rcu_dereference(c->replicas),
+ search, max_dev);
+ rcu_read_unlock();
+
+ return ret;
+}
+
bool bch2_sb_has_replicas(struct bch_fs *c, struct bkey_s_c_extent e,
enum bch_data_type data_type)
{
struct bch_replicas_cpu_entry search;
unsigned max_dev;
- bool ret;
if (!bkey_to_replicas(e, data_type, &search, &max_dev))
return true;
- rcu_read_lock();
- ret = replicas_has_entry(rcu_dereference(c->replicas),
- search, max_dev);
- rcu_read_unlock();
+ return __bch2_sb_has_replicas(c, search, max_dev);
+}
- return ret;
+bool bch2_sb_has_replicas_devlist(struct bch_fs *c, struct bch_devs_list *devs,
+ enum bch_data_type data_type)
+{
+ struct bch_replicas_cpu_entry search;
+ unsigned max_dev;
+
+ if (!devs->nr)
+ return true;
+
+ devlist_to_replicas(*devs, data_type, &search, &max_dev);
+ return __bch2_sb_has_replicas(c, search, max_dev);
}
struct replicas_status __bch2_replicas_status(struct bch_fs *c,