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.overstr...@linux.dev>
---
 fs/bcachefs/extents.c    | 10 +++++++++-
 fs/bcachefs/sb-members.c | 22 +++++++++++++++++++++-
 fs/bcachefs/sb-members.h |  8 +++++---
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c
index 98de81bdef6b..7058a3432fd2 100644
--- a/fs/bcachefs/extents.c
+++ b/fs/bcachefs/extents.c
@@ -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;
diff --git a/fs/bcachefs/sb-members.c b/fs/bcachefs/sb-members.c
index 116131f95815..5f7a7d1965e3 100644
--- a/fs/bcachefs/sb-members.c
+++ b/fs/bcachefs/sb-members.c
@@ -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);
diff --git a/fs/bcachefs/sb-members.h b/fs/bcachefs/sb-members.h
index 06bb41a3f360..99d15e54726b 100644
--- a/fs/bcachefs/sb-members.h
+++ b/fs/bcachefs/sb-members.h
@@ -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;
 }
 
-- 
2.49.0


Reply via email to