]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/btree_iter.c
Update bcachefs sources to 043cfba30c fixup! bcachefs: Improve transaction restart...
[bcachefs-tools-debian] / libbcachefs / btree_iter.c
index b5484d7702a49277de8f607153cc3f9633481f74..8c7fc74f1a77d37cc71dad4c50ff42ea4df7c7b4 100644 (file)
@@ -27,6 +27,21 @@ static inline void btree_path_list_add(struct btree_trans *, struct btree_path *
 
 static struct btree_path *btree_path_alloc(struct btree_trans *, struct btree_path *);
 
+/*
+ * Unlocks before scheduling
+ * Note: does not revalidate iterator
+ */
+static inline int bch2_trans_cond_resched(struct btree_trans *trans)
+{
+       if (need_resched() || race_fault()) {
+               bch2_trans_unlock(trans);
+               schedule();
+               return bch2_trans_relock(trans) ? 0 : -EINTR;
+       } else {
+               return 0;
+       }
+}
+
 static inline int __btree_path_cmp(const struct btree_path *l,
                                   enum btree_id        r_btree_id,
                                   bool                 r_cached,
@@ -165,11 +180,20 @@ static bool bch2_btree_node_upgrade(struct btree_trans *trans,
 {
        struct btree *b = path->l[level].b;
 
-       EBUG_ON(btree_lock_want(path, level) != BTREE_NODE_INTENT_LOCKED);
-
        if (!is_btree_node(path, level))
                return false;
 
+       switch (btree_lock_want(path, level)) {
+       case BTREE_NODE_UNLOCKED:
+               BUG_ON(btree_node_locked(path, level));
+               return true;
+       case BTREE_NODE_READ_LOCKED:
+               BUG_ON(btree_node_intent_locked(path, level));
+               return bch2_btree_node_relock(trans, path, level);
+       case BTREE_NODE_INTENT_LOCKED:
+               break;
+       }
+
        if (btree_node_intent_locked(path, level))
                return true;
 
@@ -364,7 +388,8 @@ static void bch2_btree_path_verify_locks(struct btree_path *path)
        unsigned l;
 
        if (!path->nodes_locked) {
-               BUG_ON(path->uptodate == BTREE_ITER_UPTODATE);
+               BUG_ON(path->uptodate == BTREE_ITER_UPTODATE &&
+                      btree_path_node(path, path->level));
                return;
        }
 
@@ -634,7 +659,8 @@ static void bch2_btree_path_verify(struct btree_trans *trans,
 
        for (i = 0; i < (!path->cached ? BTREE_MAX_DEPTH : 1); i++) {
                if (!path->l[i].b) {
-                       BUG_ON(c->btree_roots[path->btree_id].b->c.level > i);
+                       BUG_ON(!path->cached &&
+                              c->btree_roots[path->btree_id].b->c.level > i);
                        break;
                }
 
@@ -1331,10 +1357,8 @@ retry_all:
                } while (ret);
        }
 
-       if (unlikely(ret == -EIO)) {
-               trans->error = true;
+       if (unlikely(ret == -EIO))
                goto out;
-       }
 
        BUG_ON(ret && ret != -EINTR);
 
@@ -1351,7 +1375,8 @@ retry_all:
 
                EBUG_ON(!(trans->paths_allocated & (1ULL << path->idx)));
 
-               if (path->nodes_locked)
+               if (path->nodes_locked ||
+                   !btree_path_node(path, path->level))
                        i++;
        }
 
@@ -1435,6 +1460,11 @@ static int btree_path_traverse_one(struct btree_trans *trans,
        unsigned depth_want = path->level;
        int ret = 0;
 
+       if (unlikely(trans->restarted)) {
+               ret = -EINTR;
+               goto out;
+       }
+
        /*
         * Ensure we obey path->should_be_locked: if it's set, we can't unlock
         * and re-traverse the path without a transaction restart:
@@ -1499,19 +1529,11 @@ static int __btree_path_traverse_all(struct btree_trans *, int, unsigned long);
 int __must_check bch2_btree_path_traverse(struct btree_trans *trans,
                                          struct btree_path *path, unsigned flags)
 {
-       int ret;
-
        if (path->uptodate < BTREE_ITER_NEED_RELOCK)
                return 0;
 
-       ret =   bch2_trans_cond_resched(trans) ?:
+       return  bch2_trans_cond_resched(trans) ?:
                btree_path_traverse_one(trans, path, flags, _RET_IP_);
-       if (unlikely(ret) && hweight64(trans->paths_allocated) == 1) {
-               ret = __btree_path_traverse_all(trans, ret, _RET_IP_);
-               BUG_ON(ret == -EINTR);
-       }
-
-       return ret;
 }
 
 static void btree_path_copy(struct btree_trans *trans, struct btree_path *dst,
@@ -1677,7 +1699,7 @@ void bch2_dump_trans_paths_updates(struct btree_trans *trans)
        struct btree_path *path;
        struct btree_insert_entry *i;
        unsigned idx;
-       char buf[300];
+       char buf1[300], buf2[300];
 
        btree_trans_verify_sorted(trans);
 
@@ -1686,7 +1708,7 @@ void bch2_dump_trans_paths_updates(struct btree_trans *trans)
                       path->idx, path->ref, path->intent_ref,
                       path->preserve ? " preserve" : "",
                       bch2_btree_ids[path->btree_id],
-                      (bch2_bpos_to_text(&PBUF(buf), path->pos), buf),
+                      (bch2_bpos_to_text(&PBUF(buf1), path->pos), buf1),
 #ifdef CONFIG_BCACHEFS_DEBUG
                       (void *) path->ip_allocated
 #else
@@ -1694,11 +1716,16 @@ void bch2_dump_trans_paths_updates(struct btree_trans *trans)
 #endif
                       );
 
-       trans_for_each_update(trans, i)
-               printk(KERN_ERR "update: btree %s %s %pS\n",
+       trans_for_each_update(trans, i) {
+               struct bkey u;
+               struct bkey_s_c old = bch2_btree_path_peek_slot(i->path, &u);
+
+               printk(KERN_ERR "update: btree %s %pS\n  old %s\n  new %s",
                       bch2_btree_ids[i->btree_id],
-                      (bch2_bkey_val_to_text(&PBUF(buf), trans->c, bkey_i_to_s_c(i->k)), buf),
-                      (void *) i->ip_allocated);
+                      (void *) i->ip_allocated,
+                      (bch2_bkey_val_to_text(&PBUF(buf1), trans->c, old), buf1),
+                      (bch2_bkey_val_to_text(&PBUF(buf2), trans->c, bkey_i_to_s_c(i->k)), buf2));
+       }
 }
 
 static struct btree_path *btree_path_alloc(struct btree_trans *trans,
@@ -1866,15 +1893,16 @@ bch2_btree_iter_traverse(struct btree_iter *iter)
 
 struct btree *bch2_btree_iter_peek_node(struct btree_iter *iter)
 {
+       struct btree_trans *trans = iter->trans;
        struct btree *b = NULL;
        int ret;
 
        EBUG_ON(iter->path->cached);
        bch2_btree_iter_verify(iter);
 
-       ret = bch2_btree_path_traverse(iter->trans, iter->path, iter->flags);
+       ret = bch2_btree_path_traverse(trans, iter->path, iter->flags);
        if (ret)
-               goto out;
+               goto err;
 
        b = btree_path_node(iter->path, iter->path->level);
        if (!b)
@@ -1884,12 +1912,19 @@ struct btree *bch2_btree_iter_peek_node(struct btree_iter *iter)
 
        bkey_init(&iter->k);
        iter->k.p = iter->pos = b->key.k.p;
+
+       iter->path = btree_path_set_pos(trans, iter->path, b->key.k.p,
+                                       iter->flags & BTREE_ITER_INTENT);
        iter->path->should_be_locked = true;
+       BUG_ON(iter->path->uptodate);
 out:
        bch2_btree_iter_verify_entry_exit(iter);
        bch2_btree_iter_verify(iter);
 
        return b;
+err:
+       b = ERR_PTR(ret);
+       goto out;
 }
 
 struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
@@ -1897,32 +1932,41 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
        struct btree_trans *trans = iter->trans;
        struct btree_path *path = iter->path;
        struct btree *b = NULL;
+       unsigned l;
        int ret;
 
+       BUG_ON(trans->restarted);
        EBUG_ON(iter->path->cached);
        bch2_btree_iter_verify(iter);
 
-       /* already got to end? */
+       /* already at end? */
        if (!btree_path_node(path, path->level))
-               goto out;
-
-       bch2_trans_cond_resched(trans);
+               return NULL;
 
-       btree_node_unlock(path, path->level);
-       path->l[path->level].b = BTREE_ITER_NO_NODE_UP;
-       path->level++;
+       /* got to end? */
+       if (!btree_path_node(path, path->level + 1)) {
+               btree_node_unlock(path, path->level);
+               path->l[path->level].b = BTREE_ITER_NO_NODE_UP;
+               path->level++;
+               return NULL;
+       }
 
-       btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
-       ret = bch2_btree_path_traverse(trans, path, iter->flags);
-       if (ret)
-               goto out;
+       if (!bch2_btree_node_relock(trans, path, path->level + 1)) {
+               __bch2_btree_path_unlock(path);
+               path->l[path->level].b = BTREE_ITER_NO_NODE_GET_LOCKS;
+               path->l[path->level + 1].b = BTREE_ITER_NO_NODE_GET_LOCKS;
+               btree_trans_restart(trans);
+               ret = -EINTR;
+               goto err;
+       }
 
-       /* got to end? */
-       b = btree_path_node(path, path->level);
-       if (!b)
-               goto out;
+       b = btree_path_node(path, path->level + 1);
 
-       if (bpos_cmp(iter->pos, b->key.k.p) < 0) {
+       if (!bpos_cmp(iter->pos, b->key.k.p)) {
+               btree_node_unlock(path, path->level);
+               path->l[path->level].b = BTREE_ITER_NO_NODE_UP;
+               path->level++;
+       } else {
                /*
                 * Haven't gotten to the end of the parent node: go back down to
                 * the next child node
@@ -1931,30 +1975,37 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
                        btree_path_set_pos(trans, path, bpos_successor(iter->pos),
                                           iter->flags & BTREE_ITER_INTENT);
 
-               /* Unlock to avoid screwing up our lock invariants: */
-               btree_node_unlock(path, path->level);
-
                path->level = iter->min_depth;
+
+               for (l = path->level + 1; l < BTREE_MAX_DEPTH; l++)
+                       if (btree_lock_want(path, l) == BTREE_NODE_UNLOCKED)
+                               btree_node_unlock(path, l);
+
                btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
                bch2_btree_iter_verify(iter);
 
                ret = bch2_btree_path_traverse(trans, path, iter->flags);
-               if (ret) {
-                       b = NULL;
-                       goto out;
-               }
+               if (ret)
+                       goto err;
 
                b = path->l[path->level].b;
        }
 
        bkey_init(&iter->k);
        iter->k.p = iter->pos = b->key.k.p;
+
+       iter->path = btree_path_set_pos(trans, iter->path, b->key.k.p,
+                                       iter->flags & BTREE_ITER_INTENT);
        iter->path->should_be_locked = true;
+       BUG_ON(iter->path->uptodate);
 out:
        bch2_btree_iter_verify_entry_exit(iter);
        bch2_btree_iter_verify(iter);
 
        return b;
+err:
+       b = ERR_PTR(ret);
+       goto out;
 }
 
 /* Iterate across keys (in leaf nodes only) */
@@ -1962,7 +2013,9 @@ out:
 inline bool bch2_btree_iter_advance(struct btree_iter *iter)
 {
        struct bpos pos = iter->k.p;
-       bool ret = bpos_cmp(pos, SPOS_MAX) != 0;
+       bool ret = (iter->flags & BTREE_ITER_ALL_SNAPSHOTS
+                   ? bpos_cmp(pos, SPOS_MAX)
+                   : bkey_cmp(pos, SPOS_MAX)) != 0;
 
        if (ret && !(iter->flags & BTREE_ITER_IS_EXTENTS))
                pos = bkey_successor(iter, pos);
@@ -2594,6 +2647,7 @@ void bch2_trans_begin(struct btree_trans *trans)
        trans_for_each_update(trans, i)
                __btree_path_put(i->path, true);
 
+       memset(&trans->journal_res, 0, sizeof(trans->journal_res));
        trans->extra_journal_res        = 0;
        trans->nr_updates               = 0;
        trans->mem_top                  = 0;
@@ -2702,7 +2756,7 @@ leaked:
 #endif
 }
 
-int bch2_trans_exit(struct btree_trans *trans)
+void bch2_trans_exit(struct btree_trans *trans)
        __releases(&c->btree_trans_barrier)
 {
        struct btree_insert_entry *i;
@@ -2752,8 +2806,6 @@ int bch2_trans_exit(struct btree_trans *trans)
 
        trans->mem      = (void *) 0x1;
        trans->paths    = (void *) 0x1;
-
-       return trans->error ? -EIO : 0;
 }
 
 static void __maybe_unused