mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-06 08:47:44 -04:00
bcachefs: iter->update_path
With BTREE_ITER_FILTER_SNAPSHOTS, we have to distinguish between the path where the key was found, and the path for inserting into the current snapshot. This adds a new field to struct btree_iter for saving a path for the current snapshot, and plumbs it through bch2_trans_update(). Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
committed by
Kent Overstreet
parent
a1e82d35f8
commit
1f2d919250
@@ -704,6 +704,8 @@ static void bch2_btree_iter_verify(struct btree_iter *iter)
|
||||
(iter->flags & BTREE_ITER_ALL_SNAPSHOTS) &&
|
||||
!btree_type_has_snapshots(iter->btree_id));
|
||||
|
||||
if (iter->update_path)
|
||||
bch2_btree_path_verify(trans, iter->update_path);
|
||||
bch2_btree_path_verify(trans, iter->path);
|
||||
}
|
||||
|
||||
@@ -2311,13 +2313,7 @@ static struct bkey_s_c __bch2_btree_iter_peek(struct btree_iter *iter, struct bp
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
iter->path = btree_path_set_pos(trans, iter->path, k.k->p,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
BUG_ON(!iter->path->nodes_locked);
|
||||
out:
|
||||
iter->path->should_be_locked = true;
|
||||
|
||||
bch2_btree_iter_verify(iter);
|
||||
|
||||
return k;
|
||||
@@ -2334,6 +2330,12 @@ struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
|
||||
struct bkey_s_c k;
|
||||
int ret;
|
||||
|
||||
if (iter->update_path) {
|
||||
bch2_path_put(trans, iter->update_path,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
iter->update_path = NULL;
|
||||
}
|
||||
|
||||
bch2_btree_iter_verify_entry_exit(iter);
|
||||
|
||||
while (1) {
|
||||
@@ -2341,6 +2343,41 @@ struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
|
||||
if (!k.k || bkey_err(k))
|
||||
goto out;
|
||||
|
||||
if (iter->update_path &&
|
||||
bkey_cmp(iter->update_path->pos, k.k->p)) {
|
||||
bch2_path_put(trans, iter->update_path,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
iter->update_path = NULL;
|
||||
}
|
||||
|
||||
if ((iter->flags & BTREE_ITER_FILTER_SNAPSHOTS) &&
|
||||
(iter->flags & BTREE_ITER_INTENT) &&
|
||||
!(iter->flags & BTREE_ITER_IS_EXTENTS) &&
|
||||
!iter->update_path) {
|
||||
struct bpos pos = k.k->p;
|
||||
|
||||
if (pos.snapshot < iter->snapshot) {
|
||||
search_key = bpos_successor(k.k->p);
|
||||
continue;
|
||||
}
|
||||
|
||||
pos.snapshot = iter->snapshot;
|
||||
|
||||
/*
|
||||
* advance, same as on exit for iter->path, but only up
|
||||
* to snapshot
|
||||
*/
|
||||
__btree_path_get(iter->path, iter->flags & BTREE_ITER_INTENT);
|
||||
iter->update_path = iter->path;
|
||||
|
||||
iter->update_path = btree_path_set_pos(trans,
|
||||
iter->update_path, pos,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
|
||||
BUG_ON(!(iter->update_path->nodes_locked & 1));
|
||||
iter->update_path->should_be_locked = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can never have a key in a leaf node at POS_MAX, so
|
||||
* we don't have to check these successor() calls:
|
||||
@@ -2370,7 +2407,17 @@ struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
|
||||
iter->pos = k.k->p;
|
||||
else if (bkey_cmp(bkey_start_pos(k.k), iter->pos) > 0)
|
||||
iter->pos = bkey_start_pos(k.k);
|
||||
|
||||
iter->path = btree_path_set_pos(trans, iter->path, k.k->p,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
BUG_ON(!iter->path->nodes_locked);
|
||||
out:
|
||||
if (iter->update_path) {
|
||||
BUG_ON(!(iter->update_path->nodes_locked & 1));
|
||||
iter->update_path->should_be_locked = true;
|
||||
}
|
||||
iter->path->should_be_locked = true;
|
||||
|
||||
if (!(iter->flags & BTREE_ITER_ALL_SNAPSHOTS))
|
||||
iter->pos.snapshot = iter->snapshot;
|
||||
|
||||
@@ -2774,7 +2821,11 @@ void bch2_trans_iter_exit(struct btree_trans *trans, struct btree_iter *iter)
|
||||
if (iter->path)
|
||||
bch2_path_put(trans, iter->path,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
if (iter->update_path)
|
||||
bch2_path_put(trans, iter->update_path,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
iter->path = NULL;
|
||||
iter->update_path = NULL;
|
||||
}
|
||||
|
||||
static void __bch2_trans_iter_init(struct btree_trans *trans,
|
||||
@@ -2803,6 +2854,7 @@ static void __bch2_trans_iter_init(struct btree_trans *trans,
|
||||
|
||||
iter->trans = trans;
|
||||
iter->path = NULL;
|
||||
iter->update_path = NULL;
|
||||
iter->btree_id = btree_id;
|
||||
iter->min_depth = depth;
|
||||
iter->flags = flags;
|
||||
@@ -2848,6 +2900,8 @@ void bch2_trans_copy_iter(struct btree_iter *dst, struct btree_iter *src)
|
||||
*dst = *src;
|
||||
if (src->path)
|
||||
__btree_path_get(src->path, src->flags & BTREE_ITER_INTENT);
|
||||
if (src->update_path)
|
||||
__btree_path_get(src->update_path, src->flags & BTREE_ITER_INTENT);
|
||||
}
|
||||
|
||||
void *bch2_trans_kmalloc(struct btree_trans *trans, size_t size)
|
||||
|
||||
@@ -258,6 +258,11 @@ static inline void __bch2_btree_iter_set_pos(struct btree_iter *iter, struct bpo
|
||||
|
||||
static inline void bch2_btree_iter_set_pos(struct btree_iter *iter, struct bpos new_pos)
|
||||
{
|
||||
if (unlikely(iter->update_path))
|
||||
bch2_path_put(iter->trans, iter->update_path,
|
||||
iter->flags & BTREE_ITER_INTENT);
|
||||
iter->update_path = NULL;
|
||||
|
||||
if (!(iter->flags & BTREE_ITER_ALL_SNAPSHOTS))
|
||||
new_pos.snapshot = iter->snapshot;
|
||||
|
||||
|
||||
@@ -276,6 +276,7 @@ static inline struct btree_path_level *path_l(struct btree_path *path)
|
||||
struct btree_iter {
|
||||
struct btree_trans *trans;
|
||||
struct btree_path *path;
|
||||
struct btree_path *update_path;
|
||||
|
||||
enum btree_id btree_id:4;
|
||||
unsigned min_depth:4;
|
||||
|
||||
@@ -73,8 +73,14 @@ int bch2_btree_node_update_key(struct btree_trans *, struct btree_iter *,
|
||||
int bch2_btree_node_update_key_get_iter(struct btree_trans *,
|
||||
struct btree *, struct bkey_i *, bool);
|
||||
|
||||
int bch2_trans_update_extent(struct btree_trans *, struct btree_iter *,
|
||||
struct bkey_i *, enum btree_update_flags);
|
||||
|
||||
int __must_check bch2_trans_update_by_path(struct btree_trans *, struct btree_path *,
|
||||
struct bkey_i *, enum btree_update_flags);
|
||||
int __must_check bch2_trans_update(struct btree_trans *, struct btree_iter *,
|
||||
struct bkey_i *, enum btree_update_flags);
|
||||
|
||||
void bch2_trans_commit_hook(struct btree_trans *,
|
||||
struct btree_trans_commit_hook *);
|
||||
int __bch2_trans_commit(struct btree_trans *);
|
||||
|
||||
@@ -1181,10 +1181,10 @@ static noinline int extent_back_merge(struct btree_trans *trans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bch2_trans_update_extent(struct btree_trans *trans,
|
||||
struct btree_iter *orig_iter,
|
||||
struct bkey_i *insert,
|
||||
enum btree_update_flags flags)
|
||||
int bch2_trans_update_extent(struct btree_trans *trans,
|
||||
struct btree_iter *orig_iter,
|
||||
struct bkey_i *insert,
|
||||
enum btree_update_flags flags)
|
||||
{
|
||||
struct btree_iter iter, update_iter;
|
||||
struct bpos start = bkey_start_pos(&insert->k);
|
||||
@@ -1308,13 +1308,9 @@ static int bch2_trans_update_extent(struct btree_trans *trans,
|
||||
bkey_reassemble(update, k);
|
||||
bch2_cut_front(insert->k.p, update);
|
||||
|
||||
bch2_trans_copy_iter(&update_iter, &iter);
|
||||
update_iter.pos = update->k.p;
|
||||
ret = bch2_trans_update(trans, &update_iter, update,
|
||||
ret = bch2_trans_update_by_path(trans, iter.path, update,
|
||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE|
|
||||
flags);
|
||||
bch2_trans_iter_exit(trans, &update_iter);
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
goto out;
|
||||
@@ -1385,26 +1381,23 @@ static int need_whiteout_for_snapshot(struct btree_trans *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __must_check bch2_trans_update(struct btree_trans *trans, struct btree_iter *iter,
|
||||
int __must_check bch2_trans_update_by_path(struct btree_trans *trans, struct btree_path *path,
|
||||
struct bkey_i *k, enum btree_update_flags flags)
|
||||
{
|
||||
struct btree_insert_entry *i, n;
|
||||
|
||||
BUG_ON(!iter->path->should_be_locked);
|
||||
|
||||
if (iter->flags & BTREE_ITER_IS_EXTENTS)
|
||||
return bch2_trans_update_extent(trans, iter, k, flags);
|
||||
BUG_ON(!path->should_be_locked);
|
||||
|
||||
BUG_ON(trans->nr_updates >= BTREE_ITER_MAX);
|
||||
BUG_ON(bpos_cmp(k->k.p, iter->path->pos));
|
||||
BUG_ON(bpos_cmp(k->k.p, path->pos));
|
||||
|
||||
n = (struct btree_insert_entry) {
|
||||
.flags = flags,
|
||||
.bkey_type = __btree_node_type(iter->path->level, iter->btree_id),
|
||||
.btree_id = iter->btree_id,
|
||||
.level = iter->path->level,
|
||||
.cached = iter->flags & BTREE_ITER_CACHED,
|
||||
.path = iter->path,
|
||||
.bkey_type = __btree_node_type(path->level, path->btree_id),
|
||||
.btree_id = path->btree_id,
|
||||
.level = path->level,
|
||||
.cached = path->cached,
|
||||
.path = path,
|
||||
.k = k,
|
||||
.ip_allocated = _RET_IP_,
|
||||
};
|
||||
@@ -1415,16 +1408,6 @@ int __must_check bch2_trans_update(struct btree_trans *trans, struct btree_iter
|
||||
btree_insert_entry_cmp(i - 1, i) >= 0);
|
||||
#endif
|
||||
|
||||
if (bkey_deleted(&n.k->k) &&
|
||||
(iter->flags & BTREE_ITER_FILTER_SNAPSHOTS)) {
|
||||
int ret = need_whiteout_for_snapshot(trans, n.btree_id, n.k->k.p);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
if (ret)
|
||||
n.k->k.type = KEY_TYPE_whiteout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pending updates are kept sorted: first, find position of new update,
|
||||
* then delete/trim any updates the new update overwrites:
|
||||
@@ -1455,10 +1438,29 @@ int __must_check bch2_trans_update(struct btree_trans *trans, struct btree_iter
|
||||
i - trans->updates, n);
|
||||
|
||||
__btree_path_get(n.path, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __must_check bch2_trans_update(struct btree_trans *trans, struct btree_iter *iter,
|
||||
struct bkey_i *k, enum btree_update_flags flags)
|
||||
{
|
||||
if (iter->flags & BTREE_ITER_IS_EXTENTS)
|
||||
return bch2_trans_update_extent(trans, iter, k, flags);
|
||||
|
||||
if (bkey_deleted(&k->k) &&
|
||||
(iter->flags & BTREE_ITER_FILTER_SNAPSHOTS)) {
|
||||
int 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;
|
||||
}
|
||||
|
||||
return bch2_trans_update_by_path(trans, iter->update_path ?: iter->path,
|
||||
k, flags);
|
||||
}
|
||||
|
||||
void bch2_trans_commit_hook(struct btree_trans *trans,
|
||||
struct btree_trans_commit_hook *h)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user