diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-07-16 22:12:25 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-23 00:10:08 +0300 |
commit | a397b8df5e2f2981427f2609252f37066a0cf780 (patch) | |
tree | b926dcb48d4b81a383ed434e46e71099295eae70 | |
parent | a0076086da73297228665957c3b3bfac2492d67d (diff) | |
download | linux-a397b8df5e2f2981427f2609252f37066a0cf780.tar.xz |
bcachefs: Refactor overlapping extent checks
Make the overlapping extent check/repair code more self contained.
This is prep work for hopefully reducing key_visible_in_snapshot() usage
here as well, and also includes a nice performance optimization to not
check ref_visible2() unless the extents potentially overlap.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/fsck.c | 153 |
1 files changed, 87 insertions, 66 deletions
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index 784e55166df2..e40040001ac1 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -1151,7 +1151,62 @@ struct extent_end { struct snapshots_seen seen; }; -typedef DARRAY(struct extent_end) extent_ends; +struct extent_ends { + struct bpos last_pos; + DARRAY(struct extent_end) e; +}; + +static void extent_ends_reset(struct extent_ends *extent_ends) +{ + struct extent_end *i; + + darray_for_each(extent_ends->e, i) + snapshots_seen_exit(&i->seen); + + extent_ends->e.nr = 0; +} + +static void extent_ends_exit(struct extent_ends *extent_ends) +{ + extent_ends_reset(extent_ends); + darray_exit(&extent_ends->e); +} + +static void extent_ends_init(struct extent_ends *extent_ends) +{ + memset(extent_ends, 0, sizeof(*extent_ends)); +} + +static int extent_ends_at(struct bch_fs *c, + struct extent_ends *extent_ends, + struct snapshots_seen *seen, + struct bkey_s_c k) +{ + struct extent_end *i, n = (struct extent_end) { + .offset = k.k->p.offset, + .snapshot = k.k->p.snapshot, + .seen = *seen, + }; + + n.seen.ids.data = kmemdup(seen->ids.data, + sizeof(seen->ids.data[0]) * seen->ids.size, + GFP_KERNEL); + if (!n.seen.ids.data) + return -BCH_ERR_ENOMEM_fsck_extent_ends_at; + + darray_for_each(extent_ends->e, i) { + if (i->snapshot == k.k->p.snapshot) { + snapshots_seen_exit(&i->seen); + *i = n; + return 0; + } + + if (i->snapshot >= k.k->p.snapshot) + break; + } + + return darray_insert_item(&extent_ends->e, i - extent_ends->e.data, n); +} static int overlapping_extents_found(struct btree_trans *trans, enum btree_id btree, @@ -1229,8 +1284,9 @@ err: static int check_overlapping_extents(struct btree_trans *trans, struct snapshots_seen *seen, - extent_ends *extent_ends, + struct extent_ends *extent_ends, struct bkey_s_c k, + u32 equiv, struct btree_iter *iter) { struct bch_fs *c = trans->c; @@ -1238,10 +1294,15 @@ static int check_overlapping_extents(struct btree_trans *trans, bool fixed = false; int ret = 0; - darray_for_each(*extent_ends, i) { - /* duplicate, due to transaction restart: */ - if (i->offset == k.k->p.offset && - i->snapshot == k.k->p.snapshot) + /* transaction restart, running again */ + if (bpos_eq(extent_ends->last_pos, k.k->p)) + return 0; + + if (extent_ends->last_pos.inode != k.k->p.inode) + extent_ends_reset(extent_ends); + + darray_for_each(extent_ends->e, i) { + if (i->offset <= bkey_start_offset(k.k)) continue; if (!ref_visible2(c, @@ -1249,65 +1310,29 @@ static int check_overlapping_extents(struct btree_trans *trans, i->snapshot, &i->seen)) continue; - if (i->offset > bkey_start_offset(k.k)) { - ret = overlapping_extents_found(trans, iter->btree_id, - SPOS(iter->pos.inode, - i->offset, - i->snapshot), - *k.k, &fixed); - if (ret) - goto err; - } - } -err: - return ret ?: fixed; -} - -static int extent_ends_at(extent_ends *extent_ends, - struct snapshots_seen *seen, - struct bkey_s_c k) -{ - struct extent_end *i, n = (struct extent_end) { - .snapshot = k.k->p.snapshot, - .offset = k.k->p.offset, - .seen = *seen, - }; - - n.seen.ids.data = kmemdup(seen->ids.data, - sizeof(seen->ids.data[0]) * seen->ids.size, - GFP_KERNEL); - if (!n.seen.ids.data) - return -BCH_ERR_ENOMEM_fsck_extent_ends_at; - - darray_for_each(*extent_ends, i) { - if (i->snapshot == k.k->p.snapshot) { - snapshots_seen_exit(&i->seen); - *i = n; - return 0; - } - - if (i->snapshot >= k.k->p.snapshot) - break; + ret = overlapping_extents_found(trans, iter->btree_id, + SPOS(iter->pos.inode, + i->offset, + i->snapshot), + *k.k, &fixed); + if (ret) + goto err; } - return darray_insert_item(extent_ends, i - extent_ends->data, n); -} - -static void extent_ends_reset(extent_ends *extent_ends) -{ - struct extent_end *i; - - darray_for_each(*extent_ends, i) - snapshots_seen_exit(&i->seen); + ret = extent_ends_at(c, extent_ends, seen, k); + if (ret) + goto err; - extent_ends->nr = 0; + extent_ends->last_pos = k.k->p; +err: + return ret ?: fixed; } static int check_extent(struct btree_trans *trans, struct btree_iter *iter, struct bkey_s_c k, struct inode_walker *inode, struct snapshots_seen *s, - extent_ends *extent_ends) + struct extent_ends *extent_ends) { struct bch_fs *c = trans->c; struct inode_walker_entry *i; @@ -1327,8 +1352,6 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, ret = check_i_sectors(trans, inode); if (ret) goto err; - - extent_ends_reset(extent_ends); } i = walk_inode(trans, inode, equiv, k.k->type == KEY_TYPE_whiteout); @@ -1356,16 +1379,14 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, bch2_bkey_val_to_text(&buf, c, k), buf.buf))) goto delete; - ret = check_overlapping_extents(trans, s, extent_ends, k, iter); + ret = check_overlapping_extents(trans, s, extent_ends, k, + equiv.snapshot, iter); if (ret < 0) goto err; if (ret) inode->recalculate_sums = true; - - ret = extent_ends_at(extent_ends, s, k); - if (ret) - goto err; + ret = 0; } /* @@ -1434,11 +1455,12 @@ int bch2_check_extents(struct bch_fs *c) struct btree_trans trans; struct btree_iter iter; struct bkey_s_c k; - extent_ends extent_ends = { 0 }; + struct extent_ends extent_ends; struct disk_reservation res = { 0 }; int ret = 0; snapshots_seen_init(&s); + extent_ends_init(&extent_ends); bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0); ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_extents, @@ -1452,8 +1474,7 @@ int bch2_check_extents(struct bch_fs *c) check_i_sectors(&trans, &w); bch2_disk_reservation_put(c, &res); - extent_ends_reset(&extent_ends); - darray_exit(&extent_ends); + extent_ends_exit(&extent_ends); inode_walker_exit(&w); bch2_trans_exit(&trans); snapshots_seen_exit(&s); |