diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-02-16 23:36:41 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:53 -0400 |
commit | 2ffe3ad62dafac036c523204c6e2e2f39b23cb6f (patch) | |
tree | 34f776db8e3d8b45873802e77f97d2d060f83313 | |
parent | c58029ec807594856ae69dd7864eb7b3afb92f4a (diff) | |
download | lwn-2ffe3ad62dafac036c523204c6e2e2f39b23cb6f.tar.gz lwn-2ffe3ad62dafac036c523204c6e2e2f39b23cb6f.zip |
bcachefs: Snapshot whiteout fix
When fully overwriting an existing extent, we may need to generate a
whiteout - not just if the extent being overwritten was in an older
snapshot, but also if it was overwriting an extent in an older snapshot.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/btree_update_leaf.c | 75 |
1 files changed, 37 insertions, 38 deletions
diff --git a/fs/bcachefs/btree_update_leaf.c b/fs/bcachefs/btree_update_leaf.c index 0fc98b43a073..544b90b15260 100644 --- a/fs/bcachefs/btree_update_leaf.c +++ b/fs/bcachefs/btree_update_leaf.c @@ -1307,6 +1307,39 @@ static noinline int extent_back_merge(struct btree_trans *trans, return 0; } +/* + * When deleting, check if we need to emit a whiteout (because we're overwriting + * something in an ancestor snapshot) + */ +static int need_whiteout_for_snapshot(struct btree_trans *trans, + enum btree_id btree_id, struct bpos pos) +{ + struct btree_iter iter; + struct bkey_s_c k; + u32 snapshot = pos.snapshot; + int ret; + + if (!bch2_snapshot_parent(trans->c, pos.snapshot)) + return 0; + + pos.snapshot++; + + for_each_btree_key_norestart(trans, iter, btree_id, pos, + BTREE_ITER_ALL_SNAPSHOTS| + BTREE_ITER_NOPRESERVE, k, ret) { + if (!bkey_eq(k.k->p, pos)) + break; + + if (bch2_snapshot_is_ancestor(trans->c, snapshot, + k.k->p.snapshot)) { + ret = !bkey_whiteout(k.k); + break; + } + } + bch2_trans_iter_exit(trans, &iter); + + return ret; +} int bch2_trans_update_extent(struct btree_trans *trans, struct btree_iter *orig_iter, struct bkey_i *insert, @@ -1388,12 +1421,12 @@ int bch2_trans_update_extent(struct btree_trans *trans, bkey_init(&update->k); update->k.p = k.k->p; + update->k.p.snapshot = insert->k.p.snapshot; - if (insert->k.p.snapshot != k.k->p.snapshot) { - update->k.p.snapshot = insert->k.p.snapshot; + if (insert->k.p.snapshot != k.k->p.snapshot || + (btree_type_has_snapshots(btree_id) && + need_whiteout_for_snapshot(trans, btree_id, update->k.p))) update->k.type = KEY_TYPE_whiteout; - } - ret = bch2_btree_insert_nonextent(trans, btree_id, update, BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE|flags); @@ -1448,40 +1481,6 @@ err: return ret; } -/* - * When deleting, check if we need to emit a whiteout (because we're overwriting - * something in an ancestor snapshot) - */ -static int need_whiteout_for_snapshot(struct btree_trans *trans, - enum btree_id btree_id, struct bpos pos) -{ - struct btree_iter iter; - struct bkey_s_c k; - u32 snapshot = pos.snapshot; - int ret; - - if (!bch2_snapshot_parent(trans->c, pos.snapshot)) - return 0; - - pos.snapshot++; - - for_each_btree_key_norestart(trans, iter, btree_id, pos, - BTREE_ITER_ALL_SNAPSHOTS| - BTREE_ITER_NOPRESERVE, k, ret) { - if (!bkey_eq(k.k->p, pos)) - break; - - if (bch2_snapshot_is_ancestor(trans->c, snapshot, - k.k->p.snapshot)) { - ret = !bkey_whiteout(k.k); - break; - } - } - bch2_trans_iter_exit(trans, &iter); - - return ret; -} - static int __must_check bch2_trans_update_by_path_trace(struct btree_trans *trans, struct btree_path *path, struct bkey_i *k, enum btree_update_flags flags, |