eytzinger0_sort(r->entries, r->nr, r->entry_size, memcmp, NULL);
}
+void bch2_replicas_entry_v0_to_text(struct printbuf *out,
+ struct bch_replicas_entry_v0 *e)
+{
+ unsigned i;
+
+ if (e->data_type < BCH_DATA_NR)
+ prt_printf(out, "%s", bch2_data_types[e->data_type]);
+ else
+ prt_printf(out, "(invalid data type %u)", e->data_type);
+
+ prt_printf(out, ": %u [", e->nr_devs);
+ for (i = 0; i < e->nr_devs; i++)
+ prt_printf(out, i ? " %u" : "%u", e->devs[i]);
+ prt_printf(out, "]");
+}
+
void bch2_replicas_entry_to_text(struct printbuf *out,
struct bch_replicas_entry *e)
{
unsigned i;
- pr_buf(out, "%s: %u/%u [",
- bch2_data_types[e->data_type],
- e->nr_required,
- e->nr_devs);
+ if (e->data_type < BCH_DATA_NR)
+ prt_printf(out, "%s", bch2_data_types[e->data_type]);
+ else
+ prt_printf(out, "(invalid data type %u)", e->data_type);
+ prt_printf(out, ": %u/%u [", e->nr_required, e->nr_devs);
for (i = 0; i < e->nr_devs; i++)
- pr_buf(out, i ? " %u" : "%u", e->devs[i]);
- pr_buf(out, "]");
+ prt_printf(out, i ? " %u" : "%u", e->devs[i]);
+ prt_printf(out, "]");
}
void bch2_cpu_replicas_to_text(struct printbuf *out,
- struct bch_replicas_cpu *r)
+ struct bch_replicas_cpu *r)
{
struct bch_replicas_entry *e;
bool first = true;
for_each_cpu_replicas_entry(r, e) {
if (!first)
- pr_buf(out, " ");
+ prt_printf(out, " ");
first = false;
bch2_replicas_entry_to_text(out, e);
goto out;
}
-static int __bch2_mark_replicas(struct bch_fs *c,
- struct bch_replicas_entry *r,
- bool check)
-{
- return likely(bch2_replicas_marked(c, r)) ? 0
- : check ? -1
- : bch2_mark_replicas_slowpath(c, r);
-}
-
int bch2_mark_replicas(struct bch_fs *c, struct bch_replicas_entry *r)
{
- return __bch2_mark_replicas(c, r, false);
-}
-
-static int __bch2_mark_bkey_replicas(struct bch_fs *c, struct bkey_s_c k,
- bool check)
-{
- struct bch_replicas_padded search;
- struct bch_devs_list cached = bch2_bkey_cached_devs(k);
- unsigned i;
- int ret;
-
- memset(&search, 0, sizeof(search));
-
- for (i = 0; i < cached.nr; i++) {
- bch2_replicas_entry_cached(&search.e, cached.devs[i]);
-
- ret = __bch2_mark_replicas(c, &search.e, check);
- if (ret)
- return ret;
- }
-
- bch2_bkey_to_replicas(&search.e, k);
-
- ret = __bch2_mark_replicas(c, &search.e, check);
- if (ret)
- return ret;
-
- if (search.e.data_type == BCH_DATA_parity) {
- search.e.data_type = BCH_DATA_cached;
- ret = __bch2_mark_replicas(c, &search.e, check);
- if (ret)
- return ret;
-
- search.e.data_type = BCH_DATA_user;
- ret = __bch2_mark_replicas(c, &search.e, check);
- if (ret)
- return ret;
- }
-
- return 0;
+ return likely(bch2_replicas_marked(c, r))
+ ? 0 : bch2_mark_replicas_slowpath(c, r);
}
/* replicas delta list: */
-bool bch2_replicas_delta_list_marked(struct bch_fs *c,
- struct replicas_delta_list *r)
-{
- struct replicas_delta *d = r->d;
- struct replicas_delta *top = (void *) r->d + r->used;
-
- percpu_rwsem_assert_held(&c->mark_lock);
-
- for (d = r->d; d != top; d = replicas_delta_next(d))
- if (bch2_replicas_entry_idx(c, &d->r) < 0)
- return false;
- return true;
-}
-
int bch2_replicas_delta_list_mark(struct bch_fs *c,
struct replicas_delta_list *r)
{
return ret;
}
-/* bkey replicas: */
-
-bool bch2_bkey_replicas_marked(struct bch_fs *c,
- struct bkey_s_c k)
-{
- return __bch2_mark_bkey_replicas(c, k, true) == 0;
-}
-
-int bch2_mark_bkey_replicas(struct bch_fs *c, struct bkey_s_c k)
-{
- return __bch2_mark_bkey_replicas(c, k, false);
-}
-
/*
* Old replicas_gc mechanism: only used for journal replicas entries now, should
* die at some point:
return 0;
}
-static const char *check_dup_replicas_entries(struct bch_replicas_cpu *cpu_r)
+static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
+ struct bch_sb *sb,
+ struct printbuf *err)
{
- unsigned i;
+ struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
+ unsigned i, j;
sort_cmp_size(cpu_r->entries,
cpu_r->nr,
cpu_r->entry_size,
memcmp, NULL);
- for (i = 0; i + 1 < cpu_r->nr; i++) {
- struct bch_replicas_entry *l =
+ for (i = 0; i < cpu_r->nr; i++) {
+ struct bch_replicas_entry *e =
cpu_replicas_entry(cpu_r, i);
- struct bch_replicas_entry *r =
- cpu_replicas_entry(cpu_r, i + 1);
-
- BUG_ON(memcmp(l, r, cpu_r->entry_size) > 0);
- if (!memcmp(l, r, cpu_r->entry_size))
- return "duplicate replicas entry";
- }
+ if (e->data_type >= BCH_DATA_NR) {
+ prt_printf(err, "invalid data type in entry ");
+ bch2_replicas_entry_to_text(err, e);
+ return -EINVAL;
+ }
- return NULL;
-}
+ if (!e->nr_devs) {
+ prt_printf(err, "no devices in entry ");
+ bch2_replicas_entry_to_text(err, e);
+ return -EINVAL;
+ }
-static const char *bch2_sb_validate_replicas(struct bch_sb *sb, struct bch_sb_field *f)
-{
- struct bch_sb_field_replicas *sb_r = field_to_type(f, replicas);
- struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
- struct bch_replicas_cpu cpu_r = { .entries = NULL };
- struct bch_replicas_entry *e;
- const char *err;
- unsigned i;
+ if (e->nr_required > 1 &&
+ e->nr_required >= e->nr_devs) {
+ prt_printf(err, "bad nr_required in entry ");
+ bch2_replicas_entry_to_text(err, e);
+ return -EINVAL;
+ }
- for_each_replicas_entry(sb_r, e) {
- err = "invalid replicas entry: invalid data type";
- if (e->data_type >= BCH_DATA_NR)
- goto err;
+ for (j = 0; j < e->nr_devs; j++)
+ if (!bch2_dev_exists(sb, mi, e->devs[j])) {
+ prt_printf(err, "invalid device %u in entry ", e->devs[j]);
+ bch2_replicas_entry_to_text(err, e);
+ return -EINVAL;
+ }
- err = "invalid replicas entry: no devices";
- if (!e->nr_devs)
- goto err;
+ if (i + 1 < cpu_r->nr) {
+ struct bch_replicas_entry *n =
+ cpu_replicas_entry(cpu_r, i + 1);
- err = "invalid replicas entry: bad nr_required";
- if (e->nr_required > 1 &&
- e->nr_required >= e->nr_devs)
- goto err;
+ BUG_ON(memcmp(e, n, cpu_r->entry_size) > 0);
- err = "invalid replicas entry: invalid device";
- for (i = 0; i < e->nr_devs; i++)
- if (!bch2_dev_exists(sb, mi, e->devs[i]))
- goto err;
+ if (!memcmp(e, n, cpu_r->entry_size)) {
+ prt_printf(err, "duplicate replicas entry ");
+ bch2_replicas_entry_to_text(err, e);
+ return -EINVAL;
+ }
+ }
}
- err = "cannot allocate memory";
+ return 0;
+}
+
+static int bch2_sb_replicas_validate(struct bch_sb *sb, struct bch_sb_field *f,
+ struct printbuf *err)
+{
+ struct bch_sb_field_replicas *sb_r = field_to_type(f, replicas);
+ struct bch_replicas_cpu cpu_r;
+ int ret;
+
if (__bch2_sb_replicas_to_cpu_replicas(sb_r, &cpu_r))
- goto err;
+ return -ENOMEM;
- err = check_dup_replicas_entries(&cpu_r);
-err:
+ ret = bch2_cpu_replicas_validate(&cpu_r, sb, err);
kfree(cpu_r.entries);
- return err;
+ return ret;
}
static void bch2_sb_replicas_to_text(struct printbuf *out,
for_each_replicas_entry(r, e) {
if (!first)
- pr_buf(out, " ");
+ prt_printf(out, " ");
first = false;
bch2_replicas_entry_to_text(out, e);
}
+ prt_newline(out);
}
const struct bch_sb_field_ops bch_sb_field_ops_replicas = {
- .validate = bch2_sb_validate_replicas,
+ .validate = bch2_sb_replicas_validate,
.to_text = bch2_sb_replicas_to_text,
};
-static const char *bch2_sb_validate_replicas_v0(struct bch_sb *sb, struct bch_sb_field *f)
+static int bch2_sb_replicas_v0_validate(struct bch_sb *sb, struct bch_sb_field *f,
+ struct printbuf *err)
{
struct bch_sb_field_replicas_v0 *sb_r = field_to_type(f, replicas_v0);
- struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
- struct bch_replicas_cpu cpu_r = { .entries = NULL };
- struct bch_replicas_entry_v0 *e;
- const char *err;
- unsigned i;
+ struct bch_replicas_cpu cpu_r;
+ int ret;
- for_each_replicas_entry_v0(sb_r, e) {
- err = "invalid replicas entry: invalid data type";
- if (e->data_type >= BCH_DATA_NR)
- goto err;
+ if (__bch2_sb_replicas_v0_to_cpu_replicas(sb_r, &cpu_r))
+ return -ENOMEM;
- err = "invalid replicas entry: no devices";
- if (!e->nr_devs)
- goto err;
+ ret = bch2_cpu_replicas_validate(&cpu_r, sb, err);
+ kfree(cpu_r.entries);
+ return ret;
+}
- err = "invalid replicas entry: invalid device";
- for (i = 0; i < e->nr_devs; i++)
- if (!bch2_dev_exists(sb, mi, e->devs[i]))
- goto err;
- }
+static void bch2_sb_replicas_v0_to_text(struct printbuf *out,
+ struct bch_sb *sb,
+ struct bch_sb_field *f)
+{
+ struct bch_sb_field_replicas_v0 *sb_r = field_to_type(f, replicas_v0);
+ struct bch_replicas_entry_v0 *e;
+ bool first = true;
- err = "cannot allocate memory";
- if (__bch2_sb_replicas_v0_to_cpu_replicas(sb_r, &cpu_r))
- goto err;
+ for_each_replicas_entry(sb_r, e) {
+ if (!first)
+ prt_printf(out, " ");
+ first = false;
- err = check_dup_replicas_entries(&cpu_r);
-err:
- kfree(cpu_r.entries);
- return err;
+ bch2_replicas_entry_v0_to_text(out, e);
+ }
+ prt_newline(out);
}
const struct bch_sb_field_ops bch_sb_field_ops_replicas_v0 = {
- .validate = bch2_sb_validate_replicas_v0,
+ .validate = bch2_sb_replicas_v0_validate,
+ .to_text = bch2_sb_replicas_v0_to_text,
};
/* Query replicas: */
if (dflags & ~flags) {
if (print) {
- char buf[100];
+ struct printbuf buf = PRINTBUF;
- bch2_replicas_entry_to_text(&PBUF(buf), e);
+ bch2_replicas_entry_to_text(&buf, e);
bch_err(c, "insufficient devices online (%u) for replicas entry %s",
- nr_online, buf);
+ nr_online, buf.buf);
+ printbuf_exit(&buf);
}
ret = false;
break;
return ret;
}
-unsigned bch2_dev_has_data(struct bch_fs *c, struct bch_dev *ca)
+unsigned bch2_sb_dev_has_data(struct bch_sb *sb, unsigned dev)
{
- struct bch_replicas_entry *e;
- unsigned i, ret = 0;
+ struct bch_sb_field_replicas *replicas;
+ struct bch_sb_field_replicas_v0 *replicas_v0;
+ unsigned i, data_has = 0;
+
+ replicas = bch2_sb_get_replicas(sb);
+ replicas_v0 = bch2_sb_get_replicas_v0(sb);
+
+ if (replicas) {
+ struct bch_replicas_entry *r;
+
+ for_each_replicas_entry(replicas, r)
+ for (i = 0; i < r->nr_devs; i++)
+ if (r->devs[i] == dev)
+ data_has |= 1 << r->data_type;
+ } else if (replicas_v0) {
+ struct bch_replicas_entry_v0 *r;
+
+ for_each_replicas_entry_v0(replicas_v0, r)
+ for (i = 0; i < r->nr_devs; i++)
+ if (r->devs[i] == dev)
+ data_has |= 1 << r->data_type;
+ }
- percpu_down_read(&c->mark_lock);
- for_each_cpu_replicas_entry(&c->replicas, e)
- for (i = 0; i < e->nr_devs; i++)
- if (e->devs[i] == ca->dev_idx)
- ret |= 1 << e->data_type;
+ return data_has;
+}
- percpu_up_read(&c->mark_lock);
+unsigned bch2_dev_has_data(struct bch_fs *c, struct bch_dev *ca)
+{
+ unsigned ret;
+
+ mutex_lock(&c->sb_lock);
+ ret = bch2_sb_dev_has_data(c->disk_sb.sb, ca->dev_idx);
+ mutex_unlock(&c->sb_lock);
return ret;
}