]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
bcachefs: Fix lock ordering with new btree cache code
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 15 Jun 2020 23:53:46 +0000 (19:53 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:41 +0000 (17:08 -0400)
The code that checks lock ordering was recently changed to go off of the
pos of the btree node, rather than the iterator, but the btree cache
code didn't update to handle iterators that point to cached bkeys. Oops

Also, update various debug code.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_iter.c
fs/bcachefs/btree_key_cache.c
fs/bcachefs/btree_key_cache.h
fs/bcachefs/sysfs.c

index 592663a001821d2d7f6e02f6561328cf70201aa8..2bd02e804b76dd9f9c32b3cae44f6b680e4ad096 100644 (file)
@@ -185,6 +185,14 @@ static inline bool btree_iter_get_locks(struct btree_iter *iter,
        return iter->uptodate < BTREE_ITER_NEED_RELOCK;
 }
 
+static struct bpos btree_node_pos(struct btree_bkey_cached_common *_b,
+                                 enum btree_iter_type type)
+{
+       return  type != BTREE_ITER_CACHED
+               ? container_of(_b, struct btree, c)->key.k.p
+               : container_of(_b, struct bkey_cached, c)->key.pos;
+}
+
 /* Slowpath: */
 bool __bch2_btree_node_lock(struct btree *b, struct bpos pos,
                            unsigned level, struct btree_iter *iter,
@@ -253,7 +261,8 @@ bool __bch2_btree_node_lock(struct btree *b, struct bpos pos,
 
                if (iter->btree_id == linked->btree_id &&
                    btree_node_locked(linked, level) &&
-                   bkey_cmp(pos, linked->l[level].b->key.k.p) <= 0)
+                   bkey_cmp(pos, btree_node_pos((void *) linked->l[level].b,
+                                                btree_iter_type(linked))) <= 0)
                        ret = false;
 
                /*
@@ -435,6 +444,22 @@ void bch2_trans_unlock(struct btree_trans *trans)
 
 #ifdef CONFIG_BCACHEFS_DEBUG
 
+static void bch2_btree_iter_verify_cached(struct btree_iter *iter)
+{
+       struct bkey_cached *ck;
+       bool locked = btree_node_locked(iter, 0);
+
+       if (!bch2_btree_node_relock(iter, 0))
+               return;
+
+       ck = (void *) iter->l[0].b;
+       BUG_ON(ck->key.btree_id != iter->btree_id ||
+              bkey_cmp(ck->key.pos, iter->pos));
+
+       if (!locked)
+               btree_node_unlock(iter, 0);
+}
+
 static void bch2_btree_iter_verify_level(struct btree_iter *iter,
                                         unsigned level)
 {
@@ -449,6 +474,12 @@ static void bch2_btree_iter_verify_level(struct btree_iter *iter,
        if (!debug_check_iterators(iter->trans->c))
                return;
 
+       if (btree_iter_type(iter) == BTREE_ITER_CACHED) {
+               if (!level)
+                       bch2_btree_iter_verify_cached(iter);
+               return;
+       }
+
        BUG_ON(iter->level < iter->min_depth);
 
        if (!btree_iter_node(iter, level))
@@ -1257,13 +1288,14 @@ int __must_check __bch2_btree_iter_traverse(struct btree_iter *iter)
        return ret;
 }
 
-static inline void bch2_btree_iter_checks(struct btree_iter *iter,
-                                         enum btree_iter_type type)
+static inline void bch2_btree_iter_checks(struct btree_iter *iter)
 {
+       enum btree_iter_type type = btree_iter_type(iter);
+
        EBUG_ON(iter->btree_id >= BTREE_ID_NR);
-       EBUG_ON(btree_iter_type(iter) != type);
 
-       BUG_ON(type == BTREE_ITER_KEYS &&
+       BUG_ON((type == BTREE_ITER_KEYS ||
+               type == BTREE_ITER_CACHED) &&
               (bkey_cmp(iter->pos, bkey_start_pos(&iter->k)) < 0 ||
                bkey_cmp(iter->pos, iter->k.p) > 0));
 
@@ -1278,7 +1310,8 @@ struct btree *bch2_btree_iter_peek_node(struct btree_iter *iter)
        struct btree *b;
        int ret;
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_NODES);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_NODES);
+       bch2_btree_iter_checks(iter);
 
        if (iter->uptodate == BTREE_ITER_UPTODATE)
                return iter->l[iter->level].b;
@@ -1306,7 +1339,8 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
        struct btree *b;
        int ret;
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_NODES);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_NODES);
+       bch2_btree_iter_checks(iter);
 
        /* already got to end? */
        if (!btree_iter_node(iter, iter->level))
@@ -1534,7 +1568,8 @@ struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
        struct bkey_s_c k;
        int ret;
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_KEYS);
+       bch2_btree_iter_checks(iter);
 
        if (iter->uptodate == BTREE_ITER_UPTODATE &&
            !bkey_deleted(&iter->k))
@@ -1621,7 +1656,8 @@ struct bkey_s_c bch2_btree_iter_peek_with_updates(struct btree_iter *iter)
        struct bkey_s_c k;
        int ret;
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_KEYS);
+       bch2_btree_iter_checks(iter);
 
        while (1) {
                ret = bch2_btree_iter_traverse(iter);
@@ -1681,7 +1717,8 @@ struct bkey_s_c bch2_btree_iter_peek_prev(struct btree_iter *iter)
        struct bkey_s_c k;
        int ret;
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_KEYS);
+       bch2_btree_iter_checks(iter);
 
        if (iter->uptodate == BTREE_ITER_UPTODATE &&
            !bkey_deleted(&iter->k))
@@ -1717,7 +1754,8 @@ struct bkey_s_c bch2_btree_iter_prev(struct btree_iter *iter)
 {
        struct bpos pos = bkey_start_pos(&iter->k);
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_KEYS);
+       bch2_btree_iter_checks(iter);
 
        if (unlikely(!bkey_cmp(pos, POS_MIN)))
                return bkey_s_c_null;
@@ -1798,7 +1836,8 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_iter *iter)
        struct bkey_s_c k;
        int ret;
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_KEYS);
+       bch2_btree_iter_checks(iter);
 
        if (iter->uptodate == BTREE_ITER_UPTODATE)
                return btree_iter_peek_uptodate(iter);
@@ -1844,7 +1883,8 @@ struct bkey_s_c bch2_btree_iter_peek_cached(struct btree_iter *iter)
        struct bkey_cached *ck;
        int ret;
 
-       bch2_btree_iter_checks(iter, BTREE_ITER_CACHED);
+       EBUG_ON(btree_iter_type(iter) != BTREE_ITER_CACHED);
+       bch2_btree_iter_checks(iter);
 
        ret = bch2_btree_iter_traverse(iter);
        if (unlikely(ret))
@@ -2324,6 +2364,15 @@ int bch2_trans_exit(struct btree_trans *trans)
        return trans->error ? -EIO : 0;
 }
 
+static void bch2_btree_iter_node_to_text(struct printbuf *out,
+                                struct btree_bkey_cached_common *_b,
+                                enum btree_iter_type type)
+{
+       pr_buf(out, "    %px l=%u %s:",
+              _b, _b->level, bch2_btree_ids[_b->btree_id]);
+       bch2_bpos_to_text(out, btree_node_pos(_b, type));
+}
+
 void bch2_btree_trans_to_text(struct printbuf *out, struct bch_fs *c)
 {
 #ifdef CONFIG_BCACHEFS_DEBUG
@@ -2348,11 +2397,11 @@ void bch2_btree_trans_to_text(struct printbuf *out, struct bch_fs *c)
 
                        for (l = 0; l < BTREE_MAX_DEPTH; l++) {
                                if (btree_node_locked(iter, l)) {
-                                       b = iter->l[l].b;
-
-                                       pr_buf(out, "    %px %s l=%u ",
-                                              b, btree_node_intent_locked(iter, l) ? "i" : "r", l);
-                                       bch2_bpos_to_text(out, b->key.k.p);
+                                       pr_buf(out, "    %s l=%u ",
+                                              btree_node_intent_locked(iter, l) ? "i" : "r", l);
+                                       bch2_btree_iter_node_to_text(out,
+                                                       (void *) iter->l[l].b,
+                                                       btree_iter_type(iter));
                                        pr_buf(out, "\n");
                                }
                        }
@@ -2366,10 +2415,11 @@ void bch2_btree_trans_to_text(struct printbuf *out, struct bch_fs *c)
                               bch2_btree_ids[trans->locking_btree_id]);
                        bch2_bpos_to_text(out, trans->locking_pos);
 
-                       pr_buf(out, " node %px l=%u %s:",
-                              b, b->c.level,
-                              bch2_btree_ids[b->c.btree_id]);
-                       bch2_bpos_to_text(out, b->key.k.p);
+
+                       pr_buf(out, " node ");
+                       bch2_btree_iter_node_to_text(out,
+                                       (void *) b,
+                                       btree_iter_type(&trans->iters[trans->locking_iter_idx]));
                        pr_buf(out, "\n");
                }
        }
index 2feff59e755a9daec2920d8cb609fe05ba8bfd18..1be01035869f3db9becae594f698486d3548e679 100644 (file)
@@ -1,5 +1,6 @@
 
 #include "bcachefs.h"
+#include "btree_cache.h"
 #include "btree_iter.h"
 #include "btree_key_cache.h"
 #include "btree_locking.h"
@@ -492,3 +493,27 @@ int bch2_fs_btree_key_cache_init(struct btree_key_cache *c)
 {
        return rhashtable_init(&c->table, &bch2_btree_key_cache_params);
 }
+
+void bch2_btree_key_cache_to_text(struct printbuf *out, struct btree_key_cache *c)
+{
+       struct bucket_table *tbl;
+       struct bkey_cached *ck;
+       struct rhash_head *pos;
+       size_t i;
+
+       mutex_lock(&c->lock);
+       tbl = rht_dereference_rcu(c->table.tbl, &c->table);
+
+       for (i = 0; i < tbl->size; i++) {
+               rht_for_each_entry_rcu(ck, pos, tbl, i, hash) {
+                       pr_buf(out, "%s:",
+                              bch2_btree_ids[ck->key.btree_id]);
+                       bch2_bpos_to_text(out, ck->key.pos);
+
+                       if (test_bit(BKEY_CACHED_DIRTY, &ck->flags))
+                               pr_buf(out, " journal seq %llu", ck->journal.seq);
+                       pr_buf(out, "\n");
+               }
+       }
+       mutex_unlock(&c->lock);
+}
index fbc29336091fdb2a381beba1d56b95306289b294..b1756c6c622cec53fbad64f08b2600982ec38167 100644 (file)
@@ -20,4 +20,6 @@ void bch2_fs_btree_key_cache_exit(struct btree_key_cache *);
 void bch2_fs_btree_key_cache_init_early(struct btree_key_cache *);
 int bch2_fs_btree_key_cache_init(struct btree_key_cache *);
 
+void bch2_btree_key_cache_to_text(struct printbuf *, struct btree_key_cache *);
+
 #endif /* _BCACHEFS_BTREE_KEY_CACHE_H */
index bda9eb1598b84fc68feaa7e2ea3368bb657f01dc..67c0f6d2b219ee51de9799e2eaff87ef05fd01c9 100644 (file)
@@ -14,6 +14,7 @@
 #include "btree_cache.h"
 #include "btree_io.h"
 #include "btree_iter.h"
+#include "btree_key_cache.h"
 #include "btree_update.h"
 #include "btree_update_interior.h"
 #include "btree_gc.h"
@@ -165,6 +166,7 @@ read_attribute(journal_debug);
 read_attribute(journal_pins);
 read_attribute(btree_updates);
 read_attribute(dirty_btree_nodes);
+read_attribute(btree_key_cache);
 read_attribute(btree_transactions);
 
 read_attribute(internal_uuid);
@@ -401,6 +403,14 @@ SHOW(bch2_fs)
 
        if (attr == &sysfs_dirty_btree_nodes)
                return bch2_dirty_btree_nodes_print(c, buf);
+
+       if (attr == &sysfs_btree_key_cache) {
+               struct printbuf out = _PBUF(buf, PAGE_SIZE);
+
+               bch2_btree_key_cache_to_text(&out, &c->btree_key_cache);
+               return out.pos - buf;
+       }
+
        if (attr == &sysfs_btree_transactions) {
                struct printbuf out = _PBUF(buf, PAGE_SIZE);
 
@@ -571,6 +581,7 @@ struct attribute *bch2_fs_internal_files[] = {
        &sysfs_journal_pins,
        &sysfs_btree_updates,
        &sysfs_dirty_btree_nodes,
+       &sysfs_btree_key_cache,
        &sysfs_btree_transactions,
 
        &sysfs_read_realloc_races,