From nobody Sat Oct 4 03:07:02 2025 Received: from mail-wm1-f73.google.com (mail-wm1-f73.google.com [209.85.128.73]) (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 153472EB5B8 for ; Thu, 21 Aug 2025 08:14:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755764073; cv=none; b=UwZuo6iDBxXeP6gptOKXiuCbJvVrAzX93oh0GfjeCe3fc3GwEvm+YHVJNmVsplCmPZvyitbqXF8rfvw+Vae6gpQcm5j4ZVj3hhiRrLOGc1hXDWQNk/xoEe18ejpTZ4HdIeLkYgC272wgD3ua5sy5g/j9K+A3dAvZlKlFlwLZndM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755764073; c=relaxed/simple; bh=5+w0BR+W06Wn0JgcJC9Us0FypC/rTpbMEqbisGDqnVY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Drs2gr6S8T1Pu73SFZ7CaQ4B8oJVHtiov1HcwWQRu29BjTW3BCjVPOKbXpKrbNu9ePQMBpcGdScuhGmV0rz8GlP/ri7Ic9ztRWYx3iN5X6YfZi5hexkOZnpHuHy8djNTgpEkKOxTXds0APKCUW+bW8n81lFovOl4l0265CmXxe4= 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=qsinkaDB; arc=none smtp.client-ip=209.85.128.73 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="qsinkaDB" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-45a1b04f817so2963775e9.1 for ; Thu, 21 Aug 2025 01:14:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1755764069; x=1756368869; 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=W22EIU0wPmFpDoLsMyxYOVfGPptW7NH7wCZxoNxRvyE=; b=qsinkaDBP/h8VtHZSoIfL+zYLAJTibH2piRSVJk62qwCHM5lXwJBuZbeJusM1a9sbp 975w3f+2jf14Xzu+eC6INOQzucy+1D7+jkLi/+xLLuQ3lEbOpE53LS2V9/x5ubnBx18r O1bsXZyRxVw7nbGo+Zcm2SLFFtgr58DIXsDthqLokZbq7mUXAPuv5V+9LaUWyKS2REKe pYTrTdQQpgOxSXm7kvz7///Q0wjzSeTxxZTrJbu8zyCe9CY8W+R7B5TD4ewplRw+esDr FHAZSatUIdGEwV6RvMYMBK0l1a4ujigLhsiLdHWeC5Bv0O2nJAclg5kbbtLFTnntZ8Zt 39Kw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755764069; x=1756368869; 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=W22EIU0wPmFpDoLsMyxYOVfGPptW7NH7wCZxoNxRvyE=; b=AyVbK48kcyOKS9lBsHQApbSjFIHzfFuvg7jPe7DWQS9ewKZVEOucFPe1UlyIJlUI5s 6Mi0SxL3S1x3z7RgdfLyBd62NaRA5qZLneHVNSJ8jVloo6+8SbwYRoEcLGN+Fa2Etzf3 mm3M1oLFDPD2EhGXuWmSNj9g/44CQWv9wD9ajq6LApADNAjgsu/3+PGkz+E6Y5wEPXEt 8gwJ17Pa53K6UN1C1y4C6isVPuhhGQLMArIWU4FdV0+grIP8w5EP+i/BfYguIB0jPDYW 7J07R5HPF9DSWCnnPWOEZdmqespT+jzuXmPjk28qWXAfibSf5iIccG1b0uE7dZKA/YFg GmWA== X-Forwarded-Encrypted: i=1; AJvYcCVF1Oh98Qm/pFmAdoJhLdocK3q4Ypkix/W92lg8YjCHdoOTUJe89Fl0mkdehpqBA4MCrOn3aRPtll6poZ8=@vger.kernel.org X-Gm-Message-State: AOJu0YxZvAa/Cc/9vLj9+/X9Rfh9kSfH0qjrn7Ui8Rr/LehPv/tjTnwE YUYEQdresRZiW4gXZva0C9dJsxqGeTiAhZ03pnKk4xtzWnxhavpGWzp8HlMJkpWeXTUD4I0eM5c W4988vdq/DeG5NVZpBUg6iQ== X-Google-Smtp-Source: AGHT+IGI2PiIkbSjwFuAaWOED7yQoO70q9rCSdloyFzMisfBtQbkBFdm8+ayz44OpgWngOd+05LdDZJ9I7+dIhEE X-Received: from wmqa19.prod.google.com ([2002:a05:600c:3493:b0:459:dbaa:93a6]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:1d22:b0:43c:fe5e:f040 with SMTP id 5b1f17b1804b1-45b4fd1fc01mr922155e9.23.1755764069522; Thu, 21 Aug 2025 01:14:29 -0700 (PDT) Date: Thu, 21 Aug 2025 09:13:54 +0100 In-Reply-To: <20250821081412.1008261-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: <20250821081412.1008261-1-vdonnefort@google.com> X-Mailer: git-send-email 2.51.0.rc2.233.g662b1ed5c5-goog Message-ID: <20250821081412.1008261-7-vdonnefort@google.com> Subject: [PATCH v6 06/24] 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 82d26d97a536..4cf8efa83578 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 { int (*init)(struct dentry *d, void *priv); @@ -14,9 +15,11 @@ 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 -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); int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t size, const struct cpumask *cpumask); void trace_remote_free_buffer(struct trace_buffer_desc *desc); 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 8f8eb1f1e889..822cdd76e334 100644 --- a/kernel/trace/trace_remote.c +++ b/kernel/trace/trace_remote.c @@ -24,6 +24,7 @@ struct trace_remote_iterator { struct delayed_work poll_work; unsigned long lost_events; u64 ts; + struct remote_event_hdr *evt; int cpu; int evt_cpu; }; @@ -33,6 +34,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; @@ -155,7 +160,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 @@ -184,7 +190,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 @@ -265,16 +272,19 @@ static struct trace_remote_iterator *trace_remote_ite= r(struct trace_remote *remo static bool trace_remote_iter_next(struct trace_remote_iterator *iter) { 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 (!ring_buffer_peek(trace_buffer, cpu, &iter->ts, &iter->lost_events)) + rb_evt =3D ring_buffer_peek(trace_buffer, cpu, &iter->ts, &iter->lost_ev= ents); + if (!rb_evt) return false; =20 iter->evt_cpu =3D cpu; + iter->evt =3D (struct remote_event_hdr *)&rb_evt->array[1]; return true; } =20 @@ -286,7 +296,8 @@ static bool trace_remote_iter_next(struct trace_remote_= iterator *iter) if (ring_buffer_empty_cpu(trace_buffer, cpu)) continue; =20 - if (!ring_buffer_peek(trace_buffer, cpu, &ts, &lost_events)) + rb_evt =3D ring_buffer_peek(trace_buffer, cpu, &ts, &lost_events); + if (!rb_evt) continue; =20 if (ts >=3D iter->ts) @@ -294,14 +305,18 @@ static bool trace_remote_iter_next(struct trace_remot= e_iterator *iter) =20 iter->ts =3D ts; iter->evt_cpu =3D cpu; + iter->evt =3D (struct remote_event_hdr *)&rb_evt->array[1]; iter->lost_events =3D lost_events; } =20 return iter->ts !=3D U64_MAX; } =20 +static struct remote_event *trace_remote_find_event(struct trace_remote *r= emote, unsigned short id); + static int trace_remote_iter_print(struct trace_remote_iterator *iter) { + struct remote_event *evt; unsigned long usecs_rem; u64 ts =3D iter->ts; =20 @@ -315,6 +330,12 @@ static int trace_remote_iter_print(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 @@ -466,6 +487,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: @@ -479,7 +502,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; @@ -499,6 +526,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); @@ -561,3 +595,220 @@ int trace_remote_alloc_buffer(struct trace_buffer_des= c *desc, size_t size, trace_remote_free_buffer(desc); return -ENOMEM; } + +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_id_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.51.0.rc2.233.g662b1ed5c5-goog