bcachefs: bch2_dev_missing_bkey()
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 15 Apr 2025 18:08:42 +0000 (14:08 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:17 +0000 (20:14 -0400)
Part of the ongoing project to kill off bch2_(fs|trans)_inconsistent
calls - they generally need to be replaced with either

- a fsck_err() call that can repair the error, or

- logging an error of the appropriate type in the superblock, and
  flagging the appropriate recovery pass to repair the error

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/extents.c
fs/bcachefs/sb-members.c
fs/bcachefs/sb-members.h

index a369f978ffe6c34232430a2dbd562ea2e1f8f36b..ef116c55f0a74965b9464d59d7d0012238ab8147 100644 (file)
@@ -158,7 +158,15 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k,
                if (dev >= 0 && p.ptr.dev != dev)
                        continue;
 
-               struct bch_dev *ca = bch2_dev_rcu(c, p.ptr.dev);
+               struct bch_dev *ca = bch2_dev_rcu_noerror(c, p.ptr.dev);
+
+               if (unlikely(!ca && p.ptr.dev != BCH_SB_MEMBER_INVALID)) {
+                       rcu_read_unlock();
+                       int ret = bch2_dev_missing_bkey(c, k, p.ptr.dev);
+                       if (ret)
+                               return ret;
+                       rcu_read_lock();
+               }
 
                if (p.ptr.cached && (!ca || dev_ptr_stale_rcu(ca, &p.ptr)))
                        continue;
index 72779912939b6f0014b6211def00ba2b515b5a11..f776b00c3cc0301cd0cb96c90fa1135fa591e08e 100644 (file)
@@ -5,11 +5,31 @@
 #include "disk_groups.h"
 #include "error.h"
 #include "opts.h"
+#include "recovery_passes.h"
 #include "replicas.h"
 #include "sb-members.h"
 #include "super-io.h"
 
-void bch2_dev_missing(struct bch_fs *c, unsigned dev)
+int bch2_dev_missing_bkey(struct bch_fs *c, struct bkey_s_c k, unsigned dev)
+{
+       struct printbuf buf = PRINTBUF;
+       bch2_log_msg_start(c, &buf);
+
+       prt_printf(&buf, "pointer to nonexistent device %u in key\n", dev);
+       bch2_bkey_val_to_text(&buf, c, k);
+
+       bool print = bch2_count_fsck_err(c, ptr_to_invalid_device, &buf);
+
+       int ret = bch2_run_explicit_recovery_pass_printbuf(c, &buf,
+                                                BCH_RECOVERY_PASS_check_allocations);
+
+       if (print)
+               bch2_print_string_as_lines(KERN_ERR, buf.buf);
+       printbuf_exit(&buf);
+       return ret;
+}
+
+void bch2_dev_missing_atomic(struct bch_fs *c, unsigned dev)
 {
        if (dev != BCH_SB_MEMBER_INVALID)
                bch2_fs_inconsistent(c, "pointer to nonexistent device %u", dev);
index 42786657522ce1e7517f1f70a50c4d6bca295b88..0f1741fffcb63a8b9ac73a65c6c11310e4722c8b 100644 (file)
@@ -218,13 +218,15 @@ static inline struct bch_dev *bch2_dev_rcu_noerror(struct bch_fs *c, unsigned de
                : NULL;
 }
 
-void bch2_dev_missing(struct bch_fs *, unsigned);
+int bch2_dev_missing_bkey(struct bch_fs *, struct bkey_s_c, unsigned);
+
+void bch2_dev_missing_atomic(struct bch_fs *, unsigned);
 
 static inline struct bch_dev *bch2_dev_rcu(struct bch_fs *c, unsigned dev)
 {
        struct bch_dev *ca = bch2_dev_rcu_noerror(c, dev);
        if (unlikely(!ca))
-               bch2_dev_missing(c, dev);
+               bch2_dev_missing_atomic(c, dev);
        return ca;
 }
 
@@ -242,7 +244,7 @@ static inline struct bch_dev *bch2_dev_tryget(struct bch_fs *c, unsigned dev)
 {
        struct bch_dev *ca = bch2_dev_tryget_noerror(c, dev);
        if (unlikely(!ca))
-               bch2_dev_missing(c, dev);
+               bch2_dev_missing_atomic(c, dev);
        return ca;
 }