Commit a397b8df authored by Kent Overstreet's avatar Kent Overstreet

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent a0076086
...@@ -1151,7 +1151,62 @@ struct extent_end { ...@@ -1151,7 +1151,62 @@ struct extent_end {
struct snapshots_seen seen; 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, static int overlapping_extents_found(struct btree_trans *trans,
enum btree_id btree, enum btree_id btree,
...@@ -1229,8 +1284,9 @@ static int overlapping_extents_found(struct btree_trans *trans, ...@@ -1229,8 +1284,9 @@ static int overlapping_extents_found(struct btree_trans *trans,
static int check_overlapping_extents(struct btree_trans *trans, static int check_overlapping_extents(struct btree_trans *trans,
struct snapshots_seen *seen, struct snapshots_seen *seen,
extent_ends *extent_ends, struct extent_ends *extent_ends,
struct bkey_s_c k, struct bkey_s_c k,
u32 equiv,
struct btree_iter *iter) struct btree_iter *iter)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
...@@ -1238,10 +1294,15 @@ static int check_overlapping_extents(struct btree_trans *trans, ...@@ -1238,10 +1294,15 @@ static int check_overlapping_extents(struct btree_trans *trans,
bool fixed = false; bool fixed = false;
int ret = 0; int ret = 0;
darray_for_each(*extent_ends, i) { /* transaction restart, running again */
/* duplicate, due to transaction restart: */ if (bpos_eq(extent_ends->last_pos, k.k->p))
if (i->offset == k.k->p.offset && return 0;
i->snapshot == k.k->p.snapshot)
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; continue;
if (!ref_visible2(c, if (!ref_visible2(c,
...@@ -1249,7 +1310,6 @@ static int check_overlapping_extents(struct btree_trans *trans, ...@@ -1249,7 +1310,6 @@ static int check_overlapping_extents(struct btree_trans *trans,
i->snapshot, &i->seen)) i->snapshot, &i->seen))
continue; continue;
if (i->offset > bkey_start_offset(k.k)) {
ret = overlapping_extents_found(trans, iter->btree_id, ret = overlapping_extents_found(trans, iter->btree_id,
SPOS(iter->pos.inode, SPOS(iter->pos.inode,
i->offset, i->offset,
...@@ -1258,56 +1318,21 @@ static int check_overlapping_extents(struct btree_trans *trans, ...@@ -1258,56 +1318,21 @@ static int check_overlapping_extents(struct btree_trans *trans,
if (ret) if (ret)
goto err; 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;
}
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) ret = extent_ends_at(c, extent_ends, seen, k);
snapshots_seen_exit(&i->seen); 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, static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
struct bkey_s_c k, struct bkey_s_c k,
struct inode_walker *inode, struct inode_walker *inode,
struct snapshots_seen *s, struct snapshots_seen *s,
extent_ends *extent_ends) struct extent_ends *extent_ends)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct inode_walker_entry *i; struct inode_walker_entry *i;
...@@ -1327,8 +1352,6 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, ...@@ -1327,8 +1352,6 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
ret = check_i_sectors(trans, inode); ret = check_i_sectors(trans, inode);
if (ret) if (ret)
goto err; goto err;
extent_ends_reset(extent_ends);
} }
i = walk_inode(trans, inode, equiv, k.k->type == KEY_TYPE_whiteout); 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, ...@@ -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))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
goto delete; 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) if (ret < 0)
goto err; goto err;
if (ret) if (ret)
inode->recalculate_sums = true; inode->recalculate_sums = true;
ret = 0;
ret = extent_ends_at(extent_ends, s, k);
if (ret)
goto err;
} }
/* /*
...@@ -1434,11 +1455,12 @@ int bch2_check_extents(struct bch_fs *c) ...@@ -1434,11 +1455,12 @@ int bch2_check_extents(struct bch_fs *c)
struct btree_trans trans; struct btree_trans trans;
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
extent_ends extent_ends = { 0 }; struct extent_ends extent_ends;
struct disk_reservation res = { 0 }; struct disk_reservation res = { 0 };
int ret = 0; int ret = 0;
snapshots_seen_init(&s); 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, 0);
ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_extents, ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_extents,
...@@ -1452,8 +1474,7 @@ int bch2_check_extents(struct bch_fs *c) ...@@ -1452,8 +1474,7 @@ int bch2_check_extents(struct bch_fs *c)
check_i_sectors(&trans, &w); check_i_sectors(&trans, &w);
bch2_disk_reservation_put(c, &res); bch2_disk_reservation_put(c, &res);
extent_ends_reset(&extent_ends); extent_ends_exit(&extent_ends);
darray_exit(&extent_ends);
inode_walker_exit(&w); inode_walker_exit(&w);
bch2_trans_exit(&trans); bch2_trans_exit(&trans);
snapshots_seen_exit(&s); snapshots_seen_exit(&s);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment