When enabled, the printk tracefs file enables the redirection of all
events to dmesg. This is similar to tp_printk.

Signed-off-by: Vincent Donnefort <[email protected]>

diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index 21583fae1bd9..1bf0ba159c92 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -21,6 +21,7 @@
 enum tri_type {
        TRI_CONSUMING,
        TRI_NONCONSUMING,
+       TRI_PRINTK,
 };
 
 struct trace_remote_iterator {
@@ -42,6 +43,7 @@ struct trace_remote {
        void                            *priv;
        struct trace_buffer             *trace_buffer;
        struct trace_buffer_desc        *trace_buffer_desc;
+       struct trace_remote_iterator    *printk;
        struct dentry                   *dentry;
        struct eventfs_inode            *eventfs_root;
        struct eventfs_inode            *eventfs_subdir;
@@ -335,6 +337,8 @@ static int __alloc_ring_buffer_iter(struct 
trace_remote_iterator *iter, int cpu)
        return 0;
 }
 
+static void trace_remote_do_printk(struct trace_remote *remote);
+
 static void __poll_remote(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
@@ -342,6 +346,7 @@ static void __poll_remote(struct work_struct *work)
 
        remote = container_of(dwork, struct trace_remote, poll_work);
        ring_buffer_poll_remote(remote->trace_buffer, RING_BUFFER_ALL_CPUS);
+       trace_remote_do_printk(remote);
 
        schedule_delayed_work(dwork, msecs_to_jiffies(remote->poll_ms));
 }
@@ -351,6 +356,8 @@ static void trace_remote_inc_poll(struct trace_remote 
*remote)
        /* poll_cnt <= nr_readers, inherits its overflow protection */
        if (!remote->poll_cnt++) {
                ring_buffer_poll_remote(remote->trace_buffer, 
RING_BUFFER_ALL_CPUS);
+               trace_remote_do_printk(remote);
+
                schedule_delayed_work(&remote->poll_work, 
msecs_to_jiffies(remote->poll_ms));
        }
 }
@@ -393,6 +400,14 @@ static struct trace_remote_iterator
                trace_seq_init(&iter->seq);
 
                switch (type) {
+               case TRI_PRINTK:
+                       /* only one printk iter allowed */
+                       if (WARN_ON_ONCE(remote->printk)) {
+                               ret = -EBUSY;
+                               break;
+                       }
+                       smp_store_release(&remote->printk, iter);
+                       fallthrough;
                case TRI_CONSUMING:
                        trace_remote_inc_poll(remote);
                        break;
@@ -427,6 +442,11 @@ static void trace_remote_iter_free(struct 
trace_remote_iterator *iter)
        lockdep_assert_held(&remote->lock);
 
        switch (iter->type) {
+       case TRI_PRINTK:
+               WARN_ON_ONCE(remote->printk != iter);
+               smp_store_release(&remote->printk, NULL);
+               flush_delayed_work(&remote->poll_work);
+               fallthrough;
        case TRI_CONSUMING:
                trace_remote_dec_poll(remote);
                break;
@@ -504,6 +524,7 @@ __peek_event(struct trace_remote_iterator *iter, int cpu, 
u64 *ts, unsigned long
        struct ring_buffer_iter *rb_iter;
 
        switch (iter->type) {
+       case TRI_PRINTK:
        case TRI_CONSUMING:
                return ring_buffer_peek(iter->remote->trace_buffer, cpu, ts, 
lost_events);
        case TRI_NONCONSUMING:
@@ -571,6 +592,7 @@ static void trace_remote_iter_move(struct 
trace_remote_iterator *iter)
        struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
 
        switch (iter->type) {
+       case TRI_PRINTK:
        case TRI_CONSUMING:
                ring_buffer_consume(trace_buffer, iter->evt_cpu, NULL, NULL);
                break;
@@ -814,6 +836,80 @@ static const struct file_operations trace_fops = {
        .release        = trace_release,
 };
 
+static void trace_remote_do_printk(struct trace_remote *remote)
+{
+       struct trace_remote_iterator *iter = smp_load_acquire(&remote->printk);
+
+       if (!iter)
+               return;
+
+       trace_remote_iter_read_start(iter);
+
+       while (trace_remote_iter_read_event(iter)) {
+               trace_seq_init(&iter->seq);
+
+               trace_remote_iter_print_event(iter);
+               if (!pr_emerg("%s", iter->seq.buffer))
+                       break;
+
+               trace_remote_iter_move(iter);
+       }
+
+       trace_remote_iter_read_finished(iter);
+}
+
+static int trace_remote_enable_printk(struct trace_remote *remote, bool enable)
+{
+       struct trace_remote_iterator *iter = remote->printk;
+
+       lockdep_assert_held(&remote->lock);
+
+       if (enable == !!iter)
+               return 0;
+
+       if (enable) {
+               iter = trace_remote_iter(remote, RING_BUFFER_ALL_CPUS, 
TRI_PRINTK);
+               if (IS_ERR(iter))
+                       return PTR_ERR(iter);
+       } else {
+               trace_remote_iter_free(remote->printk);
+               /* trace_remote_iter_free has reset remote->printk */
+       }
+
+       return 0;
+}
+
+static ssize_t
+printk_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t 
*ppos)
+{
+       struct seq_file *seq = filp->private_data;
+       struct trace_remote *remote = seq->private;
+       bool val;
+       int ret;
+
+       ret = kstrtobool_from_user(ubuf, cnt, &val);
+       if (ret)
+               return ret;
+
+       guard(mutex)(&remote->lock);
+
+       ret = trace_remote_enable_printk(remote, val);
+       if (ret)
+               return ret;
+
+       return cnt;
+}
+
+static int printk_show(struct seq_file *s, void *unused)
+{
+       struct trace_remote *remote = s->private;
+
+       seq_printf(s, "%d\n", !!remote->printk);
+
+       return 0;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(printk);
+
 static struct dentry *tracefs_root;
 static DEFINE_MUTEX(tracefs_lock);
 static u64 tracefs_root_count;
@@ -858,6 +954,10 @@ static int trace_remote_init_tracefs(const char *name, 
struct trace_remote *remo
        if (!d)
                goto err;
 
+       d = trace_create_file("printk", TRACEFS_MODE_WRITE, remote_d, remote, 
&printk_fops);
+       if (!d)
+               goto err;
+
        percpu_d = tracefs_create_dir("per_cpu", remote_d);
        if (!percpu_d) {
                pr_err("Failed to create tracefs dir 
"TRACEFS_DIR"%s/per_cpu/\n", name);
-- 
2.54.0.1032.g2f8565e1d1-goog


Reply via email to