From nobody Wed Dec 17 08:03:42 2025 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C435D30FC27 for ; Tue, 2 Dec 2025 09:36:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764668204; cv=none; b=c4ctIopVE5ROHKmiSZscbJfgfm/TIN8BbnhsF8vOahD+f4O+J5WhYBO1cB+SqYTY7ckuSullPI3Azr13NBnLX8X3g6HL/7jD3t4be4mRwikr1MTHF/6eXpw1ir8iyFfXY9jqfQCubyZtKlh20spdt97QOBp4POgzolRFj5UFHXM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764668204; c=relaxed/simple; bh=E3WFtoply2CzMUaphUHrv1gLvYkS0mXOwwUjrnpBuSI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Aa4wXo9y9ywNfNk/+c3ccq4abODWJBjjtoVFLSjazYzJweSyEMKCVcBAO9Kl3E44m5NS/B5pg3JxG30tY9uM8PGlO3seUiGs73ZDCEKjDDkLq117s3GF87AnvMU+2l0Zsshd3e1fKCllI+j/gMo1tbp7lRbwvBVsbvhIHhqxYQ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Qzd8Y0dm; arc=none smtp.client-ip=209.85.221.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Qzd8Y0dm" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-42b2e448bd9so3346323f8f.1 for ; Tue, 02 Dec 2025 01:36:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1764668200; x=1765273000; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=QAg5QIJijBUD3GbQyblzpbn2Hvfi6z1+MDh+yJIOVlU=; b=Qzd8Y0dmYcTbJ7D+jOccc87IhGkLOHq08UOdPv448a6MqoYdQ1w5W7TIqqoIcK3KmM mFvCqF6Vmycocb0KZk0esoR+z4yxDgSLV4ikOKuxBdhjiefyqw06keNgyoLR1miZx5Vk nzHbohD4XVJtXoOxQIw2sR6AksofgfCUYHeGQit7qUv9+ZRy73R6oGMhiU/8GSHVndhV kfrzTrwzrKW0P7KNn5ZB/WiRUsPoEY/QlSH/GIZJM7k77IR63eHzzTADvMsxfBIxJKYw ePRvxU0LQWhjPUXnGXbCNkBzABrmc8QJsGoTD6Q+basadpnBekwq/VjBSP3cMQw/LQ8C BMcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764668200; x=1765273000; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=QAg5QIJijBUD3GbQyblzpbn2Hvfi6z1+MDh+yJIOVlU=; b=Y0RGx2L892QGS7v1OnNC04kXjprcKWUTNdEUF7KvJHSmX9EQeLG7kHFD3hjsnxamTk S8mrYm2TAVfpof6hNSK/Gn/imbZzYXM9K6yoh15/QmIsS+X9Qyk6uunfiAqqrGByt0Il Cz4uKq12K5ao6oWbEftQrJJeAOtp7VtUu2KX25w20EZYAwa9xGc9TAJ0axWxB0gy8zEY 1lPvoA8M/yfzv75BCs8XRzf7ZQyBempmFa80CFb5pkkpOIafFgt7KlLxSPpZl9L+fz68 CPvY3dwvswhanjfxOMmLSWQKXN0kwhkAu/VvfjstW24ZAilbTZRq2Mdmdctx+aZN9LVt FtLA== X-Forwarded-Encrypted: i=1; AJvYcCWzF9d1THNeUuUTvd2zx0+5xVJdCE4SmAsLoKEmEHnKYB8Utdm0hiWfEhxiu9L76zmjrn19ypLC1moQpbU=@vger.kernel.org X-Gm-Message-State: AOJu0YwIWXiW/ySuqUGXcp2AHK4QYALGbcKXVYsbHuqIX4dH7ftIA/Py kHfv9cYeJ1D9T432cVkmstQ7bJf3jGOm6gKI/UILge7Zr/+PCsulW0tT7niqUxf5XJGZWrLxlJA KJGr5kY7a6vCvgS+3+ZNYBg== X-Google-Smtp-Source: AGHT+IGutHkdtjV5abrsRXlyK81TEktEfKY8cPcmKDii9fEiZgd7lN+Pd6pb9PGmptrfFxClBPoZyp4uq7FkntZo X-Received: from wryt14.prod.google.com ([2002:a05:6000:1a4e:b0:42b:328d:1994]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:4308:b0:42b:5567:854b with SMTP id ffacd0b85a97d-42e0f356534mr27352277f8f.45.1764668200072; Tue, 02 Dec 2025 01:36:40 -0800 (PST) Date: Tue, 2 Dec 2025 09:36:02 +0000 In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20251202093623.2337860-1-vdonnefort@google.com> X-Mailer: git-send-email 2.52.0.107.ga0afd4fd5b-goog Message-ID: <20251202093623.2337860-10-vdonnefort@google.com> Subject: [PATCH v9 09/30] tracing: Add events to trace remotes From: Vincent Donnefort To: rostedt@goodmis.org, mhiramat@kernel.org, mathieu.desnoyers@efficios.com, linux-trace-kernel@vger.kernel.org, maz@kernel.org, oliver.upton@linux.dev, joey.gouly@arm.com, suzuki.poulose@arm.com, yuzenghui@huawei.com Cc: kvmarm@lists.linux.dev, linux-arm-kernel@lists.infradead.org, jstultz@google.com, qperret@google.com, will@kernel.org, aneesh.kumar@kernel.org, kernel-team@android.com, linux-kernel@vger.kernel.org, Vincent Donnefort Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" An event is predefined point in the writer code that allows to log data. Following the same scheme as kernel events, add remote events, described to user-space within the events/ tracefs directory found in the corresponding trace remote. Remote events are expected to be described during the trace remote registration. Add also a .enable_event callback for trace_remote to toggle the event logging, if supported. Signed-off-by: Vincent Donnefort diff --git a/include/linux/trace_remote.h b/include/linux/trace_remote.h index 15a579633123..456df837fc6b 100644 --- a/include/linux/trace_remote.h +++ b/include/linux/trace_remote.h @@ -5,6 +5,7 @@ =20 #include #include +#include =20 /** * struct trace_remote_callbacks - Callbacks used by Tracefs to control th= e remote @@ -24,6 +25,8 @@ * @reset: Called on `echo 0 > trace`. It is expected from the * remote to reset all ring-buffer pages. * new reader-page from the @cpu ring-buffer. + * @enable_event: Called on events/event_name/enable. It is expected from + * the remote to allow the writing event @id. */ struct trace_remote_callbacks { int (*init)(struct dentry *d, void *priv); @@ -32,6 +35,7 @@ struct trace_remote_callbacks { int (*enable_tracing)(bool enable, void *priv); int (*swap_reader_page)(unsigned int cpu, void *priv); int (*reset)(unsigned int cpu, void *priv); + int (*enable_event)(unsigned short id, bool enable, void *priv); }; =20 /** @@ -53,7 +57,8 @@ struct trace_remote_callbacks { * * Return: 0 on success, negative error code on failure. */ -int trace_remote_register(const char *name, struct trace_remote_callbacks = *cbs, void *priv); +int trace_remote_register(const char *name, struct trace_remote_callbacks = *cbs, void *priv, + struct remote_event *events, size_t nr_events); =20 /** * trace_remote_alloc_buffer() - Dynamically allocate a trace buffer diff --git a/include/linux/trace_remote_event.h b/include/linux/trace_remot= e_event.h new file mode 100644 index 000000000000..a4449008a075 --- /dev/null +++ b/include/linux/trace_remote_event.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_TRACE_REMOTE_EVENTS_H +#define _LINUX_TRACE_REMOTE_EVENTS_H + +struct trace_remote; +struct trace_event_fields; + +struct remote_event_hdr { + unsigned short id; +}; + +#define REMOTE_EVENT_NAME_MAX 30 +struct remote_event { + char name[REMOTE_EVENT_NAME_MAX]; + unsigned short id; + bool enabled; + struct trace_remote *remote; + struct trace_event_fields *fields; + char *print_fmt; + void (*print)(void *evt, struct trace_seq *seq); +}; +#endif diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c index 924e3f3ec6d2..8527804f2d22 100644 --- a/kernel/trace/trace_remote.c +++ b/kernel/trace/trace_remote.c @@ -33,6 +33,7 @@ struct trace_remote_iterator { struct ring_buffer_iter **rb_iters; struct ring_buffer_iter *rb_iter; }; + struct remote_event_hdr *evt; int cpu; int evt_cpu; loff_t pos; @@ -44,6 +45,10 @@ struct trace_remote { void *priv; struct trace_buffer *trace_buffer; struct trace_buffer_desc *trace_buffer_desc; + struct dentry *dentry; + struct eventfs_inode *eventfs; + struct remote_event *events; + unsigned long nr_events; unsigned long trace_buffer_size; struct ring_buffer_remote rb_remote; struct mutex lock; @@ -168,7 +173,8 @@ static void trace_remote_reset(struct trace_remote *rem= ote, int cpu) static ssize_t tracing_on_write(struct file *filp, const char __user *ubuf, size_t cnt, l= off_t *ppos) { - struct trace_remote *remote =3D filp->private_data; + struct seq_file *seq =3D filp->private_data; + struct trace_remote *remote =3D seq->private; unsigned long val; int ret; =20 @@ -197,7 +203,8 @@ DEFINE_SHOW_STORE_ATTRIBUTE(tracing_on); static ssize_t buffer_size_kb_write(struct file *filp, const char __user *= ubuf, size_t cnt, loff_t *ppos) { - struct trace_remote *remote =3D filp->private_data; + struct seq_file *seq =3D filp->private_data; + struct trace_remote *remote =3D seq->private; unsigned long val; int ret; =20 @@ -484,16 +491,19 @@ __peek_event(struct trace_remote_iterator *iter, int = cpu, u64 *ts, unsigned long static bool trace_remote_iter_read_event(struct trace_remote_iterator *ite= r) { struct trace_buffer *trace_buffer =3D iter->remote->trace_buffer; + struct ring_buffer_event *rb_evt; int cpu =3D iter->cpu; =20 if (cpu !=3D RING_BUFFER_ALL_CPUS) { if (ring_buffer_empty_cpu(trace_buffer, cpu)) return false; =20 - if (!__peek_event(iter, cpu, &iter->ts, &iter->lost_events)) + rb_evt =3D __peek_event(iter, cpu, &iter->ts, &iter->lost_events); + if (!rb_evt) return false; =20 iter->evt_cpu =3D cpu; + iter->evt =3D (struct remote_event_hdr *)ring_buffer_event_data(rb_evt); return true; } =20 @@ -505,7 +515,8 @@ static bool trace_remote_iter_read_event(struct trace_r= emote_iterator *iter) if (ring_buffer_empty_cpu(trace_buffer, cpu)) continue; =20 - if (!__peek_event(iter, cpu, &ts, &lost_events)) + rb_evt =3D __peek_event(iter, cpu, &ts, &lost_events); + if (!rb_evt) continue; =20 if (ts >=3D iter->ts) @@ -513,6 +524,7 @@ static bool trace_remote_iter_read_event(struct trace_r= emote_iterator *iter) =20 iter->ts =3D ts; iter->evt_cpu =3D cpu; + iter->evt =3D (struct remote_event_hdr *)ring_buffer_event_data(rb_evt); iter->lost_events =3D lost_events; } =20 @@ -533,8 +545,11 @@ static void trace_remote_iter_move(struct trace_remote= _iterator *iter) } } =20 +static struct remote_event *trace_remote_find_event(struct trace_remote *r= emote, unsigned short id); + static int trace_remote_iter_print_event(struct trace_remote_iterator *ite= r) { + struct remote_event *evt; unsigned long usecs_rem; u64 ts =3D iter->ts; =20 @@ -548,6 +563,12 @@ static int trace_remote_iter_print_event(struct trace_= remote_iterator *iter) trace_seq_printf(&iter->seq, "[%03d]\t%5llu.%06lu: ", iter->evt_cpu, ts, usecs_rem); =20 + evt =3D trace_remote_find_event(iter->remote, iter->evt->id); + if (!evt) + trace_seq_printf(&iter->seq, "UNKNOWN id=3D%d\n", iter->evt->id); + else + evt->print(iter->evt, &iter->seq); + return trace_seq_has_overflowed(&iter->seq) ? -EOVERFLOW : 0; } =20 @@ -821,6 +842,8 @@ static int trace_remote_init_tracefs(const char *name, = struct trace_remote *remo goto err; } =20 + remote->dentry =3D remote_d; + return 0; =20 err: @@ -834,7 +857,11 @@ static int trace_remote_init_tracefs(const char *name,= struct trace_remote *remo return -ENOMEM; } =20 -int trace_remote_register(const char *name, struct trace_remote_callbacks = *cbs, void *priv) +static int trace_remote_register_events(const char *remote_name, struct tr= ace_remote *remote, + struct remote_event *events, size_t nr_events); + +int trace_remote_register(const char *name, struct trace_remote_callbacks = *cbs, void *priv, + struct remote_event *events, size_t nr_events) { struct trace_remote *remote; int ret; @@ -855,6 +882,13 @@ int trace_remote_register(const char *name, struct tra= ce_remote_callbacks *cbs, return -ENOMEM; } =20 + ret =3D trace_remote_register_events(name, remote, events, nr_events); + if (ret) { + pr_err("Failed to register events for trace remote '%s' (%d)\n", + name, ret); + return ret; + } + ret =3D cbs->init ? cbs->init(remote->dentry, priv) : 0; if (ret) pr_err("Init failed for trace remote '%s' (%d)\n", name, ret); @@ -929,3 +963,220 @@ int trace_remote_alloc_buffer(struct trace_buffer_des= c *desc, size_t desc_size, return ret; } EXPORT_SYMBOL_GPL(trace_remote_alloc_buffer); + +static int +trace_remote_enable_event(struct trace_remote *remote, struct remote_event= *evt, bool enable) +{ + int ret; + + lockdep_assert_held(&remote->lock); + + if (evt->enabled =3D=3D enable) + return 0; + + ret =3D remote->cbs->enable_event(evt->id, enable, remote->priv); + if (ret) + return ret; + + evt->enabled =3D enable; + + return 0; +} + +static int remote_event_enable_show(struct seq_file *s, void *unused) +{ + struct remote_event *evt =3D s->private; + + seq_printf(s, "%d\n", evt->enabled); + + return 0; +} + +static ssize_t remote_event_enable_write(struct file *filp, const char __u= ser *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *seq =3D filp->private_data; + struct remote_event *evt =3D seq->private; + struct trace_remote *remote =3D evt->remote; + u8 enable; + int ret; + + ret =3D kstrtou8_from_user(ubuf, count, 10, &enable); + if (ret) + return ret; + + guard(mutex)(&remote->lock); + + ret =3D trace_remote_enable_event(remote, evt, enable); + if (ret) + return ret; + + return count; +} +DEFINE_SHOW_STORE_ATTRIBUTE(remote_event_enable); + +static int remote_event_id_show(struct seq_file *s, void *unused) +{ + struct remote_event *evt =3D s->private; + + seq_printf(s, "%d\n", evt->id); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(remote_event_id); + +static int remote_event_format_show(struct seq_file *s, void *unused) +{ + size_t offset =3D sizeof(struct remote_event_hdr); + struct remote_event *evt =3D s->private; + struct trace_event_fields *field; + + seq_printf(s, "name: %s\n", evt->name); + seq_printf(s, "ID: %d\n", evt->id); + seq_puts(s, + "format:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsign= ed:0;\n\n"); + + field =3D &evt->fields[0]; + while (field->name) { + seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%u;\tsigned:%d;\n", + field->type, field->name, offset, field->size, + field->is_signed); + offset +=3D field->size; + field++; + } + + if (field !=3D &evt->fields[0]) + seq_puts(s, "\n"); + + seq_printf(s, "print fmt: %s\n", evt->print_fmt); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(remote_event_format); + +static int remote_event_callback(const char *name, umode_t *mode, void **d= ata, + const struct file_operations **fops) +{ + if (!strcmp(name, "enable")) { + *mode =3D TRACEFS_MODE_WRITE; + *fops =3D &remote_event_enable_fops; + return 1; + } + + if (!strcmp(name, "id")) { + *mode =3D TRACEFS_MODE_READ; + *fops =3D &remote_event_id_fops; + return 1; + } + + if (!strcmp(name, "format")) { + *mode =3D TRACEFS_MODE_READ; + *fops =3D &remote_event_format_fops; + return 1; + } + + return 0; +} + +static int trace_remote_init_eventfs(const char *remote_name, struct trace= _remote *remote, + struct remote_event *evt) +{ + struct eventfs_inode *eventfs =3D remote->eventfs; + static struct eventfs_entry entries[] =3D { + { + .name =3D "enable", + .callback =3D remote_event_callback, + }, { + .name =3D "id", + .callback =3D remote_event_callback, + }, { + .name =3D "format", + .callback =3D remote_event_callback, + } + }; + bool eventfs_create =3D false; + + if (!eventfs) { + eventfs =3D eventfs_create_events_dir("events", remote->dentry, NULL, 0,= NULL); + if (IS_ERR(eventfs)) + return PTR_ERR(eventfs); + + /* + * Create similar hierarchy as local events even if a single system is s= upported at + * the moment + */ + eventfs =3D eventfs_create_dir(remote_name, eventfs, NULL, 0, NULL); + if (IS_ERR(eventfs)) + return PTR_ERR(eventfs); + + remote->eventfs =3D eventfs; + eventfs_create =3D true; + } + + eventfs =3D eventfs_create_dir(evt->name, eventfs, entries, ARRAY_SIZE(en= tries), evt); + if (IS_ERR(eventfs)) { + if (eventfs_create) { + eventfs_remove_events_dir(remote->eventfs); + remote->eventfs =3D NULL; + } + return PTR_ERR(eventfs); + } + + return 0; +} + +static int trace_remote_attach_events(struct trace_remote *remote, struct = remote_event *events, + size_t nr_events) +{ + int i; + + for (i =3D 0; i < nr_events; i++) { + struct remote_event *evt =3D &events[i]; + + if (evt->remote) + return -EEXIST; + + evt->remote =3D remote; + + /* We need events to be sorted for efficient lookup */ + if (i && evt->id <=3D events[i - 1].id) + return -EINVAL; + } + + remote->events =3D events; + remote->nr_events =3D nr_events; + + return 0; +} + +static int trace_remote_register_events(const char *remote_name, struct tr= ace_remote *remote, + struct remote_event *events, size_t nr_events) +{ + int i, ret; + + ret =3D trace_remote_attach_events(remote, events, nr_events); + if (ret) + return ret; + + for (i =3D 0; i < nr_events; i++) { + struct remote_event *evt =3D &events[i]; + + ret =3D trace_remote_init_eventfs(remote_name, remote, evt); + if (ret) + pr_warn("Failed to init eventfs for event '%s' (%d)", + evt->name, ret); + } + + return 0; +} + +static int __cmp_events(const void *id, const void *evt) +{ + return (long)id - ((struct remote_event *)evt)->id; +} + +static struct remote_event *trace_remote_find_event(struct trace_remote *r= emote, unsigned short id) +{ + return bsearch((const void *)(unsigned long)id, remote->events, remote->n= r_events, + sizeof(*remote->events), __cmp_events); +} --=20 2.52.0.107.ga0afd4fd5b-goog