diff options
Diffstat (limited to 'libbcachefs/btree_update.c')
-rw-r--r-- | libbcachefs/btree_update.c | 181 |
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; |