[PATCH 05/13] tracing/remotes: Add printk tracefs file
From: Vincent Donnefort
Date: Tue Jun 02 2026 - 13:20:00 EST
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 <vdonnefort@xxxxxxxxxx>
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