diff options
Diffstat (limited to 'libbcachefs/fsck.c')
-rw-r--r-- | libbcachefs/fsck.c | 98 |
1 files changed, 61 insertions, 37 deletions
diff --git a/libbcachefs/fsck.c b/libbcachefs/fsck.c index 8c186acc..0852dbe9 100644 --- a/libbcachefs/fsck.c +++ b/libbcachefs/fsck.c @@ -1123,73 +1123,100 @@ static int extent_ends_at(struct bch_fs *c, static int overlapping_extents_found(struct btree_trans *trans, enum btree_id btree, struct bpos pos1, struct bkey pos2, - bool *fixed) + bool *fixed, + struct extent_end *extent_end) { struct bch_fs *c = trans->c; struct printbuf buf = PRINTBUF; - struct btree_iter iter; - struct bkey_s_c k; - u32 snapshot = min(pos1.snapshot, pos2.p.snapshot); + struct btree_iter iter1, iter2 = { NULL }; + struct bkey_s_c k1, k2; int ret; BUG_ON(bkey_le(pos1, bkey_start_pos(&pos2))); - bch2_trans_iter_init(trans, &iter, btree, SPOS(pos1.inode, pos1.offset - 1, snapshot), 0); - k = bch2_btree_iter_peek_upto(&iter, POS(pos1.inode, U64_MAX)); - ret = bkey_err(k); + bch2_trans_iter_init(trans, &iter1, btree, pos1, + BTREE_ITER_ALL_SNAPSHOTS| + BTREE_ITER_NOT_EXTENTS); + k1 = bch2_btree_iter_peek_upto(&iter1, POS(pos1.inode, U64_MAX)); + ret = bkey_err(k1); if (ret) goto err; prt_str(&buf, "\n "); - bch2_bkey_val_to_text(&buf, c, k); + bch2_bkey_val_to_text(&buf, c, k1); - if (!bpos_eq(pos1, k.k->p)) { - bch_err(c, "%s: error finding first overlapping extent when repairing%s", + if (!bpos_eq(pos1, k1.k->p)) { + prt_str(&buf, "\n wanted\n "); + bch2_bpos_to_text(&buf, pos1); + prt_str(&buf, "\n "); + bch2_bkey_to_text(&buf, &pos2); + + bch_err(c, "%s: error finding first overlapping extent when repairing, got%s", __func__, buf.buf); ret = -BCH_ERR_internal_fsck_err; goto err; } + bch2_trans_copy_iter(&iter2, &iter1); + while (1) { - bch2_btree_iter_advance(&iter); + bch2_btree_iter_advance(&iter2); - k = bch2_btree_iter_peek_upto(&iter, POS(pos1.inode, U64_MAX)); - ret = bkey_err(k); + k2 = bch2_btree_iter_peek_upto(&iter2, POS(pos1.inode, U64_MAX)); + ret = bkey_err(k2); if (ret) goto err; - if (bkey_ge(k.k->p, pos2.p)) + if (bpos_ge(k2.k->p, pos2.p)) break; - } prt_str(&buf, "\n "); - bch2_bkey_val_to_text(&buf, c, k); + bch2_bkey_val_to_text(&buf, c, k2); - if (bkey_gt(k.k->p, pos2.p) || - pos2.size != k.k->size) { + if (bpos_gt(k2.k->p, pos2.p) || + pos2.size != k2.k->size) { bch_err(c, "%s: error finding seconding overlapping extent when repairing%s", __func__, buf.buf); ret = -BCH_ERR_internal_fsck_err; goto err; } + prt_printf(&buf, "\n overwriting %s extent", + pos1.snapshot >= pos2.p.snapshot ? "first" : "second"); + if (fsck_err(c, "overlapping extents%s", buf.buf)) { - struct bpos update_pos = pos1.snapshot < pos2.p.snapshot ? pos1 : pos2.p; - struct btree_iter update_iter; + struct btree_iter *old_iter = &iter1; + struct disk_reservation res = { 0 }; - struct bkey_i *update = bch2_bkey_get_mut(trans, &update_iter, - btree, update_pos, - BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE); - bch2_trans_iter_exit(trans, &update_iter); - if ((ret = PTR_ERR_OR_ZERO(update))) + if (pos1.snapshot < pos2.p.snapshot) { + old_iter = &iter2; + swap(k1, k2); + } + + trans->extra_journal_res += bch2_bkey_sectors_compressed(k2); + + ret = bch2_trans_update_extent_overwrite(trans, old_iter, + BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE, + k1, k2) ?: + bch2_trans_commit(trans, &res, NULL, + BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL); + bch2_disk_reservation_put(c, &res); + + if (ret) goto err; *fixed = true; + + if (pos1.snapshot == pos2.p.snapshot) + extent_end->offset = bkey_start_offset(&pos2); + else + ret = -BCH_ERR_transaction_restart_nested; } fsck_err: err: - bch2_trans_iter_exit(trans, &iter); + bch2_trans_iter_exit(trans, &iter2); + bch2_trans_iter_exit(trans, &iter1); printbuf_exit(&buf); return ret; } @@ -1199,11 +1226,11 @@ static int check_overlapping_extents(struct btree_trans *trans, struct extent_ends *extent_ends, struct bkey_s_c k, u32 equiv, - struct btree_iter *iter) + struct btree_iter *iter, + bool *fixed) { struct bch_fs *c = trans->c; struct extent_end *i; - bool fixed = false; int ret = 0; /* transaction restart, running again */ @@ -1226,7 +1253,7 @@ static int check_overlapping_extents(struct btree_trans *trans, SPOS(iter->pos.inode, i->offset, i->snapshot), - *k.k, &fixed); + *k.k, fixed, i); if (ret) goto err; } @@ -1237,7 +1264,7 @@ static int check_overlapping_extents(struct btree_trans *trans, extent_ends->last_pos = k.k->p; err: - return ret ?: fixed; + return ret; } static int check_extent(struct btree_trans *trans, struct btree_iter *iter, @@ -1292,13 +1319,10 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, goto delete; ret = check_overlapping_extents(trans, s, extent_ends, k, - equiv.snapshot, iter); - if (ret < 0) - goto err; - + equiv.snapshot, iter, + &inode->recalculate_sums); if (ret) - inode->recalculate_sums = true; - ret = 0; + goto err; } /* @@ -1373,7 +1397,7 @@ int bch2_check_extents(struct bch_fs *c) snapshots_seen_init(&s); extent_ends_init(&extent_ends); - bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0); + bch2_trans_init(&trans, c, BTREE_ITER_MAX, 4096); ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_extents, POS(BCACHEFS_ROOT_INO, 0), |