#include "io.h"
#include "keylist.h"
#include "recovery.h"
+#include "replicas.h"
#include "super-io.h"
#include "util.h"
}
/* returns blocknr in stripe that we matched: */
-static int bkey_matches_stripe(struct bch_stripe *s,
- struct bkey_s_c k)
+static const struct bch_extent_ptr *bkey_matches_stripe(struct bch_stripe *s,
+ struct bkey_s_c k, unsigned *block)
{
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
const struct bch_extent_ptr *ptr;
bkey_for_each_ptr(ptrs, ptr)
for (i = 0; i < nr_data; i++)
if (__bch2_ptr_matches_stripe(&s->ptrs[i], ptr,
- le16_to_cpu(s->sectors)))
- return i;
+ le16_to_cpu(s->sectors))) {
+ *block = i;
+ return ptr;
+ }
- return -1;
+ return NULL;
}
static bool extent_has_stripe_ptr(struct bkey_s_c k, u64 idx)
struct bch_csum got = ec_block_checksum(buf, i, offset);
if (bch2_crc_cmp(want, got)) {
- char buf2[200];
+ struct printbuf buf2 = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf2), c, bkey_i_to_s_c(&buf->key.k_i));
+ bch2_bkey_val_to_text(&buf2, c, bkey_i_to_s_c(&buf->key.k_i));
bch_err_ratelimited(c,
"stripe checksum error for %ps at %u:%u: csum type %u, expected %llx got %llx\n%s",
(void *) _RET_IP_, i, j, v->csum_type,
- want.lo, got.lo, buf2);
+ want.lo, got.lo, buf2.buf);
+ printbuf_exit(&buf2);
clear_bit(i, buf->valid);
break;
}
free_heap(&n);
}
- if (!genradix_ptr_alloc(&c->stripes[0], idx, gfp))
+ if (!genradix_ptr_alloc(&c->stripes, idx, gfp))
return -ENOMEM;
if (c->gc_pos.phase != GC_PHASE_NOT_RUNNING &&
- !genradix_ptr_alloc(&c->stripes[1], idx, gfp))
+ !genradix_ptr_alloc(&c->gc_stripes, idx, gfp))
return -ENOMEM;
return 0;
{
struct bch_fs *c = container_of(h, struct bch_fs, ec_stripes_heap);
- genradix_ptr(&c->stripes[0], h->data[i].idx)->heap_idx = i;
+ genradix_ptr(&c->stripes, h->data[i].idx)->heap_idx = i;
}
static void heap_verify_backpointer(struct bch_fs *c, size_t idx)
{
ec_stripes_heap *h = &c->ec_stripes_heap;
- struct stripe *m = genradix_ptr(&c->stripes[0], idx);
+ struct stripe *m = genradix_ptr(&c->stripes, idx);
BUG_ON(!m->alive);
BUG_ON(m->heap_idx >= h->used);
return bch2_btree_delete_range(c, BTREE_ID_stripes,
POS(0, idx),
POS(0, idx + 1),
- NULL);
+ 0, NULL);
}
static void ec_stripe_delete_work(struct work_struct *work)
break;
}
- bch2_stripes_heap_del(c, genradix_ptr(&c->stripes[0], idx), idx);
+ bch2_stripes_heap_del(c, genradix_ptr(&c->stripes, idx), idx);
spin_unlock(&c->ec_stripes_heap_lock);
if (ec_stripe_delete(c, idx))
/* stripe creation: */
-static int ec_stripe_bkey_insert(struct bch_fs *c,
+static int ec_stripe_bkey_insert(struct btree_trans *trans,
struct bkey_i_stripe *stripe,
struct disk_reservation *res)
{
- struct btree_trans trans;
+ struct bch_fs *c = trans->c;
struct btree_iter iter;
struct bkey_s_c k;
struct bpos min_pos = POS(0, 1);
struct bpos start_pos = bpos_max(min_pos, POS(0, c->ec_stripe_hint));
int ret;
- bch2_trans_init(&trans, c, 0, 0);
-retry:
- bch2_trans_begin(&trans);
-
- for_each_btree_key(&trans, iter, BTREE_ID_stripes, start_pos,
+ for_each_btree_key(trans, iter, BTREE_ID_stripes, start_pos,
BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0) {
if (start_pos.offset) {
found_slot:
start_pos = iter.pos;
- ret = ec_stripe_mem_alloc(&trans, &iter);
+ ret = ec_stripe_mem_alloc(trans, &iter);
if (ret)
goto err;
stripe->k.p = iter.pos;
- ret = bch2_trans_update(&trans, &iter, &stripe->k_i, 0) ?:
- bch2_trans_commit(&trans, res, NULL,
- BTREE_INSERT_NOFAIL);
-err:
- bch2_trans_iter_exit(&trans, &iter);
-
- if (ret == -EINTR)
- goto retry;
+ ret = bch2_trans_update(trans, &iter, &stripe->k_i, 0);
- c->ec_stripe_hint = ret ? start_pos.offset : start_pos.offset + 1;
- bch2_trans_exit(&trans);
+ c->ec_stripe_hint = start_pos.offset;
+err:
+ bch2_trans_iter_exit(trans, &iter);
return ret;
}
static int ec_stripe_bkey_update(struct btree_trans *trans,
- struct bkey_i_stripe *new)
+ struct bkey_i_stripe *new,
+ struct disk_reservation *res)
{
struct btree_iter iter;
struct bkey_s_c k;
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
bkey_start_pos(pos),
BTREE_ITER_INTENT);
-
- while ((k = bch2_btree_iter_peek(&iter)).k &&
+retry:
+ while (bch2_trans_begin(&trans),
+ (k = bch2_btree_iter_peek(&iter)).k &&
!(ret = bkey_err(k)) &&
bkey_cmp(bkey_start_pos(k.k), pos->p) < 0) {
+ const struct bch_extent_ptr *ptr_c;
struct bch_extent_ptr *ptr, *ec_ptr = NULL;
if (extent_has_stripe_ptr(k, s->key.k.p.offset)) {
continue;
}
- block = bkey_matches_stripe(&s->key.v, k);
- if (block < 0) {
+ ptr_c = bkey_matches_stripe(&s->key.v, k, &block);
+ /*
+ * It doesn't generally make sense to erasure code cached ptrs:
+ * XXX: should we be incrementing a counter?
+ */
+ if (!ptr_c || ptr_c->cached) {
bch2_btree_iter_advance(&iter);
continue;
}
BTREE_INSERT_NOFAIL);
if (!ret)
bch2_btree_iter_set_pos(&iter, next_pos);
- if (ret == -EINTR)
- ret = 0;
if (ret)
break;
}
+ if (ret == -EINTR)
+ goto retry;
bch2_trans_iter_exit(&trans, &iter);
bch2_trans_exit(&trans);
goto err_put_writes;
}
- ret = s->have_existing_stripe
- ? bch2_trans_do(c, &s->res, NULL, BTREE_INSERT_NOFAIL,
- ec_stripe_bkey_update(&trans, &s->new_stripe.key))
- : ec_stripe_bkey_insert(c, &s->new_stripe.key, &s->res);
+ ret = bch2_trans_do(c, &s->res, NULL, BTREE_INSERT_NOFAIL,
+ s->have_existing_stripe
+ ? ec_stripe_bkey_update(&trans, &s->new_stripe.key, &s->res)
+ : ec_stripe_bkey_insert(&trans, &s->new_stripe.key, &s->res));
if (ret) {
bch_err(c, "error creating stripe: error creating stripe key");
goto err_put_writes;
}
spin_lock(&c->ec_stripes_heap_lock);
- m = genradix_ptr(&c->stripes[0], s->new_stripe.key.k.p.offset);
+ m = genradix_ptr(&c->stripes, s->new_stripe.key.k.p.offset);
BUG_ON(m->on_heap);
bch2_stripes_heap_insert(c, m, s->new_stripe.key.k.p.offset);
if (!ob)
return NULL;
- ca = bch_dev_bkey_exists(c, ob->ptr.dev);
+ ca = bch_dev_bkey_exists(c, ob->dev);
offset = ca->mi.bucket_size - ob->sectors_free;
return ob->ec->new_stripe.data[ob->ec_idx] + (offset << 9);
}
-void bch2_ec_add_backpointer(struct bch_fs *c, struct write_point *wp,
- struct bpos pos, unsigned sectors)
+void bch2_ob_add_backpointer(struct bch_fs *c, struct open_bucket *ob,
+ struct bkey *k)
{
- struct open_bucket *ob = ec_open_bucket(c, &wp->ptrs);
- struct ec_stripe_new *ec;
+ struct ec_stripe_new *ec = ob->ec;
- if (!ob)
+ if (!ec)
return;
- ec = ob->ec;
mutex_lock(&ec->lock);
if (bch2_keylist_realloc(&ec->keys, ec->inline_keys,
}
bkey_init(&ec->keys.top->k);
- ec->keys.top->k.p = pos;
- bch2_key_resize(&ec->keys.top->k, sectors);
+ ec->keys.top->k.p = k->p;
+ ec->keys.top->k.size = k->size;
bch2_keylist_push(&ec->keys);
mutex_unlock(&ec->lock);
s->v.algorithm = 0;
s->v.nr_blocks = nr_data + nr_parity;
s->v.nr_redundant = nr_parity;
- s->v.csum_granularity_bits = ilog2(c->sb.encoded_extent_max);
- s->v.csum_type = BCH_CSUM_CRC32C;
+ s->v.csum_granularity_bits = ilog2(c->opts.encoded_extent_max >> 9);
+ s->v.csum_type = BCH_CSUM_crc32c;
s->v.pad = 0;
while ((u64s = stripe_val_u64s(&s->v)) > BKEY_VAL_U64s_MAX) {
return h;
}
-static enum bucket_alloc_ret
-new_stripe_alloc_buckets(struct bch_fs *c, struct ec_stripe_head *h,
- struct closure *cl)
+static int new_stripe_alloc_buckets(struct bch_fs *c, struct ec_stripe_head *h,
+ struct closure *cl)
{
struct bch_devs_mask devs = h->devs;
struct open_bucket *ob;
struct open_buckets buckets;
unsigned i, j, nr_have_parity = 0, nr_have_data = 0;
bool have_cache = true;
- enum bucket_alloc_ret ret = ALLOC_SUCCESS;
+ int ret = 0;
for (i = 0; i < h->s->new_stripe.key.v.nr_blocks; i++) {
if (test_bit(i, h->s->blocks_gotten)) {
BUG_ON(j >= h->s->nr_data + h->s->nr_parity);
h->s->blocks[j] = buckets.v[i];
- h->s->new_stripe.key.v.ptrs[j] = ob->ptr;
+ h->s->new_stripe.key.v.ptrs[j] = bch2_ob_ptr(c, ob);
__set_bit(j, h->s->blocks_gotten);
}
BUG_ON(j >= h->s->nr_data);
h->s->blocks[j] = buckets.v[i];
- h->s->new_stripe.key.v.ptrs[j] = ob->ptr;
+ h->s->new_stripe.key.v.ptrs[j] = bch2_ob_ptr(c, ob);
__set_bit(j, h->s->blocks_gotten);
}
continue;
stripe_idx = h->data[heap_idx].idx;
- m = genradix_ptr(&c->stripes[0], stripe_idx);
+ m = genradix_ptr(&c->stripes, stripe_idx);
if (m->algorithm == head->algo &&
m->nr_redundant == head->redundancy &&
err:
bch2_ec_stripe_head_put(c, h);
- return ERR_PTR(-ret);
+ return ERR_PTR(ret);
}
void bch2_ec_stop_dev(struct bch_fs *c, struct bch_dev *ca)
continue;
ob = c->open_buckets + h->s->blocks[i];
- if (ob->ptr.dev == ca->dev_idx)
+ if (ob->dev == ca->dev_idx)
goto found;
}
goto unlock;
struct genradix_iter iter;
struct stripe *m;
- genradix_for_each(&c->stripes[0], iter, m)
+ genradix_for_each(&c->stripes, iter, m)
if (m->alive)
bch2_stripes_heap_insert(c, m, iter.pos);
}
-static int __bch2_stripe_write_key(struct btree_trans *trans,
- struct btree_iter *iter,
- struct stripe *m,
- size_t idx,
- struct bkey_i_stripe *new_key)
-{
- const struct bch_stripe *v;
- struct bkey_s_c k;
- unsigned i;
- int ret;
-
- bch2_btree_iter_set_pos(iter, POS(0, idx));
-
- k = bch2_btree_iter_peek_slot(iter);
- ret = bkey_err(k);
- if (ret)
- return ret;
-
- if (k.k->type != KEY_TYPE_stripe)
- return -EIO;
-
- v = bkey_s_c_to_stripe(k).v;
- for (i = 0; i < v->nr_blocks; i++)
- if (m->block_sectors[i] != stripe_blockcount_get(v, i))
- goto write;
- return 0;
-write:
- bkey_reassemble(&new_key->k_i, k);
-
- for (i = 0; i < new_key->v.nr_blocks; i++)
- stripe_blockcount_set(&new_key->v, i,
- m->block_sectors[i]);
-
- return bch2_trans_update(trans, iter, &new_key->k_i, 0);
-}
-
-int bch2_stripes_write(struct bch_fs *c, unsigned flags)
+int bch2_stripes_read(struct bch_fs *c)
{
struct btree_trans trans;
struct btree_iter iter;
- struct genradix_iter giter;
- struct bkey_i_stripe *new_key;
+ struct bkey_s_c k;
+ const struct bch_stripe *s;
struct stripe *m;
- int ret = 0;
-
- new_key = kmalloc(255 * sizeof(u64), GFP_KERNEL);
- BUG_ON(!new_key);
+ unsigned i;
+ int ret;
bch2_trans_init(&trans, c, 0, 0);
- bch2_trans_iter_init(&trans, &iter, BTREE_ID_stripes, POS_MIN,
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
-
- genradix_for_each(&c->stripes[0], giter, m) {
- if (!m->alive)
+ for_each_btree_key(&trans, iter, BTREE_ID_stripes, POS_MIN,
+ BTREE_ITER_PREFETCH, k, ret) {
+ if (k.k->type != KEY_TYPE_stripe)
continue;
- ret = __bch2_trans_do(&trans, NULL, NULL,
- BTREE_INSERT_NOFAIL|flags,
- __bch2_stripe_write_key(&trans, &iter, m,
- giter.pos, new_key));
-
+ ret = __ec_stripe_mem_alloc(c, k.k->p.offset, GFP_KERNEL);
if (ret)
break;
- }
- bch2_trans_iter_exit(&trans, &iter);
- bch2_trans_exit(&trans);
+ s = bkey_s_c_to_stripe(k).v;
- kfree(new_key);
+ m = genradix_ptr(&c->stripes, k.k->p.offset);
+ m->alive = true;
+ m->sectors = le16_to_cpu(s->sectors);
+ m->algorithm = s->algorithm;
+ m->nr_blocks = s->nr_blocks;
+ m->nr_redundant = s->nr_redundant;
+ m->blocks_nonempty = 0;
- return ret;
-}
-
-static int bch2_stripes_read_fn(struct bch_fs *c, struct bkey_s_c k)
-{
- int ret = 0;
+ for (i = 0; i < s->nr_blocks; i++)
+ m->blocks_nonempty += !!stripe_blockcount_get(s, i);
- if (k.k->type == KEY_TYPE_stripe)
- ret = __ec_stripe_mem_alloc(c, k.k->p.offset, GFP_KERNEL) ?:
- bch2_mark_key(c, k,
- BTREE_TRIGGER_INSERT|
- BTREE_TRIGGER_NOATOMIC);
+ spin_lock(&c->ec_stripes_heap_lock);
+ bch2_stripes_heap_update(c, m, k.k->p.offset);
+ spin_unlock(&c->ec_stripes_heap_lock);
+ }
+ bch2_trans_iter_exit(&trans, &iter);
- return ret;
-}
+ bch2_trans_exit(&trans);
-int bch2_stripes_read(struct bch_fs *c)
-{
- int ret = bch2_btree_and_journal_walk(c, BTREE_ID_stripes,
- bch2_stripes_read_fn);
if (ret)
bch_err(c, "error reading stripes: %i", ret);
return ret;
}
-int bch2_ec_mem_alloc(struct bch_fs *c, bool gc)
-{
- struct btree_trans trans;
- struct btree_iter iter;
- struct bkey_s_c k;
- size_t i, idx = 0;
- int ret = 0;
-
- bch2_trans_init(&trans, c, 0, 0);
- bch2_trans_iter_init(&trans, &iter, BTREE_ID_stripes, POS(0, U64_MAX), 0);
-
- k = bch2_btree_iter_prev(&iter);
- ret = bkey_err(k);
- if (!ret && k.k)
- idx = k.k->p.offset + 1;
-
- bch2_trans_iter_exit(&trans, &iter);
- bch2_trans_exit(&trans);
- if (ret)
- return ret;
-
- if (!idx)
- return 0;
-
- if (!gc &&
- !init_heap(&c->ec_stripes_heap, roundup_pow_of_two(idx),
- GFP_KERNEL))
- return -ENOMEM;
-#if 0
- ret = genradix_prealloc(&c->stripes[gc], idx, GFP_KERNEL);
-#else
- for (i = 0; i < idx; i++)
- if (!genradix_ptr_alloc(&c->stripes[gc], i, GFP_KERNEL))
- return -ENOMEM;
-#endif
- return 0;
-}
-
void bch2_stripes_heap_to_text(struct printbuf *out, struct bch_fs *c)
{
ec_stripes_heap *h = &c->ec_stripes_heap;
spin_lock(&c->ec_stripes_heap_lock);
for (i = 0; i < min_t(size_t, h->used, 20); i++) {
- m = genradix_ptr(&c->stripes[0], h->data[i].idx);
+ m = genradix_ptr(&c->stripes, h->data[i].idx);
pr_buf(out, "%zu %u/%u+%u\n", h->data[i].idx,
h->data[i].blocks_nonempty,
BUG_ON(!list_empty(&c->ec_stripe_new_list));
free_heap(&c->ec_stripes_heap);
- genradix_free(&c->stripes[0]);
+ genradix_free(&c->stripes);
bioset_exit(&c->ec_bioset);
}