bcachefs: iter->update_path
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 9 Jan 2022 02:22:31 +0000 (21:22 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:22 +0000 (17:09 -0400)
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>
fs/bcachefs/btree_iter.c
fs/bcachefs/btree_iter.h
fs/bcachefs/btree_types.h
fs/bcachefs/btree_update.h
fs/bcachefs/btree_update_leaf.c

index 29ca9410c86c11848920c099e0ee6ed3dd3382f9..ae1628918c5759dded589b2976a8666ca52c1a34 100644 (file)
@@ -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)
index 9bb1ef404bc92879e67858c2bd07158a79a57650..c4fdfb382dcd94468198faef6c92996a9cfc862f 100644 (file)
@@ -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;
 
index 794726c4efd7249eb9b2bef5911e3842009891a7..9828bdd924aff783de5fb56ed9a511fb3b7e62a6 100644 (file)
@@ -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;
index 7d16c35112f39b799a92436a659268f6ea601014..c8e1f43f71e3f36aeebb327fc01b8828ef7db53b 100644 (file)
@@ -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 *);
index e0e99018e5a1fc7454b4bbab3bc1c26224e89c30..41403942133a941dc6a336dbebb7243427bc39d8 100644 (file)
@@ -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)
 {