bcachefs: Kill bch2_dev_bkey_exists() in backpointer code
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 30 Apr 2024 20:50:28 +0000 (16:50 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 8 May 2024 21:29:23 +0000 (17:29 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_foreground.c
fs/bcachefs/backpointers.c
fs/bcachefs/backpointers.h
fs/bcachefs/buckets.c
fs/bcachefs/ec.c
fs/bcachefs/move.c

index f54d908683147fbafef84b953325a025ea1952b8..cc182b2630665f86dcff6acba9d6ec11bf8c1ae2 100644 (file)
@@ -342,7 +342,7 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc
                struct bch_backpointer bp;
                struct bpos bp_pos = POS_MIN;
 
-               ret = bch2_get_next_backpointer(trans, POS(ca->dev_idx, b), -1,
+               ret = bch2_get_next_backpointer(trans, ca, POS(ca->dev_idx, b), -1,
                                                &bp_pos, &bp,
                                                BTREE_ITER_nopreserve);
                if (ret) {
index 282aee70a51f8e71df927074eea77592b2659811..3f5333b4c3dee80cac3a802848e903f25cce0f16 100644 (file)
@@ -23,6 +23,7 @@ static bool extent_matches_bp(struct bch_fs *c,
        const union bch_extent_entry *entry;
        struct extent_ptr_decoded p;
 
+       rcu_read_lock();
        bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
                struct bpos bucket2;
                struct bch_backpointer bp2;
@@ -30,13 +31,18 @@ static bool extent_matches_bp(struct bch_fs *c,
                if (p.ptr.cached)
                        continue;
 
-               struct bch_dev *ca = bch2_dev_bkey_exists(c, p.ptr.dev);
+               struct bch_dev *ca = bch2_dev_rcu(c, p.ptr.dev);
+               if (!ca)
+                       continue;
 
                bch2_extent_ptr_to_bp(c, ca, btree_id, level, k, p, entry, &bucket2, &bp2);
                if (bpos_eq(bucket, bucket2) &&
-                   !memcmp(&bp, &bp2, sizeof(bp)))
+                   !memcmp(&bp, &bp2, sizeof(bp))) {
+                       rcu_read_unlock();
                        return true;
+               }
        }
+       rcu_read_unlock();
 
        return false;
 }
@@ -47,16 +53,21 @@ int bch2_backpointer_invalid(struct bch_fs *c, struct bkey_s_c k,
 {
        struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
 
-       /* these will be caught by fsck */
-       if (!bch2_dev_exists(c, bp.k->p.inode))
+       rcu_read_lock();
+       struct bch_dev *ca = bch2_dev_rcu(c, bp.k->p.inode);
+       if (!ca) {
+               /* these will be caught by fsck */
+               rcu_read_unlock();
                return 0;
+       }
 
-       struct bch_dev *ca = bch2_dev_bkey_exists(c, bp.k->p.inode);
-       struct bpos bucket = bp_pos_to_bucket(c, bp.k->p);
+       struct bpos bucket = bp_pos_to_bucket(ca, bp.k->p);
+       struct bpos bp_pos = bucket_pos_to_bp_noerror(ca, bucket, bp.v->bucket_offset);
+       rcu_read_unlock();
        int ret = 0;
 
        bkey_fsck_err_on((bp.v->bucket_offset >> MAX_EXTENT_COMPRESS_RATIO_SHIFT) >= ca->mi.bucket_size ||
-                        !bpos_eq(bp.k->p, bucket_pos_to_bp_noerror(ca, bucket, bp.v->bucket_offset)),
+                        !bpos_eq(bp.k->p, bp_pos),
                         c, err,
                         backpointer_bucket_offset_wrong,
                         "backpointer bucket_offset wrong");
@@ -77,10 +88,16 @@ void bch2_backpointer_to_text(struct printbuf *out, const struct bch_backpointer
 
 void bch2_backpointer_k_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k)
 {
-       if (bch2_dev_exists(c, k.k->p.inode)) {
+       rcu_read_lock();
+       struct bch_dev *ca = bch2_dev_rcu(c, k.k->p.inode);
+       if (ca) {
+               struct bpos bucket = bp_pos_to_bucket(ca, k.k->p);
+               rcu_read_unlock();
                prt_str(out, "bucket=");
-               bch2_bpos_to_text(out, bp_pos_to_bucket(c, k.k->p));
+               bch2_bpos_to_text(out, bucket);
                prt_str(out, " ");
+       } else {
+               rcu_read_unlock();
        }
 
        bch2_backpointer_to_text(out, bkey_s_c_to_backpointer(k).v);
@@ -146,6 +163,7 @@ static noinline int backpointer_mod_err(struct btree_trans *trans,
 }
 
 int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *trans,
+                               struct bch_dev *ca,
                                struct bpos bucket,
                                struct bch_backpointer bp,
                                struct bkey_s_c orig_k,
@@ -162,7 +180,7 @@ int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *trans,
                return ret;
 
        bkey_backpointer_init(&bp_k->k_i);
-       bp_k->k.p = bucket_pos_to_bp(trans->c, bucket, bp.bucket_offset);
+       bp_k->k.p = bucket_pos_to_bp(ca, bucket, bp.bucket_offset);
        bp_k->v = bp;
 
        if (!insert) {
@@ -198,13 +216,13 @@ err:
  * Find the next backpointer >= *bp_offset:
  */
 int bch2_get_next_backpointer(struct btree_trans *trans,
+                             struct bch_dev *ca,
                              struct bpos bucket, int gen,
                              struct bpos *bp_pos,
                              struct bch_backpointer *bp,
                              unsigned iter_flags)
 {
-       struct bch_fs *c = trans->c;
-       struct bpos bp_end_pos = bucket_pos_to_bp(c, bpos_nosnap_successor(bucket), 0);
+       struct bpos bp_end_pos = bucket_pos_to_bp(ca, bpos_nosnap_successor(bucket), 0);
        struct btree_iter alloc_iter = { NULL }, bp_iter = { NULL };
        struct bkey_s_c k;
        int ret = 0;
@@ -224,7 +242,7 @@ int bch2_get_next_backpointer(struct btree_trans *trans,
                        goto done;
        }
 
-       *bp_pos = bpos_max(*bp_pos, bucket_pos_to_bp(c, bucket, 0));
+       *bp_pos = bpos_max(*bp_pos, bucket_pos_to_bp(ca, bucket, 0));
 
        for_each_btree_key_norestart(trans, bp_iter, BTREE_ID_backpointers,
                                     *bp_pos, iter_flags, k, ret) {
@@ -250,7 +268,6 @@ static void backpointer_not_found(struct btree_trans *trans,
 {
        struct bch_fs *c = trans->c;
        struct printbuf buf = PRINTBUF;
-       struct bpos bucket = bp_pos_to_bucket(c, bp_pos);
 
        /*
         * If we're using the btree write buffer, the backpointer we were
@@ -260,6 +277,10 @@ static void backpointer_not_found(struct btree_trans *trans,
        if (likely(!bch2_backpointers_no_use_write_buffer))
                return;
 
+       struct bpos bucket;
+       if (!bp_pos_to_bucket_nodev(c, bp_pos, &bucket))
+               return;
+
        prt_printf(&buf, "backpointer doesn't match %s it points to:\n  ",
                   bp.level ? "btree node" : "extent");
        prt_printf(&buf, "bucket: ");
@@ -289,15 +310,17 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans,
 {
        if (likely(!bp.level)) {
                struct bch_fs *c = trans->c;
-               struct bpos bucket = bp_pos_to_bucket(c, bp_pos);
-               struct bkey_s_c k;
+
+               struct bpos bucket;
+               if (!bp_pos_to_bucket_nodev(c, bp_pos, &bucket))
+                       return bkey_s_c_err(-EIO);
 
                bch2_trans_node_iter_init(trans, iter,
                                          bp.btree_id,
                                          bp.pos,
                                          0, 0,
                                          iter_flags);
-               k = bch2_btree_iter_peek_slot(iter);
+               struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
                if (bkey_err(k)) {
                        bch2_trans_iter_exit(trans, iter);
                        return k;
@@ -326,18 +349,20 @@ struct btree *bch2_backpointer_get_node(struct btree_trans *trans,
                                        struct bch_backpointer bp)
 {
        struct bch_fs *c = trans->c;
-       struct bpos bucket = bp_pos_to_bucket(c, bp_pos);
-       struct btree *b;
 
        BUG_ON(!bp.level);
 
+       struct bpos bucket;
+       if (!bp_pos_to_bucket_nodev(c, bp_pos, &bucket))
+               return ERR_PTR(-EIO);
+
        bch2_trans_node_iter_init(trans, iter,
                                  bp.btree_id,
                                  bp.pos,
                                  0,
                                  bp.level - 1,
                                  0);
-       b = bch2_btree_iter_peek_node(iter);
+       struct btree *b = bch2_btree_iter_peek_node(iter);
        if (IS_ERR_OR_NULL(b))
                goto err;
 
@@ -368,16 +393,16 @@ static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_
        struct printbuf buf = PRINTBUF;
        int ret = 0;
 
-       if (fsck_err_on(!bch2_dev_exists(c, k.k->p.inode), c,
-                       backpointer_to_missing_device,
-                       "backpointer for missing device:\n%s",
-                       (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
-               ret = bch2_btree_delete_at(trans, bp_iter, 0);
+       struct bpos bucket;
+       if (!bp_pos_to_bucket_nodev_noerror(c, k.k->p, &bucket)) {
+               if (fsck_err(c, backpointer_to_missing_device,
+                            "backpointer for missing device:\n%s",
+                            (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
+                       ret = bch2_btree_delete_at(trans, bp_iter, 0);
                goto out;
        }
 
-       alloc_k = bch2_bkey_get_iter(trans, &alloc_iter, BTREE_ID_alloc,
-                                    bp_pos_to_bucket(c, k.k->p), 0);
+       alloc_k = bch2_bkey_get_iter(trans, &alloc_iter, BTREE_ID_alloc, bucket, 0);
        ret = bkey_err(alloc_k);
        if (ret)
                goto out;
@@ -512,25 +537,27 @@ static int check_bp_exists(struct btree_trans *trans,
        struct printbuf buf = PRINTBUF;
        struct bkey_s_c bp_k;
        struct bkey_buf tmp;
-       int ret;
+       int ret = 0;
 
        bch2_bkey_buf_init(&tmp);
 
-       if (!bch2_dev_bucket_exists(c, bucket)) {
+       struct bch_dev *ca = bch2_dev_bucket_tryget(c, bucket);
+       if (!ca) {
                prt_str(&buf, "extent for nonexistent device:bucket ");
                bch2_bpos_to_text(&buf, bucket);
                prt_str(&buf, "\n  ");
                bch2_bkey_val_to_text(&buf, c, orig_k);
                bch_err(c, "%s", buf.buf);
-               return -BCH_ERR_fsck_repair_unimplemented;
+               ret = -BCH_ERR_fsck_repair_unimplemented;
+               goto err;
        }
 
        if (bpos_lt(bucket, s->bucket_start) ||
            bpos_gt(bucket, s->bucket_end))
-               return 0;
+               goto out;
 
        bp_k = bch2_bkey_get_iter(trans, &bp_iter, BTREE_ID_backpointers,
-                                 bucket_pos_to_bp(c, bucket, bp.bucket_offset),
+                                 bucket_pos_to_bp(ca, bucket, bp.bucket_offset),
                                  0);
        ret = bkey_err(bp_k);
        if (ret)
@@ -563,6 +590,7 @@ fsck_err:
        bch2_trans_iter_exit(trans, &other_extent_iter);
        bch2_trans_iter_exit(trans, &bp_iter);
        bch2_bkey_buf_exit(&tmp, c);
+       bch2_dev_put(ca);
        printbuf_exit(&buf);
        return ret;
 check_existing_bp:
@@ -638,13 +666,13 @@ missing:
 
        struct bkey_i_backpointer n_bp_k;
        bkey_backpointer_init(&n_bp_k.k_i);
-       n_bp_k.k.p = bucket_pos_to_bp(trans->c, bucket, bp.bucket_offset);
+       n_bp_k.k.p = bucket_pos_to_bp(ca, bucket, bp.bucket_offset);
        n_bp_k.v = bp;
        prt_printf(&buf, "\n  want:  ");
        bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&n_bp_k.k_i));
 
        if (fsck_err(c, ptr_to_missing_backpointer, "%s", buf.buf))
-               ret = bch2_bucket_backpointer_mod(trans, bucket, bp, orig_k, true);
+               ret = bch2_bucket_backpointer_mod(trans, ca, bucket, bp, orig_k, true);
 
        goto out;
 }
@@ -668,8 +696,14 @@ static int check_extent_to_backpointers(struct btree_trans *trans,
                if (p.ptr.cached)
                        continue;
 
-               struct bch_dev *ca = bch2_dev_bkey_exists(c, p.ptr.dev);
-               bch2_extent_ptr_to_bp(c, ca, btree, level, k, p, entry, &bucket_pos, &bp);
+               rcu_read_lock();
+               struct bch_dev *ca = bch2_dev_rcu(c, p.ptr.dev);
+               if (ca)
+                       bch2_extent_ptr_to_bp(c, ca, btree, level, k, p, entry, &bucket_pos, &bp);
+               rcu_read_unlock();
+
+               if (!ca)
+                       continue;
 
                ret = check_bp_exists(trans, s, bucket_pos, bp, k);
                if (ret)
index 1d270c40fce9ab9f5375ff08ecec99637481e379..929f4a068a0a077c4a5dbb98c90fdd17d30478a0 100644 (file)
@@ -6,6 +6,7 @@
 #include "btree_iter.h"
 #include "btree_update.h"
 #include "buckets.h"
+#include "error.h"
 #include "super.h"
 
 static inline u64 swab40(u64 x)
@@ -36,15 +37,29 @@ void bch2_backpointer_swab(struct bkey_s);
  * Convert from pos in backpointer btree to pos of corresponding bucket in alloc
  * btree:
  */
-static inline struct bpos bp_pos_to_bucket(const struct bch_fs *c,
-                                          struct bpos bp_pos)
+static inline struct bpos bp_pos_to_bucket(const struct bch_dev *ca, struct bpos bp_pos)
 {
-       struct bch_dev *ca = bch2_dev_bkey_exists(c, bp_pos.inode);
        u64 bucket_sector = bp_pos.offset >> MAX_EXTENT_COMPRESS_RATIO_SHIFT;
 
        return POS(bp_pos.inode, sector_to_bucket(ca, bucket_sector));
 }
 
+static inline bool bp_pos_to_bucket_nodev_noerror(struct bch_fs *c, struct bpos bp_pos, struct bpos *bucket)
+{
+       rcu_read_lock();
+       struct bch_dev *ca = bch2_dev_rcu(c, bp_pos.inode);
+       if (ca)
+               *bucket = bp_pos_to_bucket(ca, bp_pos);
+       rcu_read_unlock();
+       return ca != NULL;
+}
+
+static inline bool bp_pos_to_bucket_nodev(struct bch_fs *c, struct bpos bp_pos, struct bpos *bucket)
+{
+       return !bch2_fs_inconsistent_on(!bp_pos_to_bucket_nodev_noerror(c, bp_pos, bucket),
+                                       c, "backpointer for missing device %llu", bp_pos.inode);
+}
+
 static inline struct bpos bucket_pos_to_bp_noerror(const struct bch_dev *ca,
                                                   struct bpos bucket,
                                                   u64 bucket_offset)
@@ -57,32 +72,32 @@ static inline struct bpos bucket_pos_to_bp_noerror(const struct bch_dev *ca,
 /*
  * Convert from pos in alloc btree + bucket offset to pos in backpointer btree:
  */
-static inline struct bpos bucket_pos_to_bp(const struct bch_fs *c,
+static inline struct bpos bucket_pos_to_bp(const struct bch_dev *ca,
                                           struct bpos bucket,
                                           u64 bucket_offset)
 {
-       struct bch_dev *ca = bch2_dev_bkey_exists(c, bucket.inode);
        struct bpos ret = bucket_pos_to_bp_noerror(ca, bucket, bucket_offset);
-       EBUG_ON(!bkey_eq(bucket, bp_pos_to_bucket(c, ret)));
+       EBUG_ON(!bkey_eq(bucket, bp_pos_to_bucket(ca, ret)));
        return ret;
 }
 
-int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *, struct bpos bucket,
-                               struct bch_backpointer, struct bkey_s_c, bool);
+int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *, struct bch_dev *,
+                               struct bpos bucket, struct bch_backpointer, struct bkey_s_c, bool);
 
 static inline int bch2_bucket_backpointer_mod(struct btree_trans *trans,
+                               struct bch_dev *ca,
                                struct bpos bucket,
                                struct bch_backpointer bp,
                                struct bkey_s_c orig_k,
                                bool insert)
 {
        if (unlikely(bch2_backpointers_no_use_write_buffer))
-               return bch2_bucket_backpointer_mod_nowritebuffer(trans, bucket, bp, orig_k, insert);
+               return bch2_bucket_backpointer_mod_nowritebuffer(trans, ca, bucket, bp, orig_k, insert);
 
        struct bkey_i_backpointer bp_k;
 
        bkey_backpointer_init(&bp_k.k_i);
-       bp_k.k.p = bucket_pos_to_bp(trans->c, bucket, bp.bucket_offset);
+       bp_k.k.p = bucket_pos_to_bp(ca, bucket, bp.bucket_offset);
        bp_k.v = bp;
 
        if (!insert) {
@@ -142,7 +157,7 @@ static inline void bch2_extent_ptr_to_bp(struct bch_fs *c, struct bch_dev *ca,
        };
 }
 
-int bch2_get_next_backpointer(struct btree_trans *, struct bpos, int,
+int bch2_get_next_backpointer(struct btree_trans *, struct bch_dev *ca, struct bpos, int,
                              struct bpos *, struct bch_backpointer *, unsigned);
 struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *, struct btree_iter *,
                                         struct bpos, struct bch_backpointer,
index 4774f9c7f060e0733d86ed8c81ae52c3438a9df2..ae6d6879e2e02dd25b47eaa19e7450a6fb45c10a 100644 (file)
@@ -988,7 +988,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans,
                        goto err;
 
                if (!p.ptr.cached) {
-                       ret = bch2_bucket_backpointer_mod(trans, bucket, bp, k, insert);
+                       ret = bch2_bucket_backpointer_mod(trans, ca, bucket, bp, k, insert);
                        if (ret)
                                goto err;
                }
index f09df7f9036a0642f4b76bfecf93cce78e5be9c9..6d41530615cbd555c814a664620e1a9fcbef4f38 100644 (file)
@@ -1198,6 +1198,7 @@ err:
 }
 
 static int ec_stripe_update_extent(struct btree_trans *trans,
+                                  struct bch_dev *ca,
                                   struct bpos bucket, u8 gen,
                                   struct ec_stripe_buf *s,
                                   struct bpos *bp_pos)
@@ -1213,7 +1214,7 @@ static int ec_stripe_update_extent(struct btree_trans *trans,
        struct bkey_i *n;
        int ret, dev, block;
 
-       ret = bch2_get_next_backpointer(trans, bucket, gen,
+       ret = bch2_get_next_backpointer(trans, ca, bucket, gen,
                                bp_pos, &bp, BTREE_ITER_cached);
        if (ret)
                return ret;
@@ -1311,7 +1312,7 @@ static int ec_stripe_update_bucket(struct btree_trans *trans, struct ec_stripe_b
                ret = commit_do(trans, NULL, NULL,
                                BCH_TRANS_COMMIT_no_check_rw|
                                BCH_TRANS_COMMIT_no_enospc,
-                       ec_stripe_update_extent(trans, bucket_pos, ptr.gen, s, &bp_pos));
+                       ec_stripe_update_extent(trans, ca, bucket_pos, ptr.gen, s, &bp_pos));
                if (ret)
                        break;
                if (bkey_eq(bp_pos, POS_MAX))
index c441ce7c92eca4b067b3cb41a76bfa8384feb1e7..0e3203de1cd64cff5339d820ca65228b31de3fb9 100644 (file)
@@ -729,7 +729,7 @@ int bch2_evacuate_bucket(struct moving_context *ctxt,
 
                bch2_trans_begin(trans);
 
-               ret = bch2_get_next_backpointer(trans, bucket, gen,
+               ret = bch2_get_next_backpointer(trans, ca, bucket, gen,
                                                &bp_pos, &bp,
                                                BTREE_ITER_cached);
                if (bch2_err_matches(ret, BCH_ERR_transaction_restart))