]> www.infradead.org Git - nvme.git/commitdiff
bcachefs: Add ability to redirect log output
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 5 Dec 2023 01:15:23 +0000 (20:15 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 1 Jan 2024 16:47:40 +0000 (11:47 -0500)
Upcoming patches are going to add two new ioctls for running fsck in the
kernel, but pretending that we're running our normal userspace fsck.

This patch adds some plumbing for redirecting our normal log messages
away from the dmesg log to a thread_with_file file descriptor - via a
struct log_output, which will be consumed by the fsck f_op's read method.

The new ioctls will allow for running fsck in the kernel against an
offline filesystem (without mounting it), and an online filesystem. For
an offline filesystem we need a way to pass in a pointer to the
log_output, which is done via a new hidden opts.h option.

For online fsck, we can set c->output directly, but only want to
redirect log messages from the thread running fsck - hence the new
c->output_filter method.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs.h
fs/bcachefs/opts.h
fs/bcachefs/recovery.c
fs/bcachefs/super.c

index ca7c9dea83dd576568e237c18c46b05dc851108b..3c9d24e42ff7ff307eaacc711c89fbb2a6ef08d2 100644 (file)
@@ -264,36 +264,55 @@ do {                                                                      \
 
 #define bch2_fmt(_c, fmt)              bch2_log_msg(_c, fmt "\n")
 
+__printf(2, 3)
+void __bch2_print(struct bch_fs *c, const char *fmt, ...);
+
+#define maybe_dev_to_fs(_c)    _Generic((_c),                          \
+       struct bch_dev *:       ((struct bch_dev *) (_c))->fs,          \
+       struct bch_fs *:        (_c))
+
+#define bch2_print(_c, ...) __bch2_print(maybe_dev_to_fs(_c), __VA_ARGS__)
+
+#define bch2_print_ratelimited(_c, ...)                                        \
+do {                                                                   \
+       static DEFINE_RATELIMIT_STATE(_rs,                              \
+                                     DEFAULT_RATELIMIT_INTERVAL,       \
+                                     DEFAULT_RATELIMIT_BURST);         \
+                                                                       \
+       if (__ratelimit(&_rs))                                          \
+               bch2_print(_c, __VA_ARGS__);                            \
+} while (0)
+
 #define bch_info(c, fmt, ...) \
-       printk(KERN_INFO bch2_fmt(c, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_INFO bch2_fmt(c, fmt), ##__VA_ARGS__)
 #define bch_notice(c, fmt, ...) \
-       printk(KERN_NOTICE bch2_fmt(c, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_NOTICE bch2_fmt(c, fmt), ##__VA_ARGS__)
 #define bch_warn(c, fmt, ...) \
-       printk(KERN_WARNING bch2_fmt(c, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_WARNING bch2_fmt(c, fmt), ##__VA_ARGS__)
 #define bch_warn_ratelimited(c, fmt, ...) \
-       printk_ratelimited(KERN_WARNING bch2_fmt(c, fmt), ##__VA_ARGS__)
+       bch2_print_ratelimited(c, KERN_WARNING bch2_fmt(c, fmt), ##__VA_ARGS__)
 
 #define bch_err(c, fmt, ...) \
-       printk(KERN_ERR bch2_fmt(c, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_ERR bch2_fmt(c, fmt), ##__VA_ARGS__)
 #define bch_err_dev(ca, fmt, ...) \
-       printk(KERN_ERR bch2_fmt_dev(ca, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_ERR bch2_fmt_dev(ca, fmt), ##__VA_ARGS__)
 #define bch_err_dev_offset(ca, _offset, fmt, ...) \
-       printk(KERN_ERR bch2_fmt_dev_offset(ca, _offset, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_ERR bch2_fmt_dev_offset(ca, _offset, fmt), ##__VA_ARGS__)
 #define bch_err_inum(c, _inum, fmt, ...) \
-       printk(KERN_ERR bch2_fmt_inum(c, _inum, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_ERR bch2_fmt_inum(c, _inum, fmt), ##__VA_ARGS__)
 #define bch_err_inum_offset(c, _inum, _offset, fmt, ...) \
-       printk(KERN_ERR bch2_fmt_inum_offset(c, _inum, _offset, fmt), ##__VA_ARGS__)
+       bch2_print(c, KERN_ERR bch2_fmt_inum_offset(c, _inum, _offset, fmt), ##__VA_ARGS__)
 
 #define bch_err_ratelimited(c, fmt, ...) \
-       printk_ratelimited(KERN_ERR bch2_fmt(c, fmt), ##__VA_ARGS__)
+       bch2_print_ratelimited(c, KERN_ERR bch2_fmt(c, fmt), ##__VA_ARGS__)
 #define bch_err_dev_ratelimited(ca, fmt, ...) \
-       printk_ratelimited(KERN_ERR bch2_fmt_dev(ca, fmt), ##__VA_ARGS__)
+       bch2_print_ratelimited(ca, KERN_ERR bch2_fmt_dev(ca, fmt), ##__VA_ARGS__)
 #define bch_err_dev_offset_ratelimited(ca, _offset, fmt, ...) \
-       printk_ratelimited(KERN_ERR bch2_fmt_dev_offset(ca, _offset, fmt), ##__VA_ARGS__)
+       bch2_print_ratelimited(ca, KERN_ERR bch2_fmt_dev_offset(ca, _offset, fmt), ##__VA_ARGS__)
 #define bch_err_inum_ratelimited(c, _inum, fmt, ...) \
-       printk_ratelimited(KERN_ERR bch2_fmt_inum(c, _inum, fmt), ##__VA_ARGS__)
+       bch2_print_ratelimited(c, KERN_ERR bch2_fmt_inum(c, _inum, fmt), ##__VA_ARGS__)
 #define bch_err_inum_offset_ratelimited(c, _inum, _offset, fmt, ...) \
-       printk_ratelimited(KERN_ERR bch2_fmt_inum_offset(c, _inum, _offset, fmt), ##__VA_ARGS__)
+       bch2_print_ratelimited(c, KERN_ERR bch2_fmt_inum_offset(c, _inum, _offset, fmt), ##__VA_ARGS__)
 
 #define bch_err_fn(_c, _ret)                                           \
 do {                                                                   \
@@ -446,6 +465,12 @@ enum bch_time_stats {
 
 struct btree;
 
+struct log_output {
+       spinlock_t              lock;
+       wait_queue_head_t       wait;
+       struct printbuf         buf;
+};
+
 enum gc_phase {
        GC_PHASE_NOT_RUNNING,
        GC_PHASE_START,
@@ -700,6 +725,8 @@ struct bch_fs {
        struct super_block      *vfs_sb;
        dev_t                   dev;
        char                    name[40];
+       struct log_output       *output;
+       struct task_struct      *output_filter;
 
        /* ro/rw, add/remove/resize devices: */
        struct rw_semaphore     state_lock;
index 8526f177450a56900c907a2e4cba3950fe5f9e00..7f9e3001bf55fb1c876107c4ea665e68eaf35dd5 100644 (file)
@@ -419,6 +419,11 @@ enum fsck_err_opts {
          OPT_BOOL(),                                                   \
          BCH2_NO_SB_OPT,               false,                          \
          NULL,         "Allocate the buckets_nouse bitmap")            \
+       x(log_output,                   u64,                            \
+         0,                                                            \
+         OPT_UINT(0, S64_MAX),                                         \
+         BCH2_NO_SB_OPT,               false,                          \
+         NULL,         "Pointer to a struct log_output")               \
        x(project,                      u8,                             \
          OPT_INODE,                                                    \
          OPT_BOOL(),                                                   \
index fec74086c9c5ec5cca9e90e2da9689dbc2ac940c..b296a8fc2fdc695243a242a0589ddabd3c4a61fb 100644 (file)
@@ -690,13 +690,13 @@ static int bch2_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass)
                struct recovery_pass_fn *p = recovery_pass_fns + pass;
 
                if (!(p->when & PASS_SILENT))
-                       printk(KERN_INFO bch2_log_msg(c, "%s..."),
-                              bch2_recovery_passes[pass]);
+                       bch2_print(c, KERN_INFO bch2_log_msg(c, "%s..."),
+                                  bch2_recovery_passes[pass]);
                ret = p->fn(c);
                if (ret)
                        return ret;
                if (!(p->when & PASS_SILENT))
-                       printk(KERN_CONT " done\n");
+                       bch2_print(c, KERN_CONT " done\n");
 
                c->recovery_passes_complete |= BIT_ULL(pass);
        }
index 1ec66bb8a63f0367a14aa0837ffe8761737b4e12..83e5423fd00597c4e4dcf3050375206f6e16c118 100644 (file)
@@ -86,6 +86,32 @@ const char * const bch2_fs_flag_strs[] = {
        NULL
 };
 
+void __bch2_print(struct bch_fs *c, const char *fmt, ...)
+{
+       struct log_output *output = c->output;
+       va_list args;
+
+       if (c->output_filter && c->output_filter != current)
+               output = NULL;
+
+       va_start(args, fmt);
+       if (likely(!output)) {
+               vprintk(fmt, args);
+       } else {
+               unsigned long flags;
+
+               if (fmt[0] == KERN_SOH[0])
+                       fmt += 2;
+
+               spin_lock_irqsave(&output->lock, flags);
+               prt_vprintf(&output->buf, fmt, args);
+               spin_unlock_irqrestore(&output->lock, flags);
+
+               wake_up(&output->wait);
+       }
+       va_end(args);
+}
+
 #define KTYPE(type)                                                    \
 static const struct attribute_group type ## _group = {                 \
        .attrs = type ## _files                                         \
@@ -712,6 +738,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
                goto out;
        }
 
+       c->output = (void *)(unsigned long) opts.log_output;
+
        __module_get(THIS_MODULE);
 
        closure_init(&c->cl, NULL);