X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libbcachefs%2Fbtree_gc.c;h=65fda70d086efea7f2b554e37ab26368ef936dd3;hb=9fc4b5d675cd6dc0b2503abe95b1c761d8d05abe;hp=5b7f7cd3252a6db4a68089b275a07633645aea9b;hpb=99caca2c70f312c4a2504a7e7a9c92a91426d885;p=bcachefs-tools-debian diff --git a/libbcachefs/btree_gc.c b/libbcachefs/btree_gc.c index 5b7f7cd..65fda70 100644 --- a/libbcachefs/btree_gc.c +++ b/libbcachefs/btree_gc.c @@ -76,7 +76,7 @@ static int bch2_gc_check_topology(struct bch_fs *c, if (cur.k->k.type == KEY_TYPE_btree_ptr_v2) { struct bkey_i_btree_ptr_v2 *bp = bkey_i_to_btree_ptr_v2(cur.k); - if (bpos_cmp(expected_start, bp->v.min_key)) { + if (!bpos_eq(expected_start, bp->v.min_key)) { bch2_topology_error(c); if (bkey_deleted(&prev->k->k)) { @@ -106,7 +106,7 @@ static int bch2_gc_check_topology(struct bch_fs *c, } } - if (is_last && bpos_cmp(cur.k->k.p, node_end)) { + if (is_last && !bpos_eq(cur.k->k.p, node_end)) { bch2_topology_error(c); printbuf_reset(&buf1); @@ -199,7 +199,7 @@ static int set_node_min(struct bch_fs *c, struct btree *b, struct bpos new_min) struct bkey_i_btree_ptr_v2 *new; int ret; - new = kmalloc(BKEY_BTREE_PTR_U64s_MAX * sizeof(u64), GFP_KERNEL); + new = kmalloc_array(BKEY_BTREE_PTR_U64s_MAX, sizeof(u64), GFP_KERNEL); if (!new) return -ENOMEM; @@ -228,7 +228,7 @@ static int set_node_max(struct bch_fs *c, struct btree *b, struct bpos new_max) if (ret) return ret; - new = kmalloc(BKEY_BTREE_PTR_U64s_MAX * sizeof(u64), GFP_KERNEL); + new = kmalloc_array(BKEY_BTREE_PTR_U64s_MAX, sizeof(u64), GFP_KERNEL); if (!new) return -ENOMEM; @@ -274,12 +274,12 @@ static int btree_repair_node_boundaries(struct bch_fs *c, struct btree *b, bch2_bkey_val_to_text(&buf2, c, bkey_i_to_s_c(&cur->key)); if (prev && - bpos_cmp(expected_start, cur->data->min_key) > 0 && + bpos_gt(expected_start, cur->data->min_key) && BTREE_NODE_SEQ(cur->data) > BTREE_NODE_SEQ(prev->data)) { /* cur overwrites prev: */ - if (mustfix_fsck_err_on(bpos_cmp(prev->data->min_key, - cur->data->min_key) >= 0, c, + if (mustfix_fsck_err_on(bpos_ge(prev->data->min_key, + cur->data->min_key), c, "btree node overwritten by next node at btree %s level %u:\n" " node %s\n" " next %s", @@ -289,7 +289,7 @@ static int btree_repair_node_boundaries(struct bch_fs *c, struct btree *b, goto out; } - if (mustfix_fsck_err_on(bpos_cmp(prev->key.k.p, + if (mustfix_fsck_err_on(!bpos_eq(prev->key.k.p, bpos_predecessor(cur->data->min_key)), c, "btree node with incorrect max_key at btree %s level %u:\n" " node %s\n" @@ -301,8 +301,8 @@ static int btree_repair_node_boundaries(struct bch_fs *c, struct btree *b, } else { /* prev overwrites cur: */ - if (mustfix_fsck_err_on(bpos_cmp(expected_start, - cur->data->max_key) >= 0, c, + if (mustfix_fsck_err_on(bpos_ge(expected_start, + cur->data->max_key), c, "btree node overwritten by prev node at btree %s level %u:\n" " prev %s\n" " node %s", @@ -312,13 +312,13 @@ static int btree_repair_node_boundaries(struct bch_fs *c, struct btree *b, goto out; } - if (mustfix_fsck_err_on(bpos_cmp(expected_start, cur->data->min_key), c, + if (mustfix_fsck_err_on(!bpos_eq(expected_start, cur->data->min_key), c, "btree node with incorrect min_key at btree %s level %u:\n" " prev %s\n" " node %s", bch2_btree_ids[b->c.btree_id], b->c.level, buf1.buf, buf2.buf)) - ret = set_node_min(c, cur, expected_start); + ret = set_node_min(c, cur, expected_start); } out: fsck_err: @@ -336,7 +336,7 @@ static int btree_repair_node_end(struct bch_fs *c, struct btree *b, bch2_bkey_val_to_text(&buf1, c, bkey_i_to_s_c(&child->key)); bch2_bpos_to_text(&buf2, b->key.k.p); - if (mustfix_fsck_err_on(bpos_cmp(child->key.k.p, b->key.k.p), c, + if (mustfix_fsck_err_on(!bpos_eq(child->key.k.p, b->key.k.p), c, "btree node with incorrect max_key at btree %s level %u:\n" " %s\n" " expected %s", @@ -374,8 +374,8 @@ again: bch2_btree_and_journal_iter_init_node_iter(&iter, c, b); while ((k = bch2_btree_and_journal_iter_peek(&iter)).k) { - BUG_ON(bpos_cmp(k.k->p, b->data->min_key) < 0); - BUG_ON(bpos_cmp(k.k->p, b->data->max_key) > 0); + BUG_ON(bpos_lt(k.k->p, b->data->min_key)); + BUG_ON(bpos_gt(k.k->p, b->data->max_key)); bch2_btree_and_journal_iter_advance(&iter); bch2_bkey_buf_reassemble(&cur_k, c, k); @@ -633,8 +633,8 @@ static int bch2_check_fix_ptrs(struct btree_trans *trans, enum btree_id btree_id if (data_type != BCH_DATA_btree && p.ptr.gen != g->gen) continue; - if (fsck_err_on(g->data_type && - g->data_type != data_type, c, + if (fsck_err_on(bucket_data_type(g->data_type) && + bucket_data_type(g->data_type) != data_type, c, "bucket %u:%zu different types of data in same bucket: %s, %s\n" "while marking %s", p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), @@ -661,7 +661,7 @@ static int bch2_check_fix_ptrs(struct btree_trans *trans, enum btree_id btree_id bch2_bkey_val_to_text(&buf, c, *k), buf.buf))) do_update = true; - if (fsck_err_on(!bch2_ptr_matches_stripe_m(m, p), c, + if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c, "pointer does not match stripe %llu\n" "while marking %s", (u64) p.ec.idx, @@ -808,7 +808,7 @@ static int bch2_gc_mark_key(struct btree_trans *trans, enum btree_id btree_id, } ret = commit_do(trans, NULL, NULL, 0, - bch2_mark_key(trans, old, *k, flags)); + bch2_mark_key(trans, btree_id, level, old, *k, flags)); fsck_err: err: if (ret) @@ -887,7 +887,7 @@ static int bch2_gc_btree(struct btree_trans *trans, enum btree_id btree_id, if (!btree_node_fake(b)) { struct bkey_s_c k = bkey_i_to_s_c(&b->key); - ret = bch2_gc_mark_key(trans, b->c.btree_id, b->c.level, + ret = bch2_gc_mark_key(trans, b->c.btree_id, b->c.level + 1, true, &k, initial); } gc_pos_set(c, gc_pos_btree_root(b->c.btree_id)); @@ -912,8 +912,8 @@ static int bch2_gc_btree_init_recurse(struct btree_trans *trans, struct btree *b bkey_init(&prev.k->k); while ((k = bch2_btree_and_journal_iter_peek(&iter)).k) { - BUG_ON(bpos_cmp(k.k->p, b->data->min_key) < 0); - BUG_ON(bpos_cmp(k.k->p, b->data->max_key) > 0); + BUG_ON(bpos_lt(k.k->p, b->data->min_key)); + BUG_ON(bpos_gt(k.k->p, b->data->max_key)); ret = bch2_gc_mark_key(trans, b->c.btree_id, b->c.level, false, &k, true); @@ -1018,7 +1018,7 @@ static int bch2_gc_btree_init(struct btree_trans *trans, six_lock_read(&b->c.lock, NULL, NULL); printbuf_reset(&buf); bch2_bpos_to_text(&buf, b->data->min_key); - if (mustfix_fsck_err_on(bpos_cmp(b->data->min_key, POS_MIN), c, + if (mustfix_fsck_err_on(!bpos_eq(b->data->min_key, POS_MIN), c, "btree root with incorrect min_key: %s", buf.buf)) { bch_err(c, "repair unimplemented"); ret = -BCH_ERR_fsck_repair_unimplemented; @@ -1027,7 +1027,7 @@ static int bch2_gc_btree_init(struct btree_trans *trans, printbuf_reset(&buf); bch2_bpos_to_text(&buf, b->data->max_key); - if (mustfix_fsck_err_on(bpos_cmp(b->data->max_key, SPOS_MAX), c, + if (mustfix_fsck_err_on(!bpos_eq(b->data->max_key, SPOS_MAX), c, "btree root with incorrect max_key: %s", buf.buf)) { bch_err(c, "repair unimplemented"); ret = -BCH_ERR_fsck_repair_unimplemented; @@ -1040,7 +1040,7 @@ static int bch2_gc_btree_init(struct btree_trans *trans, if (!ret) { struct bkey_s_c k = bkey_i_to_s_c(&b->key); - ret = bch2_gc_mark_key(trans, b->c.btree_id, b->c.level, true, + ret = bch2_gc_mark_key(trans, b->c.btree_id, b->c.level + 1, true, &k, true); } fsck_err: @@ -1285,8 +1285,7 @@ fsck_err: return ret; } -static int bch2_gc_start(struct bch_fs *c, - bool metadata_only) +static int bch2_gc_start(struct bch_fs *c) { struct bch_dev *ca = NULL; unsigned i; @@ -1301,7 +1300,6 @@ static int bch2_gc_start(struct bch_fs *c, } for_each_member_device(ca, c, i) { - BUG_ON(ca->buckets_gc); BUG_ON(ca->usage_gc); ca->usage_gc = alloc_percpu(struct bch_dev_usage); @@ -1318,6 +1316,22 @@ static int bch2_gc_start(struct bch_fs *c, return 0; } +static int bch2_gc_reset(struct bch_fs *c) +{ + struct bch_dev *ca; + unsigned i; + + for_each_member_device(ca, c, i) { + free_percpu(ca->usage_gc); + ca->usage_gc = NULL; + } + + free_percpu(c->usage_gc); + c->usage_gc = NULL; + + return bch2_gc_start(c); +} + /* returns true if not equal */ static inline bool bch2_alloc_v4_cmp(struct bch_alloc_v4 l, struct bch_alloc_v4 r) @@ -1340,15 +1354,16 @@ static int bch2_alloc_write_key(struct btree_trans *trans, struct bch_dev *ca = bch_dev_bkey_exists(c, iter->pos.inode); struct bucket gc, *b; struct bkey_i_alloc_v4 *a; - struct bch_alloc_v4 old, new; + struct bch_alloc_v4 old_convert, new; + const struct bch_alloc_v4 *old; enum bch_data_type type; int ret; - if (bkey_cmp(iter->pos, POS(ca->dev_idx, ca->mi.nbuckets)) >= 0) + if (bkey_ge(iter->pos, POS(ca->dev_idx, ca->mi.nbuckets))) return 1; - bch2_alloc_to_v4(k, &old); - new = old; + old = bch2_alloc_to_v4(k, &old_convert); + new = *old; percpu_down_read(&c->mark_lock); b = gc_bucket(ca, iter->pos.offset); @@ -1360,7 +1375,7 @@ static int bch2_alloc_write_key(struct btree_trans *trans, type = __alloc_data_type(b->dirty_sectors, b->cached_sectors, b->stripe, - old, + *old, b->data_type); if (b->data_type != type) { struct bch_dev_usage *u; @@ -1382,9 +1397,19 @@ static int bch2_alloc_write_key(struct btree_trans *trans, gc.data_type != BCH_DATA_btree) return 0; - if (gen_after(old.gen, gc.gen)) + if (gen_after(old->gen, gc.gen)) return 0; + if (c->opts.reconstruct_alloc || + fsck_err_on(new.data_type != gc.data_type, c, + "bucket %llu:%llu gen %u has wrong data_type" + ": got %s, should be %s", + iter->pos.inode, iter->pos.offset, + gc.gen, + bch2_data_types[new.data_type], + bch2_data_types[gc.data_type])) + new.data_type = gc.data_type; + #define copy_bucket_field(_f) \ if (c->opts.reconstruct_alloc || \ fsck_err_on(new._f != gc._f, c, \ @@ -1397,14 +1422,13 @@ static int bch2_alloc_write_key(struct btree_trans *trans, new._f = gc._f; \ copy_bucket_field(gen); - copy_bucket_field(data_type); copy_bucket_field(dirty_sectors); copy_bucket_field(cached_sectors); copy_bucket_field(stripe_redundancy); copy_bucket_field(stripe); #undef copy_bucket_field - if (!bch2_alloc_v4_cmp(old, new)) + if (!bch2_alloc_v4_cmp(*old, new)) return 0; a = bch2_alloc_to_v4_mut(trans, k); @@ -1462,7 +1486,8 @@ static int bch2_gc_alloc_start(struct bch_fs *c, bool metadata_only) struct btree_iter iter; struct bkey_s_c k; struct bucket *g; - struct bch_alloc_v4 a; + struct bch_alloc_v4 a_convert; + const struct bch_alloc_v4 *a; unsigned i; int ret; @@ -1488,20 +1513,20 @@ static int bch2_gc_alloc_start(struct bch_fs *c, bool metadata_only) ca = bch_dev_bkey_exists(c, k.k->p.inode); g = gc_bucket(ca, k.k->p.offset); - bch2_alloc_to_v4(k, &a); + a = bch2_alloc_to_v4(k, &a_convert); g->gen_valid = 1; - g->gen = a.gen; + g->gen = a->gen; if (metadata_only && - (a.data_type == BCH_DATA_user || - a.data_type == BCH_DATA_cached || - a.data_type == BCH_DATA_parity)) { - g->data_type = a.data_type; - g->dirty_sectors = a.dirty_sectors; - g->cached_sectors = a.cached_sectors; - g->stripe = a.stripe; - g->stripe_redundancy = a.stripe_redundancy; + (a->data_type == BCH_DATA_user || + a->data_type == BCH_DATA_cached || + a->data_type == BCH_DATA_parity)) { + g->data_type = a->data_type; + g->dirty_sectors = a->dirty_sectors; + g->cached_sectors = a->cached_sectors; + g->stripe = a->stripe; + g->stripe_redundancy = a->stripe_redundancy; } } bch2_trans_iter_exit(&trans, &iter); @@ -1567,15 +1592,12 @@ static int bch2_gc_write_reflink_key(struct btree_trans *trans, " should be %u", (bch2_bkey_val_to_text(&buf, c, k), buf.buf), r->refcount)) { - struct bkey_i *new; + struct bkey_i *new = bch2_bkey_make_mut(trans, k); - new = bch2_trans_kmalloc(trans, bkey_bytes(k.k)); ret = PTR_ERR_OR_ZERO(new); if (ret) return ret; - bkey_reassemble(new, k); - if (!r->refcount) new->k.type = KEY_TYPE_deleted; else @@ -1668,6 +1690,7 @@ static int bch2_gc_write_stripes_key(struct btree_trans *trans, struct printbuf buf = PRINTBUF; const struct bch_stripe *s; struct gc_stripe *m; + bool bad = false; unsigned i; int ret = 0; @@ -1677,18 +1700,21 @@ static int bch2_gc_write_stripes_key(struct btree_trans *trans, s = bkey_s_c_to_stripe(k).v; m = genradix_ptr(&c->gc_stripes, k.k->p.offset); - for (i = 0; i < s->nr_blocks; i++) - if (stripe_blockcount_get(s, i) != (m ? m->block_sectors[i] : 0)) - goto inconsistent; - return 0; -inconsistent: - if (fsck_err_on(true, c, - "stripe has wrong block sector count %u:\n" - " %s\n" - " should be %u", i, - (printbuf_reset(&buf), - bch2_bkey_val_to_text(&buf, c, k), buf.buf), - m ? m->block_sectors[i] : 0)) { + for (i = 0; i < s->nr_blocks; i++) { + u32 old = stripe_blockcount_get(s, i); + u32 new = (m ? m->block_sectors[i] : 0); + + if (old != new) { + prt_printf(&buf, "stripe block %u has wrong sector count: got %u, should be %u\n", + i, old, new); + bad = true; + } + } + + if (bad) + bch2_bkey_val_to_text(&buf, c, k); + + if (fsck_err_on(bad, c, "%s", buf.buf)) { struct bkey_i_stripe *new; new = bch2_trans_kmalloc(trans, bkey_bytes(k.k)); @@ -1764,7 +1790,7 @@ int bch2_gc(struct bch_fs *c, bool initial, bool metadata_only) bch2_btree_interior_updates_flush(c); - ret = bch2_gc_start(c, metadata_only) ?: + ret = bch2_gc_start(c) ?: bch2_gc_alloc_start(c, metadata_only) ?: bch2_gc_reflink_start(c, metadata_only); if (ret) @@ -1825,6 +1851,9 @@ again: bch2_gc_stripes_reset(c, metadata_only); bch2_gc_alloc_reset(c, metadata_only); bch2_gc_reflink_reset(c, metadata_only); + ret = bch2_gc_reset(c); + if (ret) + goto out; /* flush fsck errors, reset counters */ bch2_flush_fsck_errs(c); @@ -1889,13 +1918,11 @@ static int gc_btree_gens_key(struct btree_trans *trans, percpu_up_read(&c->mark_lock); return 0; update: - u = bch2_trans_kmalloc(trans, bkey_bytes(k.k)); + u = bch2_bkey_make_mut(trans, k); ret = PTR_ERR_OR_ZERO(u); if (ret) return ret; - bkey_reassemble(u, k); - bch2_extent_normalize(c, bkey_i_to_s(u)); return bch2_trans_update(trans, iter, u, 0); } @@ -1904,13 +1931,12 @@ static int bch2_alloc_write_oldest_gen(struct btree_trans *trans, struct btree_i struct bkey_s_c k) { struct bch_dev *ca = bch_dev_bkey_exists(trans->c, iter->pos.inode); - struct bch_alloc_v4 a; + struct bch_alloc_v4 a_convert; + const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &a_convert); struct bkey_i_alloc_v4 *a_mut; int ret; - bch2_alloc_to_v4(k, &a); - - if (a.oldest_gen == ca->oldest_gen[iter->pos.offset]) + if (a->oldest_gen == ca->oldest_gen[iter->pos.offset]) return 0; a_mut = bch2_alloc_to_v4_mut(trans, k); @@ -1966,7 +1992,7 @@ int bch2_gc_gens(struct bch_fs *c) } for (i = 0; i < BTREE_ID_NR; i++) - if ((1 << i) & BTREE_ID_HAS_PTRS) { + if (btree_type_has_ptrs(i)) { struct btree_iter iter; struct bkey_s_c k; @@ -1979,10 +2005,10 @@ int bch2_gc_gens(struct bch_fs *c) NULL, NULL, BTREE_INSERT_NOFAIL, gc_btree_gens_key(&trans, &iter, k)); - if (ret) { + if (ret && !bch2_err_matches(ret, EROFS)) bch_err(c, "error recalculating oldest_gen: %s", bch2_err_str(ret)); + if (ret) goto err; - } } ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_alloc, @@ -1992,10 +2018,10 @@ int bch2_gc_gens(struct bch_fs *c) NULL, NULL, BTREE_INSERT_NOFAIL, bch2_alloc_write_oldest_gen(&trans, &iter, k)); - if (ret) { + if (ret && !bch2_err_matches(ret, EROFS)) bch_err(c, "error writing oldest_gen: %s", bch2_err_str(ret)); + if (ret) goto err; - } c->gc_gens_btree = 0; c->gc_gens_pos = POS_MIN;