]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: bch2_fs_emergency_read_only2()
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 13 May 2025 14:53:23 +0000 (10:53 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:56 +0000 (20:14 -0400)
More error message cleanup: instead of multiple printk()s per error, we
want to be building up a single error message in a printbuf, so that it
can be printed with indenting that shows grouping and avoid errors
getting interspersed or lost in the log.

This gets rid of most calls to bch2_fs_emergency_read_only(). We still
have calls to
 - bch2_fatal_error()
 - bch2_fs_fatal_error()
 - bch2_fs_fatal_err_on()

that need work.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_io.c
fs/bcachefs/btree_iter.c
fs/bcachefs/btree_update_interior.c
fs/bcachefs/data_update.c
fs/bcachefs/error.c
fs/bcachefs/error.h
fs/bcachefs/fs-ioctl.c
fs/bcachefs/journal_io.c
fs/bcachefs/recovery.c
fs/bcachefs/super.c
fs/bcachefs/super.h

index a3250241e13e05c4e7b669e4337d34dfec67b91c..97cd25cd492b9d15d503675732aad2f3021543b9 100644 (file)
@@ -1766,23 +1766,31 @@ void bch2_btree_node_read(struct btree_trans *trans, struct btree *b,
                                         NULL, &pick, -1);
 
        if (ret <= 0) {
+               bool ratelimit = true;
                struct printbuf buf = PRINTBUF;
+               bch2_log_msg_start(c, &buf);
 
                prt_str(&buf, "btree node read error: no device to read from\n at ");
                bch2_btree_pos_to_text(&buf, c, b);
                prt_newline(&buf);
                bch2_btree_lost_data(c, &buf, b->c.btree_id);
-               bch_err_ratelimited(c, "%s", buf.buf);
 
                if (c->opts.recovery_passes & BIT_ULL(BCH_RECOVERY_PASS_check_topology) &&
-                   c->curr_recovery_pass > BCH_RECOVERY_PASS_check_topology)
-                       bch2_fatal_error(c);
+                   c->curr_recovery_pass > BCH_RECOVERY_PASS_check_topology &&
+                   bch2_fs_emergency_read_only2(c, &buf))
+                       ratelimit = false;
+
+               static DEFINE_RATELIMIT_STATE(rs,
+                                             DEFAULT_RATELIMIT_INTERVAL,
+                                             DEFAULT_RATELIMIT_BURST);
+               if (!ratelimit || __ratelimit(&rs))
+                       bch2_print_str(c, KERN_ERR, buf.buf);
+               printbuf_exit(&buf);
 
                set_btree_node_read_error(b);
                clear_btree_node_read_in_flight(b);
                smp_mb__after_atomic();
                wake_up_bit(&b->flags, BTREE_NODE_read_in_flight);
-               printbuf_exit(&buf);
                return;
        }
 
index 55f4169ce0c9ced7b5a3cceef3d9061a97f5c632..e0c1e873c886d5a643f20fd8184b981bc47cbdf4 100644 (file)
@@ -16,6 +16,7 @@
 #include "journal_io.h"
 #include "replicas.h"
 #include "snapshot.h"
+#include "super.h"
 #include "trace.h"
 
 #include <linux/random.h>
@@ -3449,28 +3450,44 @@ got_trans:
        return trans;
 }
 
-static void check_btree_paths_leaked(struct btree_trans *trans)
-{
 #ifdef CONFIG_BCACHEFS_DEBUG
-       struct bch_fs *c = trans->c;
+
+static bool btree_paths_leaked(struct btree_trans *trans)
+{
        struct btree_path *path;
        unsigned i;
 
        trans_for_each_path(trans, path, i)
                if (path->ref)
-                       goto leaked;
-       return;
-leaked:
-       bch_err(c, "btree paths leaked from %s!", trans->fn);
-       trans_for_each_path(trans, path, i)
-               if (path->ref)
-                       printk(KERN_ERR "  btree %s %pS\n",
-                              bch2_btree_id_str(path->btree_id),
-                              (void *) path->ip_allocated);
-       /* Be noisy about this: */
-       bch2_fatal_error(c);
-#endif
+                       return true;
+       return false;
+}
+
+static void check_btree_paths_leaked(struct btree_trans *trans)
+{
+       if (btree_paths_leaked(trans)) {
+               struct bch_fs *c = trans->c;
+               struct btree_path *path;
+               unsigned i;
+
+               struct printbuf buf = PRINTBUF;
+               bch2_log_msg_start(c, &buf);
+
+               prt_printf(&buf, "btree paths leaked from %s!\n", trans->fn);
+               trans_for_each_path(trans, path, i)
+                       if (path->ref)
+                               prt_printf(&buf, "btree %s %pS\n",
+                                          bch2_btree_id_str(path->btree_id),
+                                          (void *) path->ip_allocated);
+
+               bch2_fs_emergency_read_only2(c, &buf);
+               bch2_print_str(c, KERN_ERR, buf.buf);
+               printbuf_exit(&buf);
+       }
 }
+#else
+static inline void check_btree_paths_leaked(struct btree_trans *trans) {}
+#endif
 
 void bch2_trans_put(struct btree_trans *trans)
        __releases(&c->btree_trans_barrier)
index 3d25c2be035ed9e77a8c435231d70de23fd1e4f9..2d43d51b597d7e0f456abacef0e43241336d88b6 100644 (file)
@@ -1813,10 +1813,10 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t
                           __func__, b->c.level);
                bch2_btree_update_to_text(&buf, as);
                bch2_btree_path_to_text(&buf, trans, path_idx);
+               bch2_fs_emergency_read_only2(c, &buf);
 
                bch2_print_str(c, KERN_ERR, buf.buf);
                printbuf_exit(&buf);
-               bch2_fs_emergency_read_only(c);
                return -EIO;
        }
 
index 9b44f11fb0d9b2b7d4d425b7bfb18667c9328e5c..e5909e54ad2e587c2b6e0f9ecfe82ae1fc0fa793 100644 (file)
@@ -348,6 +348,7 @@ restart_drop_extra_replicas:
                                                 });
                if (invalid) {
                        struct printbuf buf = PRINTBUF;
+                       bch2_log_msg_start(c, &buf);
 
                        prt_str(&buf, "about to insert invalid key in data update path");
                        prt_printf(&buf, "\nop.nonce: %u", m->op.nonce);
@@ -358,10 +359,11 @@ restart_drop_extra_replicas:
                        prt_str(&buf, "\nnew: ");
                        bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(insert));
 
+                       bch2_fs_emergency_read_only2(c, &buf);
+
                        bch2_print_str(c, KERN_ERR, buf.buf);
                        printbuf_exit(&buf);
 
-                       bch2_fatal_error(c);
                        ret = -BCH_ERR_invalid_bkey;
                        goto out;
                }
index 03567c559623f3b3d1aaeae3b27f321b3a6267f4..52f1108d582933a89dca91cf0177dad51e46d23d 100644 (file)
 
 #define FSCK_ERR_RATELIMIT_NR  10
 
-void bch2_log_msg_start(struct bch_fs *c, struct printbuf *out)
+void __bch2_log_msg_start(const char *fs_or_dev_name, struct printbuf *out)
 {
        printbuf_indent_add_nextline(out, 2);
 
 #ifdef BCACHEFS_LOG_PREFIX
-       prt_printf(out, bch2_log_msg(c, ""));
+       prt_printf(out, "bcachefs (%s): ", fs_or_dev_name);
 #endif
 }
 
@@ -29,9 +29,7 @@ bool __bch2_inconsistent_error(struct bch_fs *c, struct printbuf *out)
                return false;
        case BCH_ON_ERROR_fix_safe:
        case BCH_ON_ERROR_ro:
-               if (bch2_fs_emergency_read_only(c))
-                       prt_printf(out, "inconsistency detected - emergency read only at journal seq %llu\n",
-                                  journal_cur_seq(&c->journal));
+               bch2_fs_emergency_read_only2(c, out);
                return true;
        case BCH_ON_ERROR_panic:
                bch2_print_str(c, KERN_ERR, out->buf);
@@ -151,14 +149,17 @@ void bch2_io_error_work(struct work_struct *work)
 
                bool dev = !__bch2_dev_set_state(c, ca, BCH_MEMBER_STATE_ro,
                                                 BCH_FORCE_IF_DEGRADED);
+               struct printbuf buf = PRINTBUF;
+               __bch2_log_msg_start(ca->name, &buf);
 
-               bch_err(ca,
-                       "writes erroring for %u seconds, setting %s ro",
+               prt_printf(&buf, "writes erroring for %u seconds, setting %s ro",
                        c->opts.write_error_timeout,
                        dev ? "device" : "filesystem");
                if (!dev)
-                       bch2_fs_emergency_read_only(c);
+                       bch2_fs_emergency_read_only2(c, &buf);
 
+               bch2_print_str(c, KERN_ERR, buf.buf);
+               printbuf_exit(&buf);
        }
 out:
        up_write(&c->state_lock);
index d89dd270b2e58bf45cdd0664a671cb64e6ee8d62..5123d4c8677003afd1d1c516cd951cad3717b1c9 100644 (file)
@@ -18,7 +18,12 @@ struct work_struct;
 
 /* Error messages: */
 
-void bch2_log_msg_start(struct bch_fs *, struct printbuf *);
+void __bch2_log_msg_start(const char *, struct printbuf *);
+
+static inline void bch2_log_msg_start(struct bch_fs *c, struct printbuf *out)
+{
+       __bch2_log_msg_start(c->name, out);
+}
 
 /*
  * Inconsistency errors: The on disk data is inconsistent. If these occur during
index a82dfce9e4ad3735279fbfe1310e907ff24ac0c0..05361a79320685f6678524a2d339a0f0628ab2da 100644 (file)
@@ -172,7 +172,10 @@ static int bch2_ioc_goingdown(struct bch_fs *c, u32 __user *arg)
        if (get_user(flags, arg))
                return -EFAULT;
 
-       bch_notice(c, "shutdown by ioctl type %u", flags);
+       struct printbuf buf = PRINTBUF;
+       bch2_log_msg_start(c, &buf);
+
+       prt_printf(&buf, "shutdown by ioctl type %u", flags);
 
        switch (flags) {
        case FSOP_GOING_FLAGS_DEFAULT:
@@ -180,20 +183,23 @@ static int bch2_ioc_goingdown(struct bch_fs *c, u32 __user *arg)
                if (ret)
                        break;
                bch2_journal_flush(&c->journal);
-               bch2_fs_emergency_read_only(c);
+               bch2_fs_emergency_read_only2(c, &buf);
                bdev_thaw(c->vfs_sb->s_bdev);
                break;
        case FSOP_GOING_FLAGS_LOGFLUSH:
                bch2_journal_flush(&c->journal);
                fallthrough;
        case FSOP_GOING_FLAGS_NOLOGFLUSH:
-               bch2_fs_emergency_read_only(c);
+               bch2_fs_emergency_read_only2(c, &buf);
                break;
        default:
                ret = -EINVAL;
-               break;
+               goto noprint;
        }
 
+       bch2_print_str(c, KERN_ERR, buf.buf);
+noprint:
+       printbuf_exit(&buf);
        return ret;
 }
 
index c593d77dc8f275e679b49c36889a5b5bc633d693..06f7b018492c9759f0ca61b7d0dc4d41627287d2 100644 (file)
@@ -1628,8 +1628,6 @@ static CLOSURE_CALLBACK(journal_write_done)
                               : j->noflush_write_time, j->write_start_time);
 
        if (!w->devs_written.nr) {
-               if (!bch2_journal_error(j))
-                       bch_err(c, "unable to write journal to sufficient devices");
                err = -BCH_ERR_journal_write_err;
        } else {
                bch2_devlist_to_replicas(&replicas.e, BCH_DATA_journal,
@@ -1637,8 +1635,20 @@ static CLOSURE_CALLBACK(journal_write_done)
                err = bch2_mark_replicas(c, &replicas.e);
        }
 
-       if (err)
-               bch2_fatal_error(c);
+       if (err && !bch2_journal_error(j)) {
+               struct printbuf buf = PRINTBUF;
+               bch2_log_msg_start(c, &buf);
+
+               if (err == -BCH_ERR_journal_write_err)
+                       prt_printf(&buf, "unable to write journal to sufficient devices");
+               else
+                       prt_printf(&buf, "journal write error marking replicas: %s", bch2_err_str(err));
+
+               bch2_fs_emergency_read_only2(c, &buf);
+
+               bch2_print_str(c, KERN_ERR, buf.buf);
+               printbuf_exit(&buf);
+       }
 
        closure_debug_destroy(cl);
 
index b4242ad4899d5edf84faf4582aa41a9b0c405456..1895a6b13001f389a0edcb2496a68ef3b82ef462 100644 (file)
@@ -1108,8 +1108,17 @@ out:
        return ret;
 err:
 fsck_err:
-       bch2_fs_emergency_read_only(c);
-       goto out;
+       {
+               struct printbuf buf = PRINTBUF;
+               bch2_log_msg_start(c, &buf);
+
+               prt_printf(&buf, "error in recovery: %s", bch2_err_str(ret));
+               bch2_fs_emergency_read_only2(c, &buf);
+
+               bch2_print_str(c, KERN_ERR, buf.buf);
+               printbuf_exit(&buf);
+       }
+       return ret;
 }
 
 int bch2_fs_initialize(struct bch_fs *c)
index 8125c6804bd543c3d1a1ae6877fafba4b2d149c2..c46b2b2ebab14729959b37e10dd2d667dd3822a5 100644 (file)
@@ -438,6 +438,30 @@ bool bch2_fs_emergency_read_only(struct bch_fs *c)
        return ret;
 }
 
+static bool __bch2_fs_emergency_read_only2(struct bch_fs *c, struct printbuf *out,
+                                          bool locked)
+{
+       bool ret = !test_and_set_bit(BCH_FS_emergency_ro, &c->flags);
+
+       if (!locked)
+               bch2_journal_halt(&c->journal);
+       else
+               bch2_journal_halt_locked(&c->journal);
+       bch2_fs_read_only_async(c);
+       wake_up(&bch2_read_only_wait);
+
+       if (ret)
+               prt_printf(out, "emergency read only at seq %llu\n",
+                          journal_cur_seq(&c->journal));
+
+       return ret;
+}
+
+bool bch2_fs_emergency_read_only2(struct bch_fs *c, struct printbuf *out)
+{
+       return __bch2_fs_emergency_read_only2(c, out, false);
+}
+
 bool bch2_fs_emergency_read_only_locked(struct bch_fs *c)
 {
        bool ret = !test_and_set_bit(BCH_FS_emergency_ro, &c->flags);
@@ -2252,20 +2276,32 @@ static void bch2_fs_bdev_mark_dead(struct block_device *bdev, bool surprise)
        if (!ca)
                goto unlock;
 
-       if (bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_failed, BCH_FORCE_IF_DEGRADED)) {
+       bool dev = bch2_dev_state_allowed(c, ca,
+                                         BCH_MEMBER_STATE_failed,
+                                         BCH_FORCE_IF_DEGRADED);
+
+       if (!dev && sb) {
+               if (!surprise)
+                       sync_filesystem(sb);
+               shrink_dcache_sb(sb);
+               evict_inodes(sb);
+       }
+
+       struct printbuf buf = PRINTBUF;
+       __bch2_log_msg_start(ca->name, &buf);
+
+       prt_printf(&buf, "offline from block layer");
+
+       if (dev) {
                __bch2_dev_offline(c, ca);
        } else {
-               if (sb) {
-                       if (!surprise)
-                               sync_filesystem(sb);
-                       shrink_dcache_sb(sb);
-                       evict_inodes(sb);
-               }
-
                bch2_journal_flush(&c->journal);
-               bch2_fs_emergency_read_only(c);
+               bch2_fs_emergency_read_only2(c, &buf);
        }
 
+       bch2_print_str(c, KERN_ERR, buf.buf);
+       printbuf_exit(&buf);
+
        bch2_dev_put(ca);
 unlock:
        if (sb)
index be75603fefe90bb0e2b70cfc3e727aa171468706..dc52f06cb2b9ee2c3d58b0877b93b67548e5e1ac 100644 (file)
@@ -32,6 +32,8 @@ int bch2_dev_resize(struct bch_fs *, struct bch_dev *, u64);
 struct bch_dev *bch2_dev_lookup(struct bch_fs *, const char *);
 
 bool bch2_fs_emergency_read_only(struct bch_fs *);
+bool bch2_fs_emergency_read_only2(struct bch_fs *, struct printbuf *);
+
 bool bch2_fs_emergency_read_only_locked(struct bch_fs *);
 void bch2_fs_read_only(struct bch_fs *);