mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-04 11:08:35 -05:00
bcachefs: delete_dead_snapshot_keys_v2()
Since extents, dirents and xattrs require an inode with the corresponding snapshot ID to exists, we can avoid a lot of scanning by only scanning those trees for keys to process if the correspending inode exists. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
@@ -1432,6 +1432,12 @@ static unsigned live_child(struct bch_fs *c, u32 id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool snapshot_id_dying(struct snapshot_delete *d, unsigned id)
|
||||
{
|
||||
return snapshot_list_has_id(&d->delete_leaves, id) ||
|
||||
interior_delete_has_id(&d->delete_interior, id) != 0;
|
||||
}
|
||||
|
||||
static int delete_dead_snapshots_process_key(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k)
|
||||
@@ -1500,6 +1506,129 @@ static bool skip_unrelated_snapshot_tree(struct btree_trans *trans, struct btree
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int delete_dead_snapshot_keys_v1(struct btree_trans *trans)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct snapshot_delete *d = &c->snapshot_delete;
|
||||
|
||||
for (d->pos.btree = 0; d->pos.btree < BTREE_ID_NR; d->pos.btree++) {
|
||||
struct disk_reservation res = { 0 };
|
||||
u64 prev_inum = 0;
|
||||
|
||||
d->pos.pos = POS_MIN;
|
||||
|
||||
if (!btree_type_has_snapshots(d->pos.btree))
|
||||
continue;
|
||||
|
||||
int ret = for_each_btree_key_commit(trans, iter,
|
||||
d->pos.btree, POS_MIN,
|
||||
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
|
||||
&res, NULL, BCH_TRANS_COMMIT_no_enospc, ({
|
||||
d->pos.pos = iter.pos;
|
||||
|
||||
if (skip_unrelated_snapshot_tree(trans, &iter, &prev_inum))
|
||||
continue;
|
||||
|
||||
delete_dead_snapshots_process_key(trans, &iter, k);
|
||||
}));
|
||||
|
||||
bch2_disk_reservation_put(c, &res);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delete_dead_snapshot_keys_range(struct btree_trans *trans, enum btree_id btree,
|
||||
struct bpos start, struct bpos end)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct snapshot_delete *d = &c->snapshot_delete;
|
||||
struct disk_reservation res = { 0 };
|
||||
|
||||
d->pos.btree = btree;
|
||||
d->pos.pos = POS_MIN;
|
||||
|
||||
int ret = for_each_btree_key_max_commit(trans, iter,
|
||||
btree, start, end,
|
||||
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
|
||||
&res, NULL, BCH_TRANS_COMMIT_no_enospc, ({
|
||||
d->pos.pos = iter.pos;
|
||||
delete_dead_snapshots_process_key(trans, &iter, k);
|
||||
}));
|
||||
|
||||
bch2_disk_reservation_put(c, &res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int delete_dead_snapshot_keys_v2(struct btree_trans *trans)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct snapshot_delete *d = &c->snapshot_delete;
|
||||
struct disk_reservation res = { 0 };
|
||||
u64 prev_inum = 0;
|
||||
int ret = 0;
|
||||
|
||||
struct btree_iter iter;
|
||||
bch2_trans_iter_init(trans, &iter, BTREE_ID_inodes, POS_MIN,
|
||||
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots);
|
||||
|
||||
while (1) {
|
||||
struct bkey_s_c k;
|
||||
ret = lockrestart_do(trans,
|
||||
bkey_err(k = bch2_btree_iter_peek(trans, &iter)));
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (!k.k)
|
||||
break;
|
||||
|
||||
d->pos.btree = iter.btree_id;
|
||||
d->pos.pos = iter.pos;
|
||||
|
||||
if (skip_unrelated_snapshot_tree(trans, &iter, &prev_inum))
|
||||
continue;
|
||||
|
||||
if (snapshot_id_dying(d, k.k->p.snapshot)) {
|
||||
struct bpos start = POS(k.k->p.offset, 0);
|
||||
struct bpos end = POS(k.k->p.offset, U64_MAX);
|
||||
|
||||
ret = delete_dead_snapshot_keys_range(trans, BTREE_ID_extents, start, end) ?:
|
||||
delete_dead_snapshot_keys_range(trans, BTREE_ID_dirents, start, end) ?:
|
||||
delete_dead_snapshot_keys_range(trans, BTREE_ID_xattrs, start, end);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
bch2_btree_iter_set_pos(trans, &iter, POS(0, k.k->p.offset + 1));
|
||||
} else {
|
||||
bch2_btree_iter_advance(trans, &iter);
|
||||
}
|
||||
}
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
prev_inum = 0;
|
||||
ret = for_each_btree_key_commit(trans, iter,
|
||||
BTREE_ID_inodes, POS_MIN,
|
||||
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
|
||||
&res, NULL, BCH_TRANS_COMMIT_no_enospc, ({
|
||||
d->pos.btree = iter.btree_id;
|
||||
d->pos.pos = iter.pos;
|
||||
|
||||
if (skip_unrelated_snapshot_tree(trans, &iter, &prev_inum))
|
||||
continue;
|
||||
|
||||
delete_dead_snapshots_process_key(trans, &iter, k);
|
||||
}));
|
||||
err:
|
||||
bch2_disk_reservation_put(c, &res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a given snapshot, if it doesn't have a subvolume that points to it, and
|
||||
* it doesn't have child snapshot nodes - it's now redundant and we can mark it
|
||||
@@ -1683,34 +1812,13 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (d->pos.btree = 0; d->pos.btree < BTREE_ID_NR; d->pos.btree++) {
|
||||
struct disk_reservation res = { 0 };
|
||||
u64 prev_inum = 0;
|
||||
|
||||
d->pos.pos = POS_MIN;
|
||||
|
||||
if (!btree_type_has_snapshots(d->pos.btree))
|
||||
continue;
|
||||
|
||||
ret = for_each_btree_key_commit(trans, iter,
|
||||
d->pos.btree, POS_MIN,
|
||||
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
|
||||
&res, NULL, BCH_TRANS_COMMIT_no_enospc, ({
|
||||
d->pos.pos = iter.pos;
|
||||
|
||||
if (skip_unrelated_snapshot_tree(trans, &iter, &prev_inum))
|
||||
continue;
|
||||
|
||||
delete_dead_snapshots_process_key(trans, &iter, k);
|
||||
}));
|
||||
|
||||
bch2_disk_reservation_put(c, &res);
|
||||
|
||||
if (!bch2_err_matches(ret, EROFS))
|
||||
bch_err_msg(c, ret, "deleting keys from dying snapshots");
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
ret = !bch2_request_incompat_feature(c, bcachefs_metadata_version_snapshot_deletion_v2)
|
||||
? delete_dead_snapshot_keys_v2(trans)
|
||||
: delete_dead_snapshot_keys_v1(trans);
|
||||
if (!bch2_err_matches(ret, EROFS))
|
||||
bch_err_msg(c, ret, "deleting keys from dying snapshots");
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
darray_for_each(d->delete_leaves, i) {
|
||||
ret = commit_do(trans, NULL, NULL, 0,
|
||||
|
||||
Reference in New Issue
Block a user