summaryrefslogtreecommitdiff
path: root/libbcachefs/btree_update.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/btree_update.c')
-rw-r--r--libbcachefs/btree_update.c181
1 files changed, 27 insertions, 154 deletions
diff --git a/libbcachefs/btree_update.c b/libbcachefs/btree_update.c
index ac852310..cbb7cf21 100644
--- a/libbcachefs/btree_update.c
+++ b/libbcachefs/btree_update.c
@@ -82,168 +82,38 @@ static noinline int extent_back_merge(struct btree_trans *trans,
return 0;
}
-static struct bkey_s_c peek_slot_including_whiteouts(struct btree_trans *trans, struct btree_iter *iter,
- enum btree_id btree, struct bpos pos)
-{
- struct bkey_s_c k;
- int ret;
-
- for_each_btree_key_norestart(trans, *iter, btree, 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, pos.snapshot, k.k->p.snapshot))
- return k;
- }
- bch2_trans_iter_exit(trans, iter);
-
- return ret ? bkey_s_c_err(ret) : bkey_s_c_null;
-}
-
/*
* 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, struct bpos pos)
-{
- pos.snapshot = bch2_snapshot_parent(trans->c, pos.snapshot);
- if (!pos.snapshot)
- return 0;
-
- struct btree_iter iter;
- struct bkey_s_c k = peek_slot_including_whiteouts(trans, &iter, btree, pos);
- int ret = bkey_err(k) ?: k.k && !bkey_whiteout(k.k);
- bch2_trans_iter_exit(trans, &iter);
-
- return ret;
-}
-
-/*
- * We're overwriting a key at @pos in snapshot @snapshot, so we need to insert a
- * whiteout: that might be in @snapshot, or if there are overwites in sibling
- * snapshots, find the common ancestor where @pos is overwritten in every
- * descendent and insert the whiteout there - which might be at @pos.
- */
-static int delete_interior_snapshot_key(struct btree_trans *trans,
- enum btree_id btree,
- struct bpos whiteout, bool deleting,
- struct bpos overwrite, bool old_is_whiteout)
+static int need_whiteout_for_snapshot(struct btree_trans *trans,
+ enum btree_id btree_id, struct bpos pos)
{
- struct bch_fs *c = trans->c;
- struct bpos orig_whiteout = whiteout, sib = whiteout;
struct btree_iter iter;
struct bkey_s_c k;
+ u32 snapshot = pos.snapshot;
int ret;
- sib.snapshot = bch2_snapshot_sibling(c, sib.snapshot);
+ if (!bch2_snapshot_parent(trans->c, pos.snapshot))
+ return 0;
- for_each_btree_key_norestart(trans, iter, btree, sib,
- BTREE_ITER_ALL_SNAPSHOTS|BTREE_ITER_INTENT, k, ret) {
- BUG_ON(bpos_gt(k.k->p, overwrite));
+ pos.snapshot++;
- if (bpos_lt(k.k->p, sib)) /* unrelated branch - skip */
- continue;
- if (bpos_gt(k.k->p, sib)) /* did not find @sib */
+ 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;
- /* @overwrite is also written in @sib, now check parent */
- whiteout.snapshot = bch2_snapshot_parent(c, whiteout.snapshot);
- if (bpos_eq(whiteout, overwrite))
+ if (bch2_snapshot_is_ancestor(trans->c, snapshot,
+ k.k->p.snapshot)) {
+ ret = !bkey_whiteout(k.k);
break;
-
- sib = whiteout;
- sib.snapshot = bch2_snapshot_sibling(c, sib.snapshot);
- }
-
- if (ret)
- goto err;
-
- if (!deleting && bpos_eq(whiteout, orig_whiteout))
- goto out;
-
- if (!bpos_eq(iter.pos, whiteout)) {
- bch2_trans_iter_exit(trans, &iter);
- bch2_trans_iter_init(trans, &iter, btree, whiteout, BTREE_ITER_INTENT);
- k = bch2_btree_iter_peek_slot(&iter);
- ret = bkey_err(k);
- if (ret)
- goto err;
- }
-
- iter.flags &= ~BTREE_ITER_ALL_SNAPSHOTS;
- iter.flags |= BTREE_ITER_FILTER_SNAPSHOTS;
-
- struct bkey_i *delete = bch2_trans_kmalloc(trans, sizeof(*delete));
- ret = PTR_ERR_OR_ZERO(delete);
- if (ret)
- goto err;
-
- bkey_init(&delete->k);
- delete->k.p = whiteout;
-
- ret = !bpos_eq(whiteout, overwrite)
- ? !old_is_whiteout
- : need_whiteout_for_snapshot(trans, btree, whiteout);
- if (ret < 0)
- goto err;
- if (ret)
- delete->k.type = KEY_TYPE_whiteout;
-
- ret = bch2_trans_update(trans, &iter, delete,
- BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE|
- BTREE_UPDATE_SNAPSHOT_WHITEOUT_CHECKS_DONE);
-out:
-err:
- bch2_trans_iter_exit(trans, &iter);
- return ret;
-}
-
-/*
- * We're overwriting a key in a snapshot that has ancestors: if we're
- * overwriting a key in a different snapshot, we need to check if it is now
- * fully overritten and can be deleted, and if we're deleting a key in the
- * current snapshot we need to check if we need to leave a whiteout.
- */
-static noinline int
-overwrite_interior_snapshot_key(struct btree_trans *trans,
- struct btree_iter *iter,
- struct bkey_i *k)
-{
- struct bkey_s_c old = bch2_btree_iter_peek_slot(iter);
-
- int ret = bkey_err(old);
- if (ret)
- return ret;
-
- if (!bkey_deleted(old.k)) {
- if (btree_type_snapshots_unreffed(iter->btree_id) &&
- old.k->p.snapshot != k->k.p.snapshot) {
- /*
- * We're overwriting a key in a different snapshot:
- * check if it's also been overwritten in siblings
- */
- ret = delete_interior_snapshot_key(trans, iter->btree_id,
- k->k.p, bkey_deleted(&k->k),
- old.k->p, bkey_whiteout(old.k));
- if (ret)
- return ret;
- if (bkey_deleted(&k->k))
- return 1;
- } else if (bkey_deleted(&k->k)) {
- /*
- * We're deleting a key in the current snapshot:
- * check if we need to leave a whiteout
- */
- ret = need_whiteout_for_snapshot(trans, iter->btree_id, k->k.p);
- if (unlikely(ret < 0))
- return ret;
- if (ret)
- k->k.type = KEY_TYPE_whiteout;
}
}
+ bch2_trans_iter_exit(trans, &iter);
- return 0;
+ return ret;
}
int __bch2_insert_snapshot_whiteouts(struct btree_trans *trans,
@@ -633,29 +503,32 @@ static noinline int bch2_trans_update_get_key_cache(struct btree_trans *trans,
int __must_check bch2_trans_update(struct btree_trans *trans, struct btree_iter *iter,
struct bkey_i *k, enum btree_update_flags flags)
{
+ btree_path_idx_t path_idx = iter->update_path ?: iter->path;
+ int ret;
+
if (iter->flags & BTREE_ITER_IS_EXTENTS)
return bch2_trans_update_extent(trans, iter, k, flags);
- if (!(flags & (BTREE_UPDATE_SNAPSHOT_WHITEOUT_CHECKS_DONE|
- BTREE_UPDATE_KEY_CACHE_RECLAIM)) &&
- (iter->flags & BTREE_ITER_FILTER_SNAPSHOTS) &&
- bch2_snapshot_parent(trans->c, k->k.p.snapshot)) {
- int ret = overwrite_interior_snapshot_key(trans, iter, k);
+ if (bkey_deleted(&k->k) &&
+ !(flags & BTREE_UPDATE_KEY_CACHE_RECLAIM) &&
+ (iter->flags & BTREE_ITER_FILTER_SNAPSHOTS)) {
+ ret = need_whiteout_for_snapshot(trans, iter->btree_id, k->k.p);
+ if (unlikely(ret < 0))
+ return ret;
+
if (ret)
- return ret < 0 ? ret : 0;
+ k->k.type = KEY_TYPE_whiteout;
}
/*
* Ensure that updates to cached btrees go to the key cache:
*/
- btree_path_idx_t path_idx = iter->update_path ?: iter->path;
struct btree_path *path = trans->paths + path_idx;
-
if (!(flags & BTREE_UPDATE_KEY_CACHE_RECLAIM) &&
!path->cached &&
!path->level &&
btree_id_cached(trans->c, path->btree_id)) {
- int ret = bch2_trans_update_get_key_cache(trans, iter, path);
+ ret = bch2_trans_update_get_key_cache(trans, iter, path);
if (ret)
return ret;