summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-01-08 21:22:31 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:22 -0400
commit1f2d9192502917a190ef9bbf7541960d129d30fe (patch)
tree1c17ec70a196a5ed0d9d08cd45874da2aa4d5208
parenta1e82d35f89793f6347945ab48d799ce1802df87 (diff)
downloadlinux-stable-1f2d9192502917a190ef9bbf7541960d129d30fe.tar.gz
linux-stable-1f2d9192502917a190ef9bbf7541960d129d30fe.tar.bz2
linux-stable-1f2d9192502917a190ef9bbf7541960d129d30fe.zip
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>
-rw-r--r--fs/bcachefs/btree_iter.c66
-rw-r--r--fs/bcachefs/btree_iter.h5
-rw-r--r--fs/bcachefs/btree_types.h1
-rw-r--r--fs/bcachefs/btree_update.h6
-rw-r--r--fs/bcachefs/btree_update_leaf.c64
5 files changed, 105 insertions, 37 deletions
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index 29ca9410c86c..ae1628918c57 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -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)
diff --git a/fs/bcachefs/btree_iter.h b/fs/bcachefs/btree_iter.h
index 9bb1ef404bc9..c4fdfb382dcd 100644
--- a/fs/bcachefs/btree_iter.h
+++ b/fs/bcachefs/btree_iter.h
@@ -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;
diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h
index 794726c4efd7..9828bdd924af 100644
--- a/fs/bcachefs/btree_types.h
+++ b/fs/bcachefs/btree_types.h
@@ -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;
diff --git a/fs/bcachefs/btree_update.h b/fs/bcachefs/btree_update.h
index 7d16c35112f3..c8e1f43f71e3 100644
--- a/fs/bcachefs/btree_update.h
+++ b/fs/bcachefs/btree_update.h
@@ -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 *);
diff --git a/fs/bcachefs/btree_update_leaf.c b/fs/bcachefs/btree_update_leaf.c
index e0e99018e5a1..41403942133a 100644
--- a/fs/bcachefs/btree_update_leaf.c
+++ b/fs/bcachefs/btree_update_leaf.c
@@ -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)
{