From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1BC683D9533 for ; Mon, 31 Aug 2026 09:07:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167228; cv=none; b=YdGxCgRugSg6JdEYHmYxTB+QMUsrtG3JjuuXXE+Rn1xWCq1dysDdq1wq3FTH+j+39JG7y2l/Wunje8d1e+CTntBOvXMbMa4+cTyqnsp+WcrcdSBUOqoHcDpYw0lcpc1PwclEgbJoUGlHxVrSzdxp91DuS9jhNDccJEQle0ptj40= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167228; c=relaxed/simple; bh=j9Bk+0pj2/24u8T6/SP13Tt6ikszrpnpvXPCcD/6MLU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ajkUn6/j8eNXTzwFozViY7cUwFD6kE9DeQvKRIi3ud1De9y8AvzPRbzAx4VpzQP6z1CoLqciTnyHcmPqbu+teB0CsGVhWAR49AElpnrsa1XHQgNSbLIii4/f0g52pnzpVpb51CrxZcBWeV8Dl/xTdyBi3aG1Z7KBGnDXjdl+f/k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=h6Luy7Ua; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="h6Luy7Ua" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167224; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7jsHCsFIe83xcZRq1DwfLWv9aF61ZEwjfkBd6QeliCQ=; b=h6Luy7UaEddGIgkEHOhalPJVkAu7s8+UH1jwwB/JnCmDN7gX1En6u2rECb3btrgOODKb9v DnNpzj2nYWUSPeVQ7mKfHYprsiBZC4v1wxG0uOgS7N4JtACRjXlQu7yfm22wY1h96VZPgB kCDWb4Dim6OHZ0Xxmkg9mo/55mzKvXs= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-262-3GBh1lUkPE2U7wQ8A-ui3Q-1; Mon, 31 Aug 2026 05:07:00 -0400 X-MC-Unique: 3GBh1lUkPE2U7wQ8A-ui3Q-1 X-Mimecast-MFC-AGG-ID: 3GBh1lUkPE2U7wQ8A-ui3Q_1788167219 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DB240182E6B4; Mon, 31 Aug 2026 09:06:58 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C234C18005BB; Mon, 31 Aug 2026 09:06:53 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Masami Hiramatsu , Ingo Molnar , Peter Zijlstra Cc: Nam Cao , K Prateek Nayak , Gabriele Monaco , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 01/20] sched: Add task enqueue/dequeue trace points Date: Mon, 31 Aug 2026 11:05:05 +0200 Message-ID: <20260831090524.106845-2-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" From: Nam Cao Add trace points into enqueue_task() and dequeue_task(). Signed-off-by: Nam Cao Suggested-by: Peter Zijlstra Reviewed-by: K Prateek Nayak Co-developed-by: Gabriele Monaco Signed-off-by: Gabriele Monaco --- include/trace/events/sched.h | 8 ++++++++ kernel/sched/core.c | 12 +++++++++++- kernel/sched/sched.h | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 535860581f15..d6e41edc25d2 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -896,6 +896,14 @@ DECLARE_TRACE(sched_set_need_resched, TP_PROTO(struct task_struct *tsk, int cpu, int tif), TP_ARGS(tsk, cpu, tif)); =20 +DECLARE_TRACE(sched_enqueue, + TP_PROTO(struct task_struct *tsk, int cpu), + TP_ARGS(tsk, cpu)); + +DECLARE_TRACE(sched_dequeue, + TP_PROTO(struct task_struct *tsk, int cpu), + TP_ARGS(tsk, cpu)); + #define DL_OTHER 0 #define DL_TASK 1 #define DL_SERVER_FAIR 2 diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f78275192036..8561ca324943 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -121,6 +121,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_compute_energy_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_entry_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_exit_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_set_need_resched_tp); +EXPORT_TRACEPOINT_SYMBOL_GPL(sched_enqueue_tp); +EXPORT_TRACEPOINT_SYMBOL_GPL(sched_dequeue_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_dl_throttle_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_dl_replenish_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_dl_update_tp); @@ -2181,6 +2183,9 @@ unsigned long get_wchan(struct task_struct *p) =20 void enqueue_task(struct rq *rq, struct task_struct *p, int flags) { + if (trace_sched_enqueue_tp_enabled() && !(flags & ENQUEUE_DELAYED)) + trace_sched_enqueue_tp(p, cpu_of(rq)); + if (!(flags & ENQUEUE_NOCLOCK)) update_rq_clock(rq); =20 @@ -2207,6 +2212,8 @@ void enqueue_task(struct rq *rq, struct task_struct *= p, int flags) */ inline bool dequeue_task(struct rq *rq, struct task_struct *p, int flags) { + bool ret; + if (sched_core_enabled(rq)) sched_core_dequeue(rq, p, flags); =20 @@ -2223,7 +2230,10 @@ inline bool dequeue_task(struct rq *rq, struct task_= struct *p, int flags) * and mark the task ->sched_delayed. */ uclamp_rq_dec(rq, p); - return p->sched_class->dequeue_task(rq, p, flags); + ret =3D p->sched_class->dequeue_task(rq, p, flags); + if (trace_sched_dequeue_tp_enabled() && !(flags & DEQUEUE_SLEEP)) + trace_sched_dequeue_tp(p, cpu_of(rq)); + return ret; } =20 void activate_task(struct rq *rq, struct task_struct *p, int flags) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index e656c7059bf8..a2cb06beafe6 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -3070,6 +3070,8 @@ static inline void sub_nr_running(struct rq *rq, unsi= gned count) =20 static inline void __block_task(struct rq *rq, struct task_struct *p) { + trace_sched_dequeue_tp(p, cpu_of(rq)); + if (p->sched_contributes_to_load) rq->nr_uninterruptible++; =20 --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 850BD3CE0B4 for ; Mon, 31 Aug 2026 09:07:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167229; cv=none; b=KKD7iX44lkI4wHnTYMZIcKSVkarsviniDV347IxCUuqTwNkdN5OTtI7MnzDmXXahKvnyhKKOGxDhysj8N3igS4qMg/5HhqR/Sqxi/ir354FJeQOv3L7APNKSIzo2DH3XCM0rruIAf9WR7eRXbBs77QPpsb4EpGtVUYUPZ3MX7Fg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167229; c=relaxed/simple; bh=3DM/K98fffruEH8/09LX1Unl1VL6OtdvW7P6hrxuI0s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z8CNpYc6ZshWsvwje244zmyy0F1CAxXWy2es3R8WxEOQBBhc0CVQtdjAcDr7bTpmDlAY2lBDkaesBBfCVaCHwa06UameG9wdzVwt6koopk4d9s8p+Y+elyVARlNzFHaF9CetJsQRgQ6B2pvX7qlOUE/RNgOpj9sRtw+UAn4n/rA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=bHbPwbHq; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="bHbPwbHq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167226; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=x6xpONabfnSBWbWSB7Bl4iKA12vAnmh9pV4xx/IOXqI=; b=bHbPwbHqpBbgDtW4op9NKaOavakrrMAfNo3tY4FNLmdMRnrqA4IRf1WQlkkUpBw5rQlIhV LXdHEMM+Ux64YSgu3gSjuFLMEzizXD2mg0MbvUfWQ9bRP1VT3l1U4yVoEhKtPXalN48Jri k/MoWZVzuWNarmKQjDcpJn1/4i1hu9M= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-436-3aVp4fTkMX6317d2y747XQ-1; Mon, 31 Aug 2026 05:07:04 -0400 X-MC-Unique: 3aVp4fTkMX6317d2y747XQ-1 X-Mimecast-MFC-AGG-ID: 3aVp4fTkMX6317d2y747XQ_1788167223 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 215471944B23; Mon, 31 Aug 2026 09:07:03 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C45E118005BB; Mon, 31 Aug 2026 09:06:59 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 02/20] tools/rv: Skip empty pid error in selftest if command failed Date: Mon, 31 Aug 2026 11:05:06 +0200 Message-ID: <20260831090524.106845-3-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Some rv userspace selftests rely on the pid of the rv process to match with the output and fail prematurely in case the pid was not found. If the rv process failed, however, it's likely it will terminate before catching the pid, and the test reports empty pid ignoring the error that caused the process to fail. Report empty pid only when the rv process succeeds (exit code not what was expected) and continue showing exit code and output otherwise. Signed-off-by: Gabriele Monaco --- tools/verification/tests/engine.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/verification/tests/engine.sh b/tools/verification/tests/= engine.sh index cfdf2180aad8..4dad43b0b822 100644 --- a/tools/verification/tests/engine.sh +++ b/tools/verification/tests/engine.sh @@ -60,8 +60,9 @@ _check() { failbuf=3D'' fail=3D0 =20 - # Suppress any other error if a needed pid is empty - if [ -z "$pid" ] && grep -q "\$pid" <<< "$patterns"; then + # Suppress any other error if a needed pid is empty and there was no othe= r error + if [ -z "$pid" ] && grep -q "\$pid" <<< "$patterns" \ + && [ $exitcode -eq "$expected_exitcode" ]; then result=3D'' failure "# Empty pid for $command" return 1 --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 35C633DA5DA for ; Mon, 31 Aug 2026 09:07:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167234; cv=none; b=dHTlPNtXujqe8fv6hm3pB5b7f+bmXIUNGIM2zoUosR3o43N6hEd3cEj9NbTDzGm1OxieK73zAKzNuY9DLy3v+9RnZJGXiTCfx0xiTHMhOcly20UmoPqTuSzgyjQKGHN2bXBklc/zpDfYlIpbkheJ9exAwKU28NtPS5ipPwFzYKk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167234; c=relaxed/simple; bh=xN80Pfs67HCbw+oDmc7ZViSyGz9ljql1b1gK0ht12no=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qxVYDp2h9NmTZB8QMX8ay8ZnOlNC6tfGozhCnEiXHYjYxPK/lJLWxE+N1LmlotBVikWlYnDtscPcUQf/ifY6h2fJKJytuSlHkXGtR3oT0trMeYZHapt012wdOafAUHq5NRCzR12w1KI8NZwzBGyAHxjjMZVarCqETBMf+oGFYS4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=belE5inQ; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="belE5inQ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167232; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=D9nODF3ao4BoTMuSTnZHD2rQJuc0s627BBlq9bQmlc8=; b=belE5inQYDcK7sbL2XPRJkb2jgR6SAztWpyqVTKXtRWStMIeYovdTYMHBPskBuWUn4Dagz XXQ1DhWx/GGMYNHsrNshEUL8pIKUBsxrkaZfKoPzCC+CjLlHWQ45Sn13ghxT6sVWSVvW3A J4d7PJyt7VZJ4Il8Lc3edYbrvp3ny/Q= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-458-XgWx3pW2NR2sPHVbt1Fasg-1; Mon, 31 Aug 2026 05:07:08 -0400 X-MC-Unique: XgWx3pW2NR2sPHVbt1Fasg-1 X-Mimecast-MFC-AGG-ID: XgWx3pW2NR2sPHVbt1Fasg_1788167226 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D2D671977536; Mon, 31 Aug 2026 09:07:06 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EE602180034F; Mon, 31 Aug 2026 09:07:03 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 03/20] rv: Refactor da_trace() functions to get strings internally Date: Mon, 31 Aug 2026 11:05:07 +0200 Message-ID: <20260831090524.106845-4-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" The da_trace_event() and da_trace_error() functions are currently called with strings and the callers are converting the state/event enums to the corresponding string representation. This is unnecessary and is problematic if an alternative implementation is needed (e.g. BPF without using strings). Change the functions to accept enums and pass the string representations to the tracepoints only internally. Signed-off-by: Gabriele Monaco --- include/rv/da_monitor.h | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h index 6fc5ef8142ac..7f0bdfd7cce3 100644 --- a/include/rv/da_monitor.h +++ b/include/rv/da_monitor.h @@ -633,19 +633,22 @@ static inline void da_monitor_destroy(void) */ =20 static inline void da_trace_event(struct da_monitor *da_mon, - char *curr_state, char *event, - char *next_state, bool is_final, + enum states curr_state, enum events event, + enum states next_state, da_id_type id) { - CONCATENATE(trace_event_, MONITOR_NAME)(curr_state, event, next_state, - is_final); + CONCATENATE(trace_event_, MONITOR_NAME)(model_get_state_name(curr_state), + model_get_event_name(event), + model_get_state_name(next_state), + model_is_final_state(next_state)); } =20 static inline void da_trace_error(struct da_monitor *da_mon, - char *curr_state, char *event, + enum states curr_state, enum events event, da_id_type id) { - CONCATENATE(trace_error_, MONITOR_NAME)(curr_state, event); + CONCATENATE(trace_error_, MONITOR_NAME)(model_get_state_name(curr_state), + model_get_event_name(event)); } =20 /* @@ -662,19 +665,24 @@ static inline da_id_type da_get_id(struct da_monitor = *da_mon) */ =20 static inline void da_trace_event(struct da_monitor *da_mon, - char *curr_state, char *event, - char *next_state, bool is_final, + enum states curr_state, enum events event, + enum states next_state, da_id_type id) { - CONCATENATE(trace_event_, MONITOR_NAME)(id, curr_state, event, - next_state, is_final); + CONCATENATE(trace_event_, MONITOR_NAME)(id, + model_get_state_name(curr_state), + model_get_event_name(event), + model_get_state_name(next_state), + model_is_final_state(next_state)); } =20 static inline void da_trace_error(struct da_monitor *da_mon, - char *curr_state, char *event, + enum states curr_state, enum events event, da_id_type id) { - CONCATENATE(trace_error_, MONITOR_NAME)(id, curr_state, event); + CONCATENATE(trace_error_, MONITOR_NAME)(id, + model_get_state_name(curr_state), + model_get_event_name(event)); } #endif /* RV_MON_TYPE */ =20 @@ -695,17 +703,13 @@ static inline bool da_event(struct da_monitor *da_mon= , enum events event, da_id_ next_state =3D model_get_next_state(curr_state, event); if (next_state =3D=3D INVALID_STATE) { react(curr_state, event); - da_trace_error(da_mon, model_get_state_name(curr_state), - model_get_event_name(event), id); + da_trace_error(da_mon, curr_state, event, id); return false; } if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) { if (!da_monitor_event_hook(da_mon, curr_state, event, next_state, id)) return false; - da_trace_event(da_mon, model_get_state_name(curr_state), - model_get_event_name(event), - model_get_state_name(next_state), - model_is_final_state(next_state), id); + da_trace_event(da_mon, curr_state, event, next_state, id); return true; } } --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AC7C73DA5DB for ; Mon, 31 Aug 2026 09:07:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167242; cv=none; b=CbVrAg4gf6WT+A6qnzPoERdAtDb616gUFKTogtGBBSJ9Akf9NdSA2UZapTmCbzEG4O6EFkSKpOHe7JbURlhU8canG5QXIpYIIJnqVb5Q1kvYfQUUnNHLEOyokuHXNVDIFljqMmwqe8XVrhp80rOrIi2a//l6OGEnT2mDukS9eaU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167242; c=relaxed/simple; bh=sR4VZB6nBWpqoyNmrzumziJWaNPWT5Ta+6UmJ+pF3Pg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Bxi7okjFe8rCQ0FQpx+8etKNuvbFwtWUwfVBY6T+trG5XewqzyENcooya7TXr2MpKllO+8GQo4kI1IzZpsdzd5/4G5i0fx9NOwkDkeKEOBVVGbvj28G31jjYGCaBnmgCnXsCXmTKkVwYz5yi7FXkADrzltffBpcuhzF0nkW37Jo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=dLiYwJDU; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="dLiYwJDU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167238; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=d/qS+nPc8j5i0RQhS+DSJfHNaI4k+rZzA7++z5urrbw=; b=dLiYwJDUAIclQSauT8/eG3JVgCHCcUuwFlZg7CYh6Fb/V/4J2AXZQ7QCfU4RNm1U28E+PK Zq8DKbweTuedMt54ZTqFHG7v0eAkMTtJkRyJ2OHDO/fCnXU0PwQgMYUAHs34we3LPPzs+W SrM2L3J87/VsNmme2ufSjy8Ffvo5rGk= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-301-8FoS0nPAPu-kKNCjQSpZaA-1; Mon, 31 Aug 2026 05:07:12 -0400 X-MC-Unique: 8FoS0nPAPu-kKNCjQSpZaA-1 X-Mimecast-MFC-AGG-ID: 8FoS0nPAPu-kKNCjQSpZaA_1788167231 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6A404193E88D; Mon, 31 Aug 2026 09:07:11 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2536D18005BD; Mon, 31 Aug 2026 09:07:07 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco , Masami Hiramatsu Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 04/20] rv: Use static arrays for rv_monitor name and description Date: Mon, 31 Aug 2026 11:05:08 +0200 Message-ID: <20260831090524.106845-5-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Name and description in struct rv_monitor are currently defined as pointers, which are assigned during initialisation. This means they are not clearly in the structure and this can be a problem if the struct needs to be reused in other contexts (like BPF's struct_opts). Make the fields static arrays with defined size, limit the description to 128 bytes (much longer than any current description). This slightly increases the kernel size as the full space for the strings is reserved, but that's a minor increase as each monitor has a single instance of struct rv_monitor, total increase around 100B per monitor, uncompressed. Signed-off-by: Gabriele Monaco --- include/linux/rv.h | 9 ++++++--- kernel/trace/rv/rv.c | 10 +++++----- kernel/trace/rv/rv.h | 3 --- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/linux/rv.h b/include/linux/rv.h index 541ba404926a..a3a332b49747 100644 --- a/include/linux/rv.h +++ b/include/linux/rv.h @@ -7,7 +7,10 @@ #ifndef _LINUX_RV_H #define _LINUX_RV_H =20 -#define MAX_DA_NAME_LEN 32 +#define MAX_RV_MONITOR_NAME_SIZE 32 +#define MAX_RV_REACTOR_NAME_SIZE 32 +#define MAX_RV_DESCRIPTION_SIZE 128 + #define MAX_DA_RETRY_RACING_EVENTS 3 =20 #define RV_MON_GLOBAL 0 @@ -137,8 +140,8 @@ struct rv_reactor { #endif =20 struct rv_monitor { - const char *name; - const char *description; + char name[MAX_RV_MONITOR_NAME_SIZE]; + char description[MAX_RV_DESCRIPTION_SIZE]; bool enabled; int (*enable)(void); void (*disable)(void); diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c index 29f155c6968b..f77c5865f41a 100644 --- a/kernel/trace/rv/rv.c +++ b/kernel/trace/rv/rv.c @@ -392,11 +392,11 @@ static ssize_t monitor_desc_read_data(struct file *fi= lp, char __user *user_buf, loff_t *ppos) { struct rv_monitor *mon =3D filp->private_data; - char buff[256]; + char buff[MAX_RV_DESCRIPTION_SIZE + 2]; =20 memset(buff, 0, sizeof(buff)); =20 - snprintf(buff, sizeof(buff), "%s\n", mon->description); + snprintf(buff, sizeof(buff), "%.*s\n", MAX_RV_DESCRIPTION_SIZE, mon->desc= ription); =20 return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff) = + 1); } @@ -756,9 +756,9 @@ int rv_register_monitor(struct rv_monitor *monitor, str= uct rv_monitor *parent) struct rv_monitor *r; int retval =3D 0; =20 - if (strlen(monitor->name) >=3D MAX_RV_MONITOR_NAME_SIZE) { - pr_info("Monitor %s has a name longer than %d\n", monitor->name, - MAX_RV_MONITOR_NAME_SIZE); + if (strnlen(monitor->name, MAX_RV_MONITOR_NAME_SIZE) =3D=3D MAX_RV_MONITO= R_NAME_SIZE) { + pr_info("Monitor %.*s has a name longer than %d\n", MAX_RV_MONITOR_NAME_= SIZE, + monitor->name, MAX_RV_MONITOR_NAME_SIZE); return -EINVAL; } =20 diff --git a/kernel/trace/rv/rv.h b/kernel/trace/rv/rv.h index 2c0f51ff9d5c..07512046e5cc 100644 --- a/kernel/trace/rv/rv.h +++ b/kernel/trace/rv/rv.h @@ -19,9 +19,6 @@ struct rv_interface { =20 DEFINE_FREE(rv_remove, struct dentry *, if (_T) rv_remove(_T)); =20 -#define MAX_RV_MONITOR_NAME_SIZE 32 -#define MAX_RV_REACTOR_NAME_SIZE 32 - extern struct mutex rv_interface_lock; extern struct list_head rv_monitors_list; =20 --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B0C593DB324 for ; Mon, 31 Aug 2026 09:07:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167246; cv=none; b=F/zRw+g/fhy9IJPKkBVH+2YZpWk9bbWMsN/Zoy2XweB2gmCx6xxX/+LaDSZSnm5YTZXczC0zjQrXarZoD8wosx8xPcpObYCFVSm8HtTPDrv66Dvr8Zeg27I3ONMPKk9Karjce2yFW7Gygw7f1uOyTK+XAoCBnMewPOPAPVVdKFk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167246; c=relaxed/simple; bh=yBB1fad5mlp6iWM0uARLq/gmr+NgwzM5PoiXDO2yt7c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZDW1tlCV49tAmKsBN1J/lTzAekfN4UeaIBo9iwjikfuMWYduWPJe5WcesXGAXTrajbop+AO1R25jNMJl5/eEsPdjdxCxl4Cswt9hagdFqkWpU8in6OWFsnMF3xU+6OmatzYjXsgPX1YaqbKrdKIQlCTZKD8k4aHEwV8ePnXgzNY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=T6dF00n1; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="T6dF00n1" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167243; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vhFeqRL96mpgj/YjWSZc04DIWo2rmDytfV8bt3Yl7J8=; b=T6dF00n1INteCVYkevfuinhjwAhLtn0K7dPQ4KsF/92lri2mO2tz91UTdkLrZzei/fXbZf VNXs3bW5ARk6vUralKkJk3bfLGd5bdHXwxyQzhX0pgMeg2IsU4vWeBZMeTXxPSOON3fXFf TOHcz6KzxvaJWiQpbrjQ5vkKH1Zisc0= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-511-DAbWaGCWNIKMBEIyzKPUQg-1; Mon, 31 Aug 2026 05:07:17 -0400 X-MC-Unique: DAbWaGCWNIKMBEIyzKPUQg-1 X-Mimecast-MFC-AGG-ID: DAbWaGCWNIKMBEIyzKPUQg_1788167235 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C887B1944D30; Mon, 31 Aug 2026 09:07:15 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A4C46180034F; Mon, 31 Aug 2026 09:07:12 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco , Masami Hiramatsu Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 05/20] rv: Add in-kernel support for BPF monitors Date: Mon, 31 Aug 2026 11:05:09 +0200 Message-ID: <20260831090524.106845-6-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add support for BPF monitors via the struct_ops mechanism, which allows BPF monitors to be loaded and appear almost like in-kernel modules. Signed-off-by: Gabriele Monaco --- kernel/trace/rv/Kconfig | 10 ++++ kernel/trace/rv/Makefile | 1 + kernel/trace/rv/rv_bpf.c | 118 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 kernel/trace/rv/rv_bpf.c diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index efa930f94ea4..be11e5c85a60 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -126,3 +126,13 @@ config RV_MONITORS_KUNIT_TEST unrelated KUnit test is running. =20 If unsure, say N. + +config RV_MON_BPF_STRUCT_OPS + bool "BPF struct_ops support for RV monitors" + depends on RV && BPF_SYSCALL && BPF_JIT + help + Enable BPF programs to register as Runtime Verification monitors + using the BPF struct_ops mechanism. This allows BPF monitors to + be managed through the standard RV interface in sysfs alongside + kernel monitors. + It has no performance impact if not used. diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile index cdbf68c84f5a..635461395cba 100644 --- a/kernel/trace/rv/Makefile +++ b/kernel/trace/rv/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_RV_REACTORS) +=3D rv_reactors.o obj-$(CONFIG_RV_REACT_PRINTK) +=3D reactor_printk.o obj-$(CONFIG_RV_REACT_PANIC) +=3D reactor_panic.o obj-$(CONFIG_RV_MONITORS_KUNIT_TEST) +=3D rv_monitors_test.o +obj-$(CONFIG_RV_MON_BPF_STRUCT_OPS) +=3D rv_bpf.o diff --git a/kernel/trace/rv/rv_bpf.c b/kernel/trace/rv/rv_bpf.c new file mode 100644 index 000000000000..0450bcaf1b79 --- /dev/null +++ b/kernel/trace/rv/rv_bpf.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * BPF struct_ops support for Runtime Verification monitors + * + * Allows BPF programs to register as RV monitors via struct_ops. + * BPF monitors appear in /sys/kernel/tracing/rv/ alongside kernel monitor= s. + * + * Copyright (C) 2026-2029 Red Hat, Inc. Gabriele Monaco + */ + +#include +#include +#include +#include +#include +#include + +static int bpf_rv_monitor_init(struct btf *btf) +{ + return 0; +} + +static int bpf_rv_monitor_init_member(const struct btf_type *t, + const struct btf_member *member, + void *kdata, const void *udata) +{ + const struct rv_monitor *umon =3D udata; + struct rv_monitor *kmon =3D kdata; + u32 moff =3D __btf_member_bit_offset(t, member) / 8; + int ret; + + switch (moff) { + case offsetof(struct rv_monitor, name): + ret =3D bpf_obj_name_cpy(kmon->name, umon->name, + sizeof(kmon->name)); + if (ret < 0) + return ret; + if (ret =3D=3D 0) + return -EINVAL; + return 1; + case offsetof(struct rv_monitor, description): + ret =3D strscpy(kmon->description, umon->description); + if (ret < 0) + return ret; + if (ret =3D=3D 0) + return -EINVAL; + return 1; + } + + return 0; +} + +static int bpf_rv_monitor_reg(void *kdata, struct bpf_link *link) +{ + struct rv_monitor *mon =3D kdata; + + pr_info("rv: Registering BPF monitor %s\n", mon->name); + return rv_register_monitor(mon, NULL); +} + +static void bpf_rv_monitor_unreg(void *kdata, struct bpf_link *link) +{ + struct rv_monitor *mon =3D kdata; + + pr_info("rv: Unregistering BPF monitor %s\n", mon->name); + rv_unregister_monitor(mon); +} + +static int bpf_rv_monitor_validate(void *kdata) +{ + struct rv_monitor *mon =3D kdata; + + if (!mon->enable) + return -EINVAL; + + return 0; +} + +static const struct bpf_verifier_ops bpf_rv_monitor_verifier_ops =3D { + .get_func_proto =3D bpf_base_func_proto, + .is_valid_access =3D NULL, +}; + +static int rv_ops__mon_enable(void) +{ + return 0; +} + +static void rv_ops__mon_disable(void) { } + +static void rv_ops__mon_reset(void) { } + +static struct rv_monitor __bpf_ops_rv_monitor =3D { + .name =3D "rv_monitor", + .description =3D "stub BPF monitor.", + .enable =3D rv_ops__mon_enable, + .disable =3D rv_ops__mon_disable, + .reset =3D rv_ops__mon_reset, + .enabled =3D 0, +}; + +static struct bpf_struct_ops bpf_rv_monitor_ops =3D { + .verifier_ops =3D &bpf_rv_monitor_verifier_ops, + .init =3D bpf_rv_monitor_init, + .init_member =3D bpf_rv_monitor_init_member, + .reg =3D bpf_rv_monitor_reg, + .unreg =3D bpf_rv_monitor_unreg, + .validate =3D bpf_rv_monitor_validate, + .name =3D "rv_monitor", + .cfi_stubs =3D &__bpf_ops_rv_monitor, + .owner =3D THIS_MODULE, +}; + +static int __init bpf_rv_monitor_init_ops(void) +{ + return register_bpf_struct_ops(&bpf_rv_monitor_ops, rv_monitor); +} +late_initcall(bpf_rv_monitor_init_ops); --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A48CC3D648F for ; Mon, 31 Aug 2026 09:07:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167246; cv=none; b=SNZh/2fyM/iFIR6JhgwHELM0pkQRGp0p+aXBqooOa69Qcnl//VInGRj5haXZLqyVOrEiiaJ+QV0OIwtnBbRiUhCUoVXzLKjpwWwaF3A4zfNnfUJsfd7Sg3yGtUKlXJs2jY9NFDNE2O2ndwMISZiLOsgVpTFy+i0/uGfAJ70JxHM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167246; c=relaxed/simple; bh=mjHNhB0GKsScSXsL5mV9BTT34DJUyPOPTHw7o+N3oqM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kGuFYjqk5QAoULUj8700HwJMZfFmg+hi9drzctuo8XNzKz91hEZlw7mgGSj0WxhNrzdj1PYlmWBTiw1Qsqa65uexzSvj4QDH8tCeNuO/jZBS4+xEeHNVG+4cDavOj1E15p6OUde8bPRFBz2XnBCPySEM7KUOCzT16h7H4u8NjL0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=SS4qYyhe; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="SS4qYyhe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167243; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=osC9YIvYCLoTIMz23HH8P7/BrPk8KQ6tK0BnBySim50=; b=SS4qYyheaTIFkLy3YT/+gz87ki+RTviLwHXJU61U0gsP9sKyR3c3NnxtRjigof4r+JSJ5D NWwLtCoxQirTV7wr3gpx/Tg03QHD3MojOArFPds5V5h5o9wIte2opTUtH2uUGkMCTmr50Z 4m88WfsdcPGQqUpCRPMVXhy+9Pl0Rqc= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-14-dQ_XbCmQM3KVg3QZ7779DQ-1; Mon, 31 Aug 2026 05:07:21 -0400 X-MC-Unique: dQ_XbCmQM3KVg3QZ7779DQ-1 X-Mimecast-MFC-AGG-ID: dQ_XbCmQM3KVg3QZ7779DQ_1788167240 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0E32A1977534; Mon, 31 Aug 2026 09:07:20 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E8CA5180034F; Mon, 31 Aug 2026 09:07:16 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco , Masami Hiramatsu Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 06/20] rv: Add rv_get_monitor_by_name() Date: Mon, 31 Aug 2026 11:05:10 +0200 Message-ID: <20260831090524.106845-7-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add a helper function to get the rv_monitor pointer for a registered monitor given its name and add its first user in rv_register_monitor(). Signed-off-by: Gabriele Monaco --- kernel/trace/rv/rv.c | 28 +++++++++++++++++++--------- kernel/trace/rv/rv.h | 1 + 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c index f77c5865f41a..33919c5fbd6a 100644 --- a/kernel/trace/rv/rv.c +++ b/kernel/trace/rv/rv.c @@ -142,6 +142,7 @@ #include #include #include +#include =20 #ifdef CONFIG_RV_MON_EVENTS #define CREATE_TRACE_POINTS @@ -229,6 +230,18 @@ bool rv_is_container_monitor(struct rv_monitor *mon) return next->parent =3D=3D mon || !mon->enable; } =20 +struct rv_monitor *rv_get_monitor_by_name(const char *name) +{ + struct rv_monitor *m; + + list_for_each_entry_rcu(m, &rv_monitors_list, list, + lockdep_is_held(&rv_interface_lock)) { + if (strcmp(name, m->name) =3D=3D 0) + return m; + } + return NULL; +} + /* * This section collects the monitor/ files and folders. */ @@ -753,7 +766,6 @@ static void destroy_monitor_dir(struct rv_monitor *mon) */ int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *par= ent) { - struct rv_monitor *r; int retval =3D 0; =20 if (strnlen(monitor->name, MAX_RV_MONITOR_NAME_SIZE) =3D=3D MAX_RV_MONITO= R_NAME_SIZE) { @@ -764,11 +776,9 @@ int rv_register_monitor(struct rv_monitor *monitor, st= ruct rv_monitor *parent) =20 guard(mutex)(&rv_interface_lock); =20 - list_for_each_entry(r, &rv_monitors_list, list) { - if (strcmp(monitor->name, r->name) =3D=3D 0) { - pr_info("Monitor %s is already registered\n", monitor->name); - return -EEXIST; - } + if (rv_get_monitor_by_name(monitor->name)) { + pr_info("Monitor %s is already registered\n", monitor->name); + return -EEXIST; } =20 if (parent && rv_is_nested_monitor(parent)) { @@ -785,9 +795,9 @@ int rv_register_monitor(struct rv_monitor *monitor, str= uct rv_monitor *parent) =20 /* keep children close to the parent for easier visualisation */ if (parent) - list_add(&monitor->list, &parent->list); + list_add_rcu(&monitor->list, &parent->list); else - list_add_tail(&monitor->list, &rv_monitors_list); + list_add_tail_rcu(&monitor->list, &rv_monitors_list); =20 return 0; } @@ -803,7 +813,7 @@ int rv_unregister_monitor(struct rv_monitor *monitor) guard(mutex)(&rv_interface_lock); =20 rv_disable_monitor(monitor); - list_del(&monitor->list); + list_del_rcu(&monitor->list); destroy_monitor_dir(monitor); =20 return 0; diff --git a/kernel/trace/rv/rv.h b/kernel/trace/rv/rv.h index 07512046e5cc..4d2c9cb284c9 100644 --- a/kernel/trace/rv/rv.h +++ b/kernel/trace/rv/rv.h @@ -27,6 +27,7 @@ int rv_disable_monitor(struct rv_monitor *mon); int rv_enable_monitor(struct rv_monitor *mon); bool rv_is_container_monitor(struct rv_monitor *mon); bool rv_is_nested_monitor(struct rv_monitor *mon); +struct rv_monitor *rv_get_monitor_by_name(const char *name); =20 #ifdef CONFIG_RV_REACTORS int reactor_populate_monitor(struct rv_monitor *mon, struct dentry *root); --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 489383C1D4F for ; Mon, 31 Aug 2026 09:07:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167253; cv=none; b=q1j1f6L6Zfh9xQdNnzsRhztBObL6TXlb0HQ11cLazWD5YWub1MDtu6gfwH/Z5hqu5k6hFXDmDUBkZ5PpawOFMRIdDRU6K9Hjpyf1SlMNKikDa95ISH1weqJO0klZKUnfU/ncF9zyTBRkKYKgb+XWE7M2beUSdV1khaFlzmjdVsU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167253; c=relaxed/simple; bh=BoR45k3q5o9YVGWscqsIDD+1+IXZyCFZRlspz+0cFnQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tEZJ8+QQbs9OVBmk3tDeUxDynKshZlI0RoT21T5rW7NZKCkK8xtihHuT/2sTPPHELRBtHlB4BOi0oiT5LWnbOyKKNuEtNnFadRJzU5QbRChHyn+vDNlgOtRT92G5ckn9jNWpGExM3ogJk/D2Mox8D25caMOL48FydTSjpErSkNg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=PuDznv3H; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="PuDznv3H" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167251; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hmriJ188EVhFMk186iDx29M8MLeYCr/PiV4RJlqkkHY=; b=PuDznv3HZFnNf1XXYrkjnsMF2UlwU/LSq9Kj8w0H46vvarofAE3xqsJuqeJxpR4lZoWmQ3 okHglPUYbu/1pfp10ligWxGqfgxBsRAWvasqoYyQDOdb9W1y121z2wmanCsKorD6jhbDDv 5WigOjfPYH7+DCPszfsc9bIP/wtmRyQ= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-160-oK-3V-ahPoqgv8U9FD-oMw-1; Mon, 31 Aug 2026 05:07:25 -0400 X-MC-Unique: oK-3V-ahPoqgv8U9FD-oMw-1 X-Mimecast-MFC-AGG-ID: oK-3V-ahPoqgv8U9FD-oMw_1788167244 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4274A19539B6; Mon, 31 Aug 2026 09:07:24 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 03EA718005BD; Mon, 31 Aug 2026 09:07:20 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco , Masami Hiramatsu Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 07/20] rv: Add reactors support to BPF monitors Date: Mon, 31 Aug 2026 11:05:11 +0200 Message-ID: <20260831090524.106845-8-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" The struct_ops system allows BPF monitors to be assigned reactors transparently, but calling rv_react() is something the monitors should do and BPF monitors cannot, as well as they cannot easily get a pointer to the rv_monitor structure. Add a bpf_rv_react kfunc that finds the monitor pointer given its name and triggers a reaction. Since variadic functions are complicated in BPF, this kfunc receives a plain string, that should be populated by the caller with some sort of sprintf(). Signed-off-by: Gabriele Monaco --- kernel/trace/rv/rv_bpf.c | 62 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/kernel/trace/rv/rv_bpf.c b/kernel/trace/rv/rv_bpf.c index 0450bcaf1b79..90ac7af1edff 100644 --- a/kernel/trace/rv/rv_bpf.c +++ b/kernel/trace/rv/rv_bpf.c @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include "rv.h" =20 static int bpf_rv_monitor_init(struct btf *btf) { @@ -111,8 +113,62 @@ static struct bpf_struct_ops bpf_rv_monitor_ops =3D { .owner =3D THIS_MODULE, }; =20 -static int __init bpf_rv_monitor_init_ops(void) +__bpf_kfunc_start_defs(); + +/** + * bpf_rv_react - trigger a reactor from BPF + * @name: monitor name + * @msg: pre-formatted message string + * @msg__sz: size of the msg buffer + * + * This kfunc allows BPF monitors to trigger reactors with a message. + * The message should be pre-formatted by the BPF program using bpf_snprin= tf. + */ +__bpf_kfunc void bpf_rv_react(char *name__str, char *msg, u32 msg__sz) +{ + struct rv_monitor *monitor; + char safe_msg[256]; + + if (msg__sz =3D=3D 0) + return; + msg__sz =3D min_t(u32, msg__sz, sizeof(safe_msg)); + if (strncpy_from_kernel_nofault(safe_msg, msg, msg__sz) < 0) + return; + safe_msg[msg__sz - 1] =3D '\0'; + + guard(rcu)(); + monitor =3D rv_get_monitor_by_name(name__str); + + if (monitor) + rv_react(monitor, "%s", safe_msg); +} + +__bpf_kfunc_end_defs(); + +BTF_KFUNCS_START(rv_kfunc_set_ids) +BTF_ID_FLAGS(func, bpf_rv_react) +BTF_KFUNCS_END(rv_kfunc_set_ids) + +static const struct btf_kfunc_id_set rv_kfunc_set =3D { + .owner =3D THIS_MODULE, + .set =3D &rv_kfunc_set_ids, +}; + +static int __init rv_monitor_init_bpf(void) { - return register_bpf_struct_ops(&bpf_rv_monitor_ops, rv_monitor); + int ret; + + ret =3D register_bpf_struct_ops(&bpf_rv_monitor_ops, rv_monitor); + if (ret) { + pr_err("rv: Failed to register struct_ops (%pe)\n", ERR_PTR(ret)); + return ret; + } + + ret =3D register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &rv_kfunc_set); + if (ret) { + pr_err("rv: Failed to register reactor kfunc (%pe)\n", ERR_PTR(ret)); + return ret; + } + return 0; } -late_initcall(bpf_rv_monitor_init_ops); +late_initcall(rv_monitor_init_bpf); --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 92C043DCDA4 for ; Mon, 31 Aug 2026 09:07:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167256; cv=none; b=bK0emEhWtgstgEKWH3iYALnOu8P7iy/IgRSge1W86V7Zw68UCEFYd9GxZiNkOi8gX0Ee2y4pqyB0oD0C8hUx5Bymd+cOi097CaF7mE6gb/pWgBfcIR2jtS8RctF2AJXqvwJrlacCb48uJ3MB/3H1eeU96G9oe4oPndfLvuO42ng= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167256; c=relaxed/simple; bh=0jcN2iFHeLYz5g2Rm8sCC2sW0gbrujvXHoF4PubAbZs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tsUfVaX2PqudF/i11mvL+ExhLFj2sCVS1xBhccPz/lJ2h1R9vnid4d9DysLChihCvNvrsXv+bt5kIDdk8tJEH4efUOukvIpkhV988ZhOXOAQWQrf1FilM26YxuMgeUmpSu8D25w/UTMBp3aOjOENMRnGkAd0+fZIpHAsWxMKQug= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Y0M66T8v; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Y0M66T8v" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167253; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6y7FpboE6dB3g0qpILJfxK978PdFVDdCOnXJM43FKdQ=; b=Y0M66T8vYIc/jj2tUkSR7pdEhhnluWXhF8SPtpGwPI0UATjRl7Y6trxghpwFe6DScUJYPZ ecVn0JwIWiSrOUFWQ3RfCTGtwWBYvUjEMIU2176jcNCdWuWKbuapDlNOrtkykuF7KTiXNR iNrdmwSercVIiup12bSHztEzVEnYsIA= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-482-9DsAUIwOPmGo7pc0SIFRtw-1; Mon, 31 Aug 2026 05:07:29 -0400 X-MC-Unique: 9DsAUIwOPmGo7pc0SIFRtw-1 X-Mimecast-MFC-AGG-ID: 9DsAUIwOPmGo7pc0SIFRtw_1788167248 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0C02A1831372; Mon, 31 Aug 2026 09:07:28 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3784318005BB; Mon, 31 Aug 2026 09:07:24 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 08/20] rv: Cast result of model_get_*_name() Date: Mon, 31 Aug 2026 11:05:12 +0200 Message-ID: <20260831090524.106845-9-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Functions like model_get_event_name() and model_get_state_name() are shared with BPF monitors, however those programs don't play nice with string pointers without fixed length and the event_name and state_name arrays need to be defined differently. This gets the compiler to notice those are const char and the above function discard the const qualifier. Drop the warning by casting the result to (char *). Note, a cleaner solution would require to modify all callers, but that would require changing every single monitor's tracepoint and the advantage is minimal. Signed-off-by: Gabriele Monaco --- include/rv/automata.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rv/automata.h b/include/rv/automata.h index 4a4eb40cf09a..3c7070e91d11 100644 --- a/include/rv/automata.h +++ b/include/rv/automata.h @@ -27,7 +27,7 @@ static char *model_get_state_name(enum states state) if ((state < 0) || (state >=3D STATE_MAX)) return "INVALID"; =20 - return RV_AUTOMATON_NAME.state_names[state]; + return (char *)RV_AUTOMATON_NAME.state_names[state]; } =20 /* @@ -38,7 +38,7 @@ static char *model_get_event_name(enum events event) if ((event < 0) || (event >=3D EVENT_MAX)) return "INVALID"; =20 - return RV_AUTOMATON_NAME.event_names[event]; + return (char *)RV_AUTOMATON_NAME.event_names[event]; } =20 /* --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D0CC53DCDB5 for ; Mon, 31 Aug 2026 09:07:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167258; cv=none; b=M/9Vpt7DqxyVcpuoYzOc+yRrJDsqLXwpixNlLaWIthXvKD/jhIWmcpWtlD25+aeeAGtKEED389UPvPKX5SwVme73RvK9hHw/C5WQeG52LaF7HW+EHRWD3FmypFZdUPwcJ1A6pA4Cmasm4UfVkTWHJpcREfVEaxTo00o3PphWnUc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167258; c=relaxed/simple; bh=+qV67Ar596nvxR1LzpkF9oPPwr0qUM+QM87yOpwM8ik=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DV7ITipIiDVIXcDrGRTjC1J+FDDGvIOxglq0ycI4Oc37gnfLSQ1uOgk93m1mflCfFjK+JIsORLN78+I6tn9bdaKly9YhWX3zy8mbhH4Auq+WgvJwoYSPkfdFUfR0tedOYyx+y/1fOv52Z8jLaCp4GxctkjP0fmOJfVGzusu7YMc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=FlOl8KUI; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="FlOl8KUI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167255; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Cjis/B05Scr88Nzqwwo6UIDqHak36kTaKJ2jA+vrqPA=; b=FlOl8KUIVDBUMJBgyqZwvWQrUp/FvpLFT36DGMJNUgXweH8gAOgvdz1pX3ozudHNU9O6Pc K1J+/NfkAHdZdWJOIoZvZ0Dks8iGOBJkWJ0f1b3fU3wGeKapOMvUx1TgBPuuqVwvUO1gvI sVpG9J0DZLa+89mnx+WIEnQI5+K1Fdg= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-538-cfPM8NB5NN6Ue5h7KqYHQw-1; Mon, 31 Aug 2026 05:07:34 -0400 X-MC-Unique: cfPM8NB5NN6Ue5h7KqYHQw-1 X-Mimecast-MFC-AGG-ID: cfPM8NB5NN6Ue5h7KqYHQw_1788167252 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7ECEE1977503; Mon, 31 Aug 2026 09:07:32 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 42F0A18005BB; Mon, 31 Aug 2026 09:07:29 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco , Masami Hiramatsu Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 09/20] rv: Handle unregistered monitors safely in tracefs Date: Mon, 31 Aug 2026 11:05:13 +0200 Message-ID: <20260831090524.106845-10-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" With the introduction of pluggable BPF monitors, a monitor can be dynamically unregistered while its tracefs files are still open by a userspace process. This leaves a dangling pointer in the tracefs file descriptor's private_data. Validate that the monitor pointer still exists in the rv_monitors_list before dereferencing it during read/write operations and return an error otherwise. Signed-off-by: Gabriele Monaco --- kernel/trace/rv/rv.c | 32 +++++++++++++++++++++++++++++--- kernel/trace/rv/rv.h | 1 + kernel/trace/rv/rv_reactors.c | 6 ++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c index 33919c5fbd6a..6ddd3b92da1d 100644 --- a/kernel/trace/rv/rv.c +++ b/kernel/trace/rv/rv.c @@ -245,13 +245,31 @@ struct rv_monitor *rv_get_monitor_by_name(const char = *name) /* * This section collects the monitor/ files and folders. */ + +bool rv_is_monitor_registered(struct rv_monitor *mon) +{ + struct rv_monitor *m; + + list_for_each_entry_rcu(m, &rv_monitors_list, list, + lockdep_is_held(&rv_interface_lock)) { + if (m =3D=3D mon) + return true; + } + return false; +} + static ssize_t monitor_enable_read_data(struct file *filp, char __user *us= er_buf, size_t count, loff_t *ppos) { struct rv_monitor *mon =3D filp->private_data; const char *buff; =20 - buff =3D mon->enabled ? "1\n" : "0\n"; + scoped_guard(rcu) { + if (!rv_is_monitor_registered(mon)) + return -ENODEV; + + buff =3D mon->enabled ? "1\n" : "0\n"; + } =20 return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff)+= 1); } @@ -384,6 +402,9 @@ static ssize_t monitor_enable_write_data(struct file *f= ilp, const char __user *u =20 guard(mutex)(&rv_interface_lock); =20 + if (!rv_is_monitor_registered(mon)) + return -ENODEV; + if (val) retval =3D rv_enable_monitor(mon); else @@ -407,9 +428,14 @@ static ssize_t monitor_desc_read_data(struct file *fil= p, char __user *user_buf, struct rv_monitor *mon =3D filp->private_data; char buff[MAX_RV_DESCRIPTION_SIZE + 2]; =20 - memset(buff, 0, sizeof(buff)); + scoped_guard(rcu) { + if (!rv_is_monitor_registered(mon)) + return -ENODEV; =20 - snprintf(buff, sizeof(buff), "%.*s\n", MAX_RV_DESCRIPTION_SIZE, mon->desc= ription); + memset(buff, 0, sizeof(buff)); + snprintf(buff, sizeof(buff), "%.*s\n", MAX_RV_DESCRIPTION_SIZE, + mon->description); + } =20 return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff) = + 1); } diff --git a/kernel/trace/rv/rv.h b/kernel/trace/rv/rv.h index 4d2c9cb284c9..6650ee9de308 100644 --- a/kernel/trace/rv/rv.h +++ b/kernel/trace/rv/rv.h @@ -28,6 +28,7 @@ int rv_enable_monitor(struct rv_monitor *mon); bool rv_is_container_monitor(struct rv_monitor *mon); bool rv_is_nested_monitor(struct rv_monitor *mon); struct rv_monitor *rv_get_monitor_by_name(const char *name); +bool rv_is_monitor_registered(struct rv_monitor *mon); =20 #ifdef CONFIG_RV_REACTORS int reactor_populate_monitor(struct rv_monitor *mon, struct dentry *root); diff --git a/kernel/trace/rv/rv_reactors.c b/kernel/trace/rv/rv_reactors.c index 2f5fc8d18dea..e23e0b5cc0ca 100644 --- a/kernel/trace/rv/rv_reactors.c +++ b/kernel/trace/rv/rv_reactors.c @@ -142,6 +142,9 @@ static int monitor_reactor_show(struct seq_file *m, voi= d *p) struct rv_monitor *mon =3D m->private; struct rv_reactor *reactor =3D container_of(p, struct rv_reactor, list); =20 + if (!rv_is_monitor_registered(mon)) + return -ENODEV; + if (mon->reactor =3D=3D reactor) seq_printf(m, "[%s]\n", reactor->name); else @@ -235,6 +238,9 @@ monitor_reactors_write(struct file *file, const char __= user *user_buf, =20 guard(mutex)(&rv_interface_lock); =20 + if (!rv_is_monitor_registered(mon)) + return -ENODEV; + list_for_each_entry(reactor, &rv_reactors_list, list) { if (strcmp(ptr, reactor->name) !=3D 0) continue; --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 492CD3D953D for ; Mon, 31 Aug 2026 09:07:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167263; cv=none; b=NEB6Ja0Ui9JrDRUiN6gNtOUb818ptXpcN79UR94wME7ZcaE6m9F808q5Zez9Asg3KEvjss+LZtw+/MeBx/Y5N2rS0PTXa61C9fme2s/HFnrXydLulMqTeri6mMofr70rG6P3P10D+/GI2wJx0xavnYszJd/X15p40eDnr/MEGrI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167263; c=relaxed/simple; bh=9r5M4rIj4+hF+KtfQqrO2x8G++VULgRCMeD1ZgM3wHY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kpjLkdb6wV1tsJNw23ARSw3Jzd4Qz22LvOXDZ908rP2vBazmYbJuWd9+eomWbOAFDCva9FQFjfS9LeUS06SX3/NXTLUE/NJdrTvTUngsShnu8EtL0/QrEgqjxxOR8Mol0b8uBCDWrEFtXq7H0DLDDAgc0iGBs1bWwCGcbM8empE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=W52y0JAs; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="W52y0JAs" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167261; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=KV/Vux23DHgPSLGlb27mR1UC4IHDhvUez5agcR2b54Q=; b=W52y0JAss3bzPdFwASVZ/cONNpjipt/0pYGHuj2dxNCwVdeNWRnMNMt6YCJUQr97yLfbKK boFHQqE5gCuQxv0CUeyicvXX8tuW3sJM3s6pHA5WQnYReGzk3eOUpR/kwmW856l4eDDEPv On7GUTu2GWwMS86tNmi1ZuwgBeByyvY= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-578-Ia3uqnTqOHilvwHzV_fL7w-1; Mon, 31 Aug 2026 05:07:37 -0400 X-MC-Unique: Ia3uqnTqOHilvwHzV_fL7w-1 X-Mimecast-MFC-AGG-ID: Ia3uqnTqOHilvwHzV_fL7w_1788167256 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 77E6F1977536; Mon, 31 Aug 2026 09:07:36 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 84EFD18005BB; Mon, 31 Aug 2026 09:07:33 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org Cc: Gabriele Monaco , Steven Rostedt , Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 10/20] tools/build: Add a feature test for bpftool-btf Date: Mon, 31 Aug 2026 11:05:14 +0200 Message-ID: <20260831090524.106845-11-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" RV can run bpf monitors and also build them, only the latter requires the vmlinux.h from bpftool btf. Add a feature so that RV can be built with BPF support without having to build in-tree BPF monitors if not supported on the system. Signed-off-by: Gabriele Monaco --- tools/build/Makefile.feature | 1 + tools/build/feature/Makefile | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 99eb0ea09537..18e3a7ae893a 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -129,6 +129,7 @@ FEATURE_TESTS_EXTRA :=3D \ libdebuginfod \ clang-bpf-co-re \ bpftool-skeletons \ + bpftool-btf \ libunwind \ libunwind-debug-frame \ $(foreach arch,$(LIBUNWIND_ARCHS),libunwind-$(arch) libunwind-deb= ug-frame-$(arch)) diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 7d165018116a..2f01203dda5c 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -71,7 +71,8 @@ FILES=3D \ test-libpfm4.bin \ test-rust.bin \ test-libopenssl.bin \ - test-bpftool-skeletons.bin + test-bpftool-skeletons.bin \ + test-bpftool-btf.bin =20 FILES :=3D $(addprefix $(OUTPUT),$(FILES)) =20 @@ -383,6 +384,10 @@ $(OUTPUT)test-bpftool-skeletons.bin: { $(SYSTEM_BPFTOOL) version | grep '^features:.*skeletons'; } \ > $(@:.bin=3D.make.output) 2>&1 && touch $@ =20 +$(OUTPUT)test-bpftool-btf.bin: + $(SYSTEM_BPFTOOL) btf help \ + > $(@:.bin=3D.make.output) 2>&1 && touch $@ + # Testing Rust is special: we don't compile anything, it's enough to check= the # compiler presence. Compiling a test code for this purposes is problemati= c, # because Rust will emit a dependency file without any external references, --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BFD043D34B1 for ; Mon, 31 Aug 2026 09:07:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167270; cv=none; b=Ebnn62FTY3jOcf8H5WLcmxY4eCv/OS32EJYs7cDzWILgYNqEGp6+1Hr/w6vgq3QHts/zgGkshCCG7s37Lpjb4qkhjrGfxj7R4OaIyDWp322NLA5kQVTKhihh7pfc2X9b1nqyxpVfN3+6GzRPMRUTWmKmCDXxTybLViQ7ig2KCvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167270; c=relaxed/simple; bh=uSJomDprxsnWTtFPX/R2Afszocpxml5nszMvKZHe0KU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kF5iZ/B+HY0DpT2f48d+K0rZUCKaMy0QY3ekUnWt0IvNfPj7MhmRFFvNL200H7LBYHssMfM+ppxHLZzvovNuRR7kxSINZWJeabe9n2P7k41/dba2pasNAP0yz1J1d00n0jgT4smNVDw2i2R2c/lsXZzQEs1+MgjgpTJaa+jNRdA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=hd63OE8V; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="hd63OE8V" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167266; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Gb4BBRJgsos+aIxLr9PMCch4Op1Of0hAHjtYV/DYPx8=; b=hd63OE8VFL8tcC7fKffKUXpAh65SUQSGdsb506+XagO+wrpCGpU1Q0D8NZU8qNEDjrFhyE miE2/YVIjnfffMHzXjoN5vcQIjXA9bd+vptl0mJTWRuQILz1qvNfDsokmdZJTJJQ8CyGnK WZdj8hhb4oXHyTyQcX+YiWF9bZ1J/HA= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-155-nmhHIhIeNTyhCdyEogHfYQ-1; Mon, 31 Aug 2026 05:07:42 -0400 X-MC-Unique: nmhHIhIeNTyhCdyEogHfYQ-1 X-Mimecast-MFC-AGG-ID: nmhHIhIeNTyhCdyEogHfYQ_1788167260 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CAA94195C248; Mon, 31 Aug 2026 09:07:40 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A64DB18005BB; Mon, 31 Aug 2026 09:07:37 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 11/20] tools/rv: Move argument parsing from in_kernel to utils Date: Mon, 31 Aug 2026 11:05:15 +0200 Message-ID: <20260831090524.106845-12-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" The configuration of the in-kernel RV monitor is relying on global variables, some static and some extern and the argument parsing occurs there. That's not scalable especially if the configuration needs to be shared by other monitor implementations (e.g. BPF). Move the common argument parsing in utils and use a global struct for the configuration. Implementation-specific configuration such as the reactors are still handled in the in-kernel source. Signed-off-by: Gabriele Monaco --- tools/verification/rv/include/utils.h | 17 ++- tools/verification/rv/src/in_kernel.c | 176 ++++++-------------------- tools/verification/rv/src/utils.c | 95 +++++++++++++- 3 files changed, 149 insertions(+), 139 deletions(-) diff --git a/tools/verification/rv/include/utils.h b/tools/verification/rv/= include/utils.h index f24ae8282bd2..61f77a72a1a2 100644 --- a/tools/verification/rv/include/utils.h +++ b/tools/verification/rv/include/utils.h @@ -1,8 +1,23 @@ // SPDX-License-Identifier: GPL-2.0 =20 +#include + #define MAX_PATH 1024 =20 void debug_msg(const char *fmt, ...); void err_msg(const char *fmt, ...); +void mon_usage(int exit_val, char *monitor_name, const char *fmt, ...); +int parse_arguments(char *monitor_name, int argc, char **argv); + +void ikm_usage_print_reactors(void); =20 -extern int config_debug; +struct config { + bool debug; + bool is_container; + bool trace; + int has_id; + int my_pid; + char *initial_reactor; + char *reactor; +}; +extern struct config config; diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/= src/in_kernel.c index e6dea4040f8f..90c340a73c76 100644 --- a/tools/verification/rv/src/in_kernel.c +++ b/tools/verification/rv/src/in_kernel.c @@ -4,7 +4,6 @@ * * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira */ -#include #include #include #include @@ -16,14 +15,6 @@ #include #include =20 -static int config_has_id; -static int config_is_container; -static int config_my_pid; -static int config_trace; - -static char *config_initial_reactor; -static char *config_reactor; - /* * __ikm_read_enable - reads monitor's enable status * @@ -66,7 +57,7 @@ static int __ikm_find_monitor_name(char *monitor_name, ch= ar *out_name) if (!available_monitors) return -1; =20 - config_is_container =3D 0; + config.is_container =3D 0; cursor =3D available_monitors; while ((line =3D strsep(&cursor, "\n"))) { char *colon =3D strchr(line, ':'); @@ -83,7 +74,7 @@ static int __ikm_find_monitor_name(char *monitor_name, ch= ar *out_name) /* If there are children, they are on the next line. */ line =3D strsep(&cursor, "\n"); if (line && !strncmp(line, monitor_name, len) && line[len] =3D=3D ':') - config_is_container =3D 1; + config.is_container =3D 1; } =20 found =3D 1; @@ -391,7 +382,7 @@ int ikm_list_monitors(char *container) static void ikm_print_header(struct trace_seq *s) { trace_seq_printf(s, "%16s-%-8s %5s %5s ", "", "PID", "[CPU]", "TYPE= "); - if (config_has_id) + if (config.has_id) trace_seq_printf(s, "%8s ", "ID"); =20 trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n", @@ -402,7 +393,7 @@ static void ikm_print_header(struct trace_seq *s) =20 trace_seq_printf(s, "%16s %-8s %5s %5s ", " | ", " | ", " | ", " | "); =20 - if (config_has_id) + if (config.has_id) trace_seq_printf(s, "%8s ", " | "); =20 trace_seq_printf(s, "%24s %-24s %-24s %s\n", @@ -431,25 +422,25 @@ ikm_event_handler(struct trace_seq *s, struct tep_rec= ord *record, int val; bool missing_id; =20 - if (config_has_id) + if (config.has_id) missing_id =3D tep_get_field_val(s, trace_event, "id", record, &id, 1); =20 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); =20 - if (config_has_id && (config_my_pid =3D=3D id)) + if (config.has_id && (config.my_pid =3D=3D id)) return 0; - else if (config_my_pid =3D=3D pid) + else if (config.my_pid =3D=3D pid) return 0; =20 tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ", TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU); =20 - if (config_is_container) + if (config.is_container) tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); else trace_seq_printf(s, "event "); =20 - if (config_has_id) { + if (config.has_id) { if (missing_id) /* placeholder if we are dealing with a mixed-type container*/ trace_seq_printf(s, " "); @@ -490,24 +481,24 @@ ikm_error_handler(struct trace_seq *s, struct tep_rec= ord *record, int val; bool missing_id; =20 - if (config_has_id) + if (config.has_id) missing_id =3D tep_get_field_val(s, trace_event, "id", record, &id, 1); =20 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); =20 - if (config_has_id && config_my_pid =3D=3D id) + if (config.has_id && config.my_pid =3D=3D id) return 0; - else if (config_my_pid =3D=3D pid) + else if (config.my_pid =3D=3D pid) return 0; =20 trace_seq_printf(s, "%8lld [%03d] ", pid, cpu); =20 - if (config_is_container) + if (config.is_container) tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); else trace_seq_printf(s, "error "); =20 - if (config_has_id) { + if (config.has_id) { if (missing_id) /* placeholder if we are dealing with a mixed-type container*/ trace_seq_printf(s, " "); @@ -548,8 +539,8 @@ static int ikm_enable_trace_events(char *monitor_name, = struct trace_instance *in ikm_error_handler, NULL); =20 /* set if at least 1 monitor has id in case of a container */ - config_has_id =3D ikm_has_id(monitor_name); - if (config_has_id < 0) + config.has_id =3D ikm_has_id(monitor_name); + if (config.has_id < 0) return -1; =20 =20 @@ -596,7 +587,7 @@ static struct trace_instance *ikm_setup_trace_instance(= char *monitor_name) struct trace_instance *inst; int retval; =20 - if (!config_trace) + if (!config.trace) return NULL; =20 /* alloc data */ @@ -610,7 +601,7 @@ static struct trace_instance *ikm_setup_trace_instance(= char *monitor_name) if (retval) goto out_free; =20 - if (config_is_container) + if (config.is_container) retval =3D ikm_enable_trace_container(monitor_name, inst); else retval =3D ikm_enable_trace_events(monitor_name, inst); @@ -645,7 +636,7 @@ static void ikm_destroy_trace_instance(struct trace_ins= tance *inst) /* * ikm_usage_print_reactors - print all available reactors, one per line. */ -static void ikm_usage_print_reactors(void) +void ikm_usage_print_reactors(void) { char *reactors =3D tracefs_instance_file_read(NULL, "rv/available_reactor= s", NULL); char *start, *end; @@ -669,106 +660,6 @@ static void ikm_usage_print_reactors(void) =20 fprintf(stderr, "\n"); } -/* - * ikm_usage - print usage - */ -static void ikm_usage(int exit_val, char *monitor_name, const char *fmt, .= ..) -{ - - char message[1024]; - va_list ap; - int i; - - static const char *const usage[] =3D { - "", - " -h/--help: print this menu and the reactor list", - " -r/--reactor 'reactor': enables the 'reactor'", - " -s/--self: when tracing (-t), also trace rv command", - " -t/--trace: trace monitor's event", - " -v/--verbose: print debug messages", - "", - NULL, - }; - - va_start(ap, fmt); - vsnprintf(message, sizeof(message), fmt, ap); - va_end(ap); - - fprintf(stderr, " %s\n", message); - - fprintf(stderr, "\n usage: rv mon %s [-h] [-q] [-r reactor] [-s] [-v]", = monitor_name); - - for (i =3D 0; usage[i]; i++) - fprintf(stderr, "%s\n", usage[i]); - - ikm_usage_print_reactors(); - exit(exit_val); -} - -/* - * parse_arguments - parse arguments and set config - */ -static int parse_arguments(char *monitor_name, int argc, char **argv) -{ - int c, retval; - - config_my_pid =3D getpid(); - - while (1) { - static struct option long_options[] =3D { - {"help", no_argument, 0, 'h'}, - {"reactor", required_argument, 0, 'r'}, - {"self", no_argument, 0, 's'}, - {"trace", no_argument, 0, 't'}, - {"verbose", no_argument, 0, 'v'}, - {0, 0, 0, 0} - }; - - /* getopt_long stores the option index here. */ - int option_index =3D 0; - - c =3D getopt_long(argc, argv, "hr:stv", long_options, &option_index); - - /* detect the end of the options. */ - if (c =3D=3D -1) - break; - - switch (c) { - case 'h': - ikm_usage(0, monitor_name, "help:"); - break; - case 'r': - config_reactor =3D optarg; - break; - case 's': - config_my_pid =3D -1; - break; - case 't': - config_trace =3D 1; - break; - case 'v': - config_debug =3D 1; - break; - } - } - - if (config_reactor) { - config_initial_reactor =3D ikm_get_current_reactor(monitor_name); - if (!config_initial_reactor) - ikm_usage(1, monitor_name, - "ikm: failed to read current reactor, are reactors enabled?"); - - retval =3D ikm_write_reactor(monitor_name, config_reactor); - if (retval <=3D 0) - ikm_usage(1, monitor_name, - "ikm: failed to set %s reactor, is it available?", - config_reactor); - } - - debug_msg("ikm: my pid is %d\n", config_my_pid); - - return 0; -} =20 /** * ikm_run_monitor - apply configs and run the monitor @@ -805,9 +696,22 @@ int ikm_run_monitor(char *monitor_name, int argc, char= **argv) /* we should be good to go */ retval =3D parse_arguments(full_name, argc, argv); if (retval) - ikm_usage(1, nested_name, "ikm: failed parsing arguments"); + mon_usage(1, nested_name, "ikm: failed parsing arguments"); + + if (config.reactor) { + config.initial_reactor =3D ikm_get_current_reactor(full_name); + if (!config.initial_reactor) + mon_usage(1, full_name, + "ikm: failed to read current reactor, are reactors enabled?"); + + retval =3D ikm_write_reactor(full_name, config.reactor); + if (retval <=3D 0) + mon_usage(1, full_name, + "ikm: failed to set %s reactor, is it available?", + config.reactor); + } =20 - if (config_trace) { + if (config.trace) { inst =3D ikm_setup_trace_instance(nested_name); if (!inst) goto out_free_instance; @@ -817,11 +721,11 @@ int ikm_run_monitor(char *monitor_name, int argc, cha= r **argv) if (retval < 0) goto out_free_instance; =20 - if (config_trace) + if (config.trace) ikm_print_header(inst->seq); =20 while (!should_stop()) { - if (config_trace) { + if (config.trace) { retval =3D tracefs_iterate_raw_events(inst->tep, inst->inst, NULL, @@ -840,14 +744,14 @@ int ikm_run_monitor(char *monitor_name, int argc, cha= r **argv) ikm_disable(full_name); ikm_destroy_trace_instance(inst); =20 - if (config_reactor && config_initial_reactor) - ikm_write_reactor(full_name, config_initial_reactor); + if (config.reactor && config.initial_reactor) + ikm_write_reactor(full_name, config.initial_reactor); =20 return 1; =20 out_free_instance: ikm_destroy_trace_instance(inst); - if (config_reactor && config_initial_reactor) - ikm_write_reactor(full_name, config_initial_reactor); + if (config.reactor && config.initial_reactor) + ikm_write_reactor(full_name, config.initial_reactor); return -1; } diff --git a/tools/verification/rv/src/utils.c b/tools/verification/rv/src/= utils.c index 5677b439dc2f..e19dd65ec789 100644 --- a/tools/verification/rv/src/utils.c +++ b/tools/verification/rv/src/utils.c @@ -5,11 +5,14 @@ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira */ =20 +#include #include +#include #include +#include #include =20 -int config_debug; +struct config config; =20 #define MAX_MSG_LENGTH 1024 =20 @@ -36,7 +39,7 @@ void debug_msg(const char *fmt, ...) char message[MAX_MSG_LENGTH]; va_list ap; =20 - if (!config_debug) + if (!config.debug) return; =20 va_start(ap, fmt); @@ -45,3 +48,91 @@ void debug_msg(const char *fmt, ...) =20 fprintf(stderr, "%s", message); } + +/* + * mon_usage - print usage + */ +void mon_usage(int exit_val, char *monitor_name, const char *fmt, ...) +{ + + char message[1024]; + va_list ap; + int i; + + static const char *const usage[] =3D { + "", + " -h/--help: print this menu and the reactor list", + " -r/--reactor 'reactor': enables the 'reactor'", + " -s/--self: when tracing (-t), also trace rv command", + " -t/--trace: trace monitor's event", + " -v/--verbose: print debug messages", + "", + NULL, + }; + + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + + fprintf(stderr, " %s\n", message); + + fprintf(stderr, "\n usage: rv mon %s [-h] [-q] [-r reactor] [-s] [-v]", = monitor_name); + + for (i =3D 0; usage[i]; i++) + fprintf(stderr, "%s\n", usage[i]); + + ikm_usage_print_reactors(); + exit(exit_val); +} + +/* + * parse_arguments - parse arguments and set config + */ +int parse_arguments(char *monitor_name, int argc, char **argv) +{ + int c; + + config.my_pid =3D getpid(); + + while (1) { + static struct option long_options[] =3D { + {"help", no_argument, 0, 'h'}, + {"reactor", required_argument, 0, 'r'}, + {"self", no_argument, 0, 's'}, + {"trace", no_argument, 0, 't'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + + /* getopt_long stores the option index here. */ + int option_index =3D 0; + + c =3D getopt_long(argc, argv, "hr:stv", long_options, &option_index); + + /* detect the end of the options. */ + if (c =3D=3D -1) + break; + + switch (c) { + case 'h': + mon_usage(0, monitor_name, "help:"); + break; + case 'r': + config.reactor =3D optarg; + break; + case 's': + config.my_pid =3D -1; + break; + case 't': + config.trace =3D 1; + break; + case 'v': + config.debug =3D 1; + break; + } + } + + debug_msg("ikm: my pid is %d\n", config.my_pid); + + return 0; +} --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 921C23E0083 for ; Mon, 31 Aug 2026 09:07:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167273; cv=none; b=mc1BUsZt4LhnSZ9/m/rx6GPucDtnCjLCW0lSKtoR0GiFKbvn4toWtLsBxEUY2tnmCz+RaGtuS1Mekn0prxUMIMXzLAlT4Ozy4FRbydlcLlq4iLApA0wxg39sl+rRzds3HmXAQSRcEZyeeJ63+6P/6ggkGFK+E/v86ZSyiQkByks= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167273; c=relaxed/simple; bh=LWVvoYDOjwXs2EC7A13p00+8P6+MboEh6Gx+JUd1pDw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Gc2jA9XKDibbLrY6eFWJ2gE63YvKxfsmV+5U/dtCbtpGQWWMxDLeXeqcbrQAgxo4KOMNIjqOH3sHaX8sqHOOXgQv4rZXlT+OdrmFYoTPTjuJN0MXzNdD1lNuNpBFRmUG7UP6vLNFr0AhDyNWZd3slPF+TAQwB4+3eyoHY38jOJc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=dLeof61m; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="dLeof61m" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167270; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=48qH1PP4jCa06+axLa6Y0uRn+3AU5SUX8PUnznpl2do=; b=dLeof61mdb7lARHRIsv38vkrUbt2t50YLR1uFIpKxuRu2FIeQZ7nJqcd7F8+xR2yI26pIv ScXyp0d9hxB9kO3yJF0ne8W6REtN1FVib8HzApjg686AHZpMXTLFPn6iQPp/xyeBEWy1aS wSCV62kv6XYfmxEzuS1iWoEPfV20nRw= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-652-VAhD7_5VO2ig7e2GI0AwHg-1; Mon, 31 Aug 2026 05:07:46 -0400 X-MC-Unique: VAhD7_5VO2ig7e2GI0AwHg-1 X-Mimecast-MFC-AGG-ID: VAhD7_5VO2ig7e2GI0AwHg_1788167264 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B3343193E889; Mon, 31 Aug 2026 09:07:44 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BEA8A180034F; Mon, 31 Aug 2026 09:07:41 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 12/20] tools/rv: Export functionality for in_kernel monitors Date: Mon, 31 Aug 2026 11:05:16 +0200 Message-ID: <20260831090524.106845-13-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Export enable/disable and reactor set/reset functionality from in-kernel monitor to be used by other compatible monitor types (BPF). Use helpers to simplify the reactor set/reset actions. Signed-off-by: Gabriele Monaco --- tools/verification/rv/include/in_kernel.h | 5 ++ tools/verification/rv/src/in_kernel.c | 61 ++++++++++++++++------- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/tools/verification/rv/include/in_kernel.h b/tools/verification= /rv/include/in_kernel.h index f3bfd3b9895f..16d68caa84bd 100644 --- a/tools/verification/rv/include/in_kernel.h +++ b/tools/verification/rv/include/in_kernel.h @@ -1,3 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 int ikm_list_monitors(char *container); int ikm_run_monitor(char *monitor, int argc, char **argv); +int __ikm_read_enable(char *monitor_name); +int ikm_enable(char *monitor_name); +int ikm_disable(char *monitor_name); +void ikm_set_reactor(char *monitor_name); +void ikm_reset_reactor(char *monitor_name); diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/= src/in_kernel.c index 90c340a73c76..3e8272d55a3a 100644 --- a/tools/verification/rv/src/in_kernel.c +++ b/tools/verification/rv/src/in_kernel.c @@ -23,7 +23,7 @@ * Returns the current status, or -1 if the monitor does not exist, * __hence not logging errors. */ -static int __ikm_read_enable(char *monitor_name) +int __ikm_read_enable(char *monitor_name) { char path[MAX_PATH]; long long enabled; @@ -132,7 +132,7 @@ static int ikm_write_enable(char *monitor_name, char *e= nable_disable) * * Returns -1 on failure. Success otherwise. */ -static int ikm_enable(char *monitor_name) +int ikm_enable(char *monitor_name) { return ikm_write_enable(monitor_name, "1"); } @@ -142,7 +142,7 @@ static int ikm_enable(char *monitor_name) * * Returns -1 on failure. Success otherwise. */ -static int ikm_disable(char *monitor_name) +int ikm_disable(char *monitor_name) { return ikm_write_enable(monitor_name, "0"); } @@ -304,6 +304,42 @@ static char *ikm_get_current_reactor(char *monitor_nam= e) return curr_reactor; } =20 +/* + * ikm_set_reactor - set the configured reactor and store the initial one + * + * Do nothing if we should not set reactors. + */ +void ikm_set_reactor(char *monitor_name) +{ + int retval; + + if (!config.reactor) + return; + + config.initial_reactor =3D ikm_get_current_reactor(monitor_name); + if (!config.initial_reactor) + mon_usage(1, monitor_name, + "ikm: failed to read current reactor, are reactors enabled?"); + + retval =3D ikm_write_reactor(monitor_name, config.reactor); + if (retval <=3D 0) + mon_usage(1, monitor_name, + "ikm: failed to set %s reactor, is it available?", + config.reactor); + +} + +/* + * ikm_reset_reactor - restore the initially stored reactor + * + * Do nothing if we should not set reactors. + */ +void ikm_reset_reactor(char *monitor_name) +{ + if (config.reactor && config.initial_reactor) + ikm_write_reactor(monitor_name, config.initial_reactor); +} + static int ikm_has_id(char *monitor_name) { char path[MAX_PATH]; @@ -698,18 +734,7 @@ int ikm_run_monitor(char *monitor_name, int argc, char= **argv) if (retval) mon_usage(1, nested_name, "ikm: failed parsing arguments"); =20 - if (config.reactor) { - config.initial_reactor =3D ikm_get_current_reactor(full_name); - if (!config.initial_reactor) - mon_usage(1, full_name, - "ikm: failed to read current reactor, are reactors enabled?"); - - retval =3D ikm_write_reactor(full_name, config.reactor); - if (retval <=3D 0) - mon_usage(1, full_name, - "ikm: failed to set %s reactor, is it available?", - config.reactor); - } + ikm_set_reactor(full_name); =20 if (config.trace) { inst =3D ikm_setup_trace_instance(nested_name); @@ -744,14 +769,12 @@ int ikm_run_monitor(char *monitor_name, int argc, cha= r **argv) ikm_disable(full_name); ikm_destroy_trace_instance(inst); =20 - if (config.reactor && config.initial_reactor) - ikm_write_reactor(full_name, config.initial_reactor); + ikm_reset_reactor(full_name); =20 return 1; =20 out_free_instance: ikm_destroy_trace_instance(inst); - if (config.reactor && config.initial_reactor) - ikm_write_reactor(full_name, config.initial_reactor); + ikm_reset_reactor(full_name); return -1; } --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 547273DC4CC for ; Mon, 31 Aug 2026 09:07:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167279; cv=none; b=DEtWWulqcvYn2i1vIBPRlLDDIDlT73yuvq2UdQrM6R2xmRVJId+oKb62vZkqMNZRPrmJrsWXiXKd0OXOXCFuQYlyl7Df78lFul8A9O2jEHQFxwC7W9BlzvhPKDM7NsCC82USxZUQs0f8JJfKmCAod/gAFZNSKUEaF3wnoac4VOo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167279; c=relaxed/simple; bh=STe/Ew+lmpLpVGbXcSOX/igx68AFHMxRG+5JmNWIe5k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oZOL6J/MttBiAWZYDEzjwKAQJixy4X6yNvKdAhAbiIn2OB1wmn3oO/kDgLe2zrNYejZKc1IgO/iRIu9k0ItoaBi3gHLEdevbTeUwbqgTByAEow6M6Ifb2jfX8WY9HmMSt6q5/DyrOhweV8CcN33Ty0N5lTjGc4dS49mJkH0Ecwc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=PUy1spHR; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="PUy1spHR" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167276; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PfwnhSnqYrdkMR3z87XdFahsTZzAfFRpyLcSXL3M+us=; b=PUy1spHRFgT3RWLol131HpIkB6GrGFaSvNEdnTR1BRXGAf5KfVKczVMvtOv8hRqVYky5oO mW1BN2gBXWFmH/DLln/FdkQChCNBa9oNlO64I6UtEAdi0iZTOG7dzYF/mY89k2D9qCPYou zeVzxBhNFd95OLt6sGgZDQ38Bt9gLZ0= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-680-DUWvDvZfNIKVY-BcpxDYMQ-1; Mon, 31 Aug 2026 05:07:50 -0400 X-MC-Unique: DUWvDvZfNIKVY-BcpxDYMQ-1 X-Mimecast-MFC-AGG-ID: DUWvDvZfNIKVY-BcpxDYMQ_1788167269 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5A59F19540E2; Mon, 31 Aug 2026 09:07:49 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8716D18005BB; Mon, 31 Aug 2026 09:07:46 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 13/20] tools/rv: Implement BPF monitor loading and tracing Date: Mon, 31 Aug 2026 11:05:17 +0200 Message-ID: <20260831090524.106845-14-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Implement BPF monitor loading, execution, and optional tracing functionality. Running rv mon MON loads the MON monitor into the kernel and passing the -t parameter also attaches to the event ring buffer printing events and errors to standard output. Event and state names as well as the ring buffer entry format are dynamically parsed from BTF. Signed-off-by: Gabriele Monaco --- tools/verification/rv/Makefile | 8 +- tools/verification/rv/Makefile.config | 23 + tools/verification/rv/include/bpf_monitor.h | 14 + tools/verification/rv/src/Build | 5 + tools/verification/rv/src/bpf_monitor.c | 681 ++++++++++++++++++++ tools/verification/rv/src/rv.c | 6 +- 6 files changed, 734 insertions(+), 3 deletions(-) create mode 100644 tools/verification/rv/include/bpf_monitor.h create mode 100644 tools/verification/rv/src/bpf_monitor.c diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile index 8ae5fc0d1d17..af83566b930c 100644 --- a/tools/verification/rv/Makefile +++ b/tools/verification/rv/Makefile @@ -27,13 +27,17 @@ endif RV :=3D $(OUTPUT)rv RV_IN :=3D $(RV)-in.o =20 +TOOLS_INCLUDES =3D -I$(srctree)/tools/include + VERSION :=3D $(shell sh -c "make -sC ../../.. kernelversion | grep -v mak= e") DOCSRC :=3D ../../../Documentation/tools/rv/ =20 FEATURE_TESTS :=3D libtraceevent FEATURE_TESTS +=3D libtracefs +FEATURE_TESTS +=3D libbpf FEATURE_DISPLAY :=3D libtraceevent FEATURE_DISPLAY +=3D libtracefs +FEATURE_DISPLAY +=3D libbpf =20 all: $(RV) =20 @@ -55,9 +59,9 @@ ifeq ($(config),1) include Makefile.config endif =20 -CFLAGS +=3D $(INCLUDES) $(LIB_INCLUDES) +CFLAGS +=3D $(INCLUDES) $(LIB_INCLUDES) $(TOOLS_INCLUDES) =20 -export CFLAGS OUTPUT srctree +export CFLAGS OUTPUT srctree BUILD_BPF =20 $(RV): $(RV_IN) $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RV) $(RV_IN) $(EXTLIBS) diff --git a/tools/verification/rv/Makefile.config b/tools/verification/rv/= Makefile.config index 066302230eb2..0600170ac217 100644 --- a/tools/verification/rv/Makefile.config +++ b/tools/verification/rv/Makefile.config @@ -43,6 +43,29 @@ else $(info libtracefs is missing. Please install libtracefs-dev/libtracefs-d= evel) endif =20 +ifndef BUILD_BPF + # BPF monitors are optional but enabled by default + BUILD_BPF :=3D 1 +endif + +ifeq ($(BUILD_BPF),0) + $(info BPF monitor support disabled, building without BPF monitor suppor= t.) +endif + +$(call feature_check,libbpf) +ifeq ($(feature-libbpf), 1) + $(call detected,CONFIG_LIBBPF) +else + $(info libbpf is missing, building without BPF monitor support.) + $(info Please install libbpf-dev/libbpf-devel) + BUILD_BPF :=3D 0 +endif + +ifeq ($(BUILD_BPF),1) + CFLAGS +=3D -DHAVE_LIBBPF + $(call lib_setup,bpf) +endif + ifeq ($(STOP_ERROR),1) $(error Please, check the errors above.) endif diff --git a/tools/verification/rv/include/bpf_monitor.h b/tools/verificati= on/rv/include/bpf_monitor.h new file mode 100644 index 000000000000..60ce23589102 --- /dev/null +++ b/tools/verification/rv/include/bpf_monitor.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _BPF_MONITOR_H +#define _BPF_MONITOR_H + +#ifdef HAVE_LIBBPF +int bpf_run_monitor(char *monitor_name, int argc, char **argv); +#else +static inline int bpf_run_monitor(char *monitor_name, int argc, char **arg= v) +{ + return 0; +} +#endif /* HAVE_LIBBPF */ + +#endif diff --git a/tools/verification/rv/src/Build b/tools/verification/rv/src/Bu= ild index d781983c1a79..326503c22915 100644 --- a/tools/verification/rv/src/Build +++ b/tools/verification/rv/src/Build @@ -1,4 +1,9 @@ rv-y +=3D trace.o rv-y +=3D utils.o rv-y +=3D in_kernel.o + +ifeq ($(BUILD_BPF),1) + rv-y +=3D bpf_monitor.o +endif + rv-y +=3D rv.o diff --git a/tools/verification/rv/src/bpf_monitor.c b/tools/verification/r= v/src/bpf_monitor.c new file mode 100644 index 000000000000..e13ae35678cb --- /dev/null +++ b/tools/verification/rv/src/bpf_monitor.c @@ -0,0 +1,681 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * BPF monitor support: allows rv to control BPF monitors. + * + * Copyright (C) 2026 Red Hat Inc, Gabriele Monaco + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static char bpf_monitor_paths[][MAX_PATH] =3D { + "./bpf_monitors/", + "/usr/share/rv/bpf_monitors/", + "", /* Marker */ +}; + +/* Path used for development monitors, searched first */ +#define DEVEL_PATH 0 + +#define MAX_ENUMS 64 +#define MAX_LINKS 16 +#define RV_TRACE_EVENT 0 +#define RV_TRACE_ERROR 1 +#define BPF_PIN_BASE_PATH "/sys/fs/bpf/rv" +#define RV_TRACE_STRUCT "rv_trace_entry" + +enum da_field_id { + FIELD_EVENT_TYPE, + FIELD_ID, + FIELD_CPU, + FIELD_PID, + FIELD_COMM, + FIELD_IS_FINAL, + FIELD_CURR_STATE, + FIELD_EVENT, + FIELD_NEXT_STATE, + FIELD_MAX, +}; + +static const char *const field_names[] =3D { + [FIELD_EVENT_TYPE] =3D "event_type", + [FIELD_ID] =3D "id", + [FIELD_CPU] =3D "cpu", + [FIELD_PID] =3D "pid", + [FIELD_COMM] =3D "comm", + [FIELD_IS_FINAL] =3D "is_final", + [FIELD_CURR_STATE] =3D "curr_state", + [FIELD_EVENT] =3D "event", + [FIELD_NEXT_STATE] =3D "next_state", +}; + +struct da_field { + size_t offset; + size_t size; +}; + +struct bpf_monitor_ctx { + char monitor_name[MAX_DA_NAME_LEN]; + char state_names[MAX_ENUMS][MAX_DA_NAME_LEN]; + char event_names[MAX_ENUMS][MAX_DA_NAME_LEN]; + int num_states; + int num_events; + struct da_field field_metadata[FIELD_MAX]; +}; + +/* + * bpf_fill_monitor_paths - fill the path for development builds + * + * RV searches for BPF monitors on absolute paths on the system as well + * as in the same directory of the rv binary. This is useful when running + * rv from the kernel tree. This function resolves right location. + */ +static void bpf_fill_monitor_paths(void) +{ + char tmp_path[MAX_PATH], *dir; + ssize_t len; + + len =3D readlink("/proc/self/exe", tmp_path, MAX_PATH); + if (len > 0 && len !=3D MAX_PATH) { + tmp_path[len] =3D '\0'; + dir =3D dirname(tmp_path); + snprintf(bpf_monitor_paths[DEVEL_PATH], MAX_PATH, "%s/bpf_monitors", dir= ); + } +} + +static int libbpf_print_fn(enum libbpf_print_level level, const char *form= at, + va_list args) +{ + if (level =3D=3D LIBBPF_DEBUG && !config.debug) + return 0; + return vfprintf(stderr, format, args); +} + +/* + * Helper functions for state/event name lookup + */ +static const char *get_state_name(struct bpf_monitor_ctx *ctx, uint32_t st= ate) +{ + static char buf[16]; + + if (state < ctx->num_states && ctx->state_names[state][0] !=3D '\0') + return ctx->state_names[state]; + + snprintf(buf, sizeof(buf), "%u", state); + return buf; +} + +static const char *get_event_name(struct bpf_monitor_ctx *ctx, uint32_t ev= ent) +{ + static char buf[16]; + + if (event < ctx->num_events && ctx->event_names[event][0] !=3D '\0') + return ctx->event_names[event]; + + snprintf(buf, sizeof(buf), "%u", event); + return buf; +} + +/* + * extract_field_metadata - extract field metadata from BTF for efficient = parsing + * + * Introspect the rv_trace_entry structure via BTF and store field offsets= and + * sizes for direct memory access during event processing. + * + * Returns 0 on success, -1 on error + */ +static int extract_field_metadata(const struct btf *btf, struct bpf_monito= r_ctx *ctx) +{ + const struct btf_type *trace_type; + const struct btf_member *members; + int type_id, vlen; + + type_id =3D btf__find_by_name_kind(btf, RV_TRACE_STRUCT, BTF_KIND_STRUCT); + if (type_id <=3D 0) { + debug_msg("bpf: could not find struct '%s' in BTF\n", RV_TRACE_STRUCT); + return -1; + } + + trace_type =3D btf__type_by_id(btf, type_id); + if (!trace_type) { + debug_msg("bpf: could not get type for '%s'\n", RV_TRACE_STRUCT); + return -1; + } + + members =3D btf_members(trace_type); + vlen =3D btf_vlen(trace_type); + + for (int i =3D 0; i < vlen; i++) { + const char *name =3D btf__name_by_offset(btf, members[i].name_off); + size_t offset =3D btf_member_bit_offset(trace_type, i) / 8; + size_t size =3D btf__resolve_size(btf, members[i].type); + + if (!name || (ssize_t)size < 0) + continue; + + debug_msg("bpf: field '%s' at offset %zu, size %lld\n", name, + offset, (long long)size); + + for (int j =3D 0; j < FIELD_MAX; j++) { + if (strcmp(name, field_names[j]) =3D=3D 0) { + ctx->field_metadata[j].offset =3D offset; + ctx->field_metadata[j].size =3D size; + if (j =3D=3D FIELD_ID) + config.has_id =3D true; + break; + } + } + } + + return 0; +} + +/* + * bpf_print_header - print trace output header + */ +static void bpf_print_header(void) +{ + printf("%16s-%-8s %5s %5s ", "", "PID", "[CPU]", "TYPE"); + if (config.has_id) + printf(" %8s", "ID"); + + printf("%24s x %-24s -> %-24s %s\n", + "STATE", + "EVENT", + "NEXT_STATE", + "FINAL"); + + printf("%16s %-8s %5s %5s ", " | ", " | ", " | ", " | "); + + if (config.has_id) + printf(" %8s", " | "); + printf("%24s %-24s %-24s %s\n", " | ", " | ", " | ", "|"); +} + +static inline uint64_t read_field(uint64_t *entry, enum da_field_id id, + const uint8_t *raw, + const struct bpf_monitor_ctx *ctx) +{ + const struct da_field *field =3D &ctx->field_metadata[id]; + + switch (field->size) { + case 1: + return entry[id] =3D *(const uint8_t *)(raw + field->offset); + case 2: + return entry[id] =3D *(const uint16_t *)(raw + field->offset); + case 4: + return entry[id] =3D *(const uint32_t *)(raw + field->offset); + case 8: + return entry[id] =3D *(const uint64_t *)(raw + field->offset); + } + return 0; +} + +/* + * handle_event - ring buffer callback for trace events + */ +static int handle_event(void *ctx, void *data, size_t data_sz) +{ + struct bpf_monitor_ctx *mon_ctx =3D ctx; + const uint8_t *raw =3D data; + uint64_t entry[FIELD_MAX] =3D {0}; + const char *comm; + + if (should_stop()) + return 1; + + if (config.has_id) + read_field(entry, FIELD_ID, raw, mon_ctx); + read_field(entry, FIELD_PID, raw, mon_ctx); + + if (config.has_id && (config.my_pid =3D=3D entry[FIELD_ID])) + return 0; + else if (config.my_pid =3D=3D entry[FIELD_PID]) + return 0; + + read_field(entry, FIELD_EVENT_TYPE, raw, mon_ctx); + read_field(entry, FIELD_CPU, raw, mon_ctx); + comm =3D (const char *)(raw + mon_ctx->field_metadata[FIELD_COMM].offset); + read_field(entry, FIELD_CURR_STATE, raw, mon_ctx); + read_field(entry, FIELD_EVENT, raw, mon_ctx); + + printf("%16s-%-8"PRIu64" [%.3"PRIu64"] ", comm, entry[FIELD_PID], entry[F= IELD_CPU]); + if (entry[FIELD_EVENT_TYPE] =3D=3D RV_TRACE_ERROR) { + printf("error "); + if (config.has_id) + printf(" %8"PRIu64"", entry[FIELD_ID]); + printf(" %24s x %-24s\n", + get_state_name(mon_ctx, entry[FIELD_CURR_STATE]), + get_event_name(mon_ctx, entry[FIELD_EVENT])); + } else { + printf("event "); + read_field(entry, FIELD_IS_FINAL, raw, mon_ctx); + read_field(entry, FIELD_NEXT_STATE, raw, mon_ctx); + + if (config.has_id) + printf(" %8"PRIu64"", entry[FIELD_ID]); + printf(" %24s x %-24s -> %-24s %c\n", + get_state_name(mon_ctx, entry[FIELD_CURR_STATE]), + get_event_name(mon_ctx, entry[FIELD_EVENT]), + get_state_name(mon_ctx, entry[FIELD_NEXT_STATE]), + entry[FIELD_IS_FINAL] ? 'Y' : 'N'); + } + + return 0; +} + +/* + * extract_enum_names - extract names from a BTF enum + * + * Reads enum member names from BTF and stores them in dest array. + * Returns the number of enum members extracted (excluding the + * {state/event}_max_NAME entry and trimming the _NAME padding). + */ +static int extract_enum_names(const struct btf *btf, const char *enum_kind, + char dest[][MAX_DA_NAME_LEN], struct bpf_monitor_ctx *ctx) +{ + const struct btf_type *enum_type; + const struct btf_enum *enums; + char enum_name[64]; + int type_id, vlen; + int count =3D 0; + + snprintf(enum_name, sizeof(enum_name), "%ss_%s", enum_kind, ctx->monitor_= name); + type_id =3D btf__find_by_name_kind(btf, enum_name, BTF_KIND_ENUM); + if (type_id <=3D 0) { + err_msg("bpf: could not find enum '%s' in BTF\n", enum_name); + return -1; + } + enum_type =3D btf__type_by_id(btf, type_id); + if (!enum_type) { + err_msg("bpf: could not get enum type for '%s'\n", enum_name); + return -1; + } + + enums =3D btf_enum(enum_type); + vlen =3D btf_vlen(enum_type); + + snprintf(enum_name, sizeof(enum_name), "%s_max_%s", enum_kind, ctx->monit= or_name); + for (int i =3D 0; i < vlen && count < MAX_ENUMS; i++) { + const char *name =3D btf__name_by_offset(btf, enums[i].name_off); + size_t name_len; + const char *padding; + + if (!name || !strcmp(name, enum_name)) + continue; + + padding =3D strrchr(name, '_'); + name_len =3D strlen(name); + if (padding && !strcmp(ctx->monitor_name, padding + 1)) + name_len =3D (size_t)(padding - name); + + if (name_len >=3D MAX_DA_NAME_LEN) + name_len =3D MAX_DA_NAME_LEN - 1; + strncpy(dest[count], name, name_len); + dest[count][name_len] =3D '\0'; + count++; + } + + return count; +} + +/* + * extract_btf_info - extract BTF types information from the monitor + * + * Extract state and event names from enums using BTF and extract field + * offsets for flexible event parsing. + */ +static int extract_btf_info(struct bpf_object *obj, struct bpf_monitor_ctx= *ctx) +{ + const struct btf *btf; + + btf =3D bpf_object__btf(obj); + if (!btf) { + err_msg("bpf: no BTF found in BPF object\n"); + return -1; + } + + if (extract_field_metadata(btf, ctx)) { + err_msg("bpf: failed to extract field metadata\n"); + return -1; + } + + ctx->num_states =3D extract_enum_names(btf, "state", ctx->state_names, ct= x); + ctx->num_events =3D extract_enum_names(btf, "event", ctx->event_names, ct= x); + if (ctx->num_states < 0 || ctx->num_events < 0) { + err_msg("bpf: failed to extract states (%d) or events names (%d)\n", + ctx->num_states, ctx->num_events); + return -1; + } + + return 0; +} + +/* + * find_bpf_object - search for BPF monitor object file in all directories + */ +static int find_bpf_object(const char *monitor_name, char *path_out, size_= t path_len) +{ + char path[MAX_PATH]; + + bpf_fill_monitor_paths(); + for (int i =3D 0; bpf_monitor_paths[i][0]; i++) { + size_t size =3D snprintf(path, sizeof(path), "%s/%s.o", + bpf_monitor_paths[i], monitor_name); + + if (size < MAX_PATH && access(path, R_OK) =3D=3D 0) { + strncpy(path_out, path, path_len - 1); + path_out[path_len - 1] =3D '\0'; + return 1; + } + } + + return 0; +} + +/* + * bpf_setup_ring_buffer - set up the ring buffer to trace events + * + * Find the ring buffer map, set up the events handler, and consume any + * pending data to start fresh. + */ +static struct ring_buffer *bpf_setup_ring_buffer(struct bpf_object *obj, + struct bpf_monitor_ctx *ctx) +{ + struct ring_buffer *rb; + struct bpf_map *map; + char ringbuf_name[64]; + + if (extract_btf_info(obj, ctx)) + return NULL; + + snprintf(ringbuf_name, sizeof(ringbuf_name), "da_ringbuf_%s", ctx->monito= r_name); + map =3D bpf_object__find_map_by_name(obj, ringbuf_name); + if (!map) { + err_msg("bpf: error finding ring buffer %s\n", ringbuf_name); + return NULL; + } + + rb =3D ring_buffer__new(bpf_map__fd(map), handle_event, ctx, NULL); + if (!rb) { + err_msg("bpf: error opening ring buffer: %s\n", strerror(errno)); + return NULL; + } + + ring_buffer__consume(rb); + + return rb; +} + +/* + * reset_monitor_maps - clear all elements from monitor's maps + */ +static void reset_monitor_maps(struct bpf_object *obj) +{ + struct bpf_map *map; + bool err =3D false; + + bpf_object__for_each_map(map, obj) { + enum bpf_map_type type =3D bpf_map__type(map); + int value_size =3D bpf_map__value_size(map); + int fd =3D bpf_map__fd(map); + + if (fd < 0 || bpf_map__is_internal(map)) + continue; + + switch (type) { + case BPF_MAP_TYPE_HASH: + case BPF_MAP_TYPE_PERCPU_HASH: { + void *key =3D malloc(bpf_map__key_size(map)); + + if (!key) { + err =3D true; + break; + } + + while (!err && bpf_map_get_next_key(fd, NULL, key) =3D=3D 0) + err |=3D bpf_map_delete_elem(fd, key); + + free(key); + debug_msg("bpf: reset hash map %s\n", bpf_map__name(map)); + break; + } + + case BPF_MAP_TYPE_PERCPU_ARRAY: + /* + * Per-CPU maps require a buffer for all CPUs with each + * element padded to 8 bytes + */ + value_size =3D libbpf_num_possible_cpus() * + round_up(bpf_map__value_size(map), 8); + fallthrough; + case BPF_MAP_TYPE_ARRAY: { + uint32_t max_entries =3D bpf_map__max_entries(map); + void *zero_value =3D calloc(1, value_size); + + if (!zero_value) { + err =3D true; + break; + } + + for (uint32_t idx =3D 0; !err && idx < max_entries; idx++) + err |=3D bpf_map_update_elem(fd, &idx, zero_value, BPF_ANY); + + free(zero_value); + debug_msg("bpf: zeroed array map %s\n", bpf_map__name(map)); + break; + } + default: + } + } + if (err) + err_msg("bpf: errors during maps reset, continuing anyway.\n"); +} + +/* + * open_bpf_monitor - open and load a BPF monitor object + * + * If path is NULL, searches for the monitor by name. Otherwise uses the + * provided path directly. + * + * Returns loaded BPF object on success, NULL on error. + */ +static struct bpf_object *open_bpf_monitor(const char *monitor_name, const= char *path) +{ + struct bpf_object *obj =3D NULL; + char _path[MAX_PATH]; + int res; + + LIBBPF_OPTS(bpf_object_open_opts, opts, + .pin_root_path =3D BPF_PIN_BASE_PATH, + ); + + if (!path) { + if (!find_bpf_object(monitor_name, _path, sizeof(_path))) { + err_msg("bpf: error finding monitor %s\n", monitor_name); + return NULL; + } + path =3D _path; + } + + obj =3D bpf_object__open_file(path, &opts); + if (!obj) { + err_msg("bpf: error opening object file: %s\n", strerror(errno)); + return NULL; + } + + res =3D bpf_object__load(obj); + if (res) { + err_msg("bpf: error loading object file: %s\n", strerror(-res)); + return NULL; + } + + return obj; +} + +/* + * attach_bpf_handlers - attach and pin all BPF programs + * + * Attaches all non-struct_ops programs and stores links in the provided a= rray. + * Reuses existing pinned links when available. + * + * Returns number of attached programs on success, -1 on error. + */ +static int attach_bpf_handlers(const char *monitor_name, struct bpf_object= *obj, + struct bpf_link **links, int *link_count) +{ + struct bpf_program *prog; + int res =3D 0; + + bpf_object__for_each_program(prog, obj) { + struct bpf_link *link =3D NULL; + char pin_path[MAX_PATH]; + const char *prog_name; + bool reused =3D true; + + if (bpf_program__type(prog) =3D=3D BPF_PROG_TYPE_STRUCT_OPS) + continue; + + if (*link_count >=3D MAX_LINKS) { + err_msg("bpf: too many programs to attach (%d)\n", *link_count); + return -1; + } + + prog_name =3D bpf_program__name(prog); + snprintf(pin_path, sizeof(pin_path), "%s/%s_%s", + BPF_PIN_BASE_PATH, monitor_name, prog_name); + + if (access(pin_path, F_OK) =3D=3D 0) + link =3D bpf_link__open(pin_path); + if (!link) { + reused =3D false; + unlink(pin_path); + link =3D bpf_program__attach(prog); + if (!link) { + err_msg("bpf: error attaching program '%s': %s\n", + prog_name, strerror(errno)); + return -1; + } + } + links[(*link_count)++] =3D link; + + if (!reused) { + res =3D bpf_link__pin(link, pin_path); + if (res) { + err_msg("bpf: failed to pin link '%s': %s\n", + prog_name, strerror(-res)); + return -1; + } + } + } + return res; +} + +/* + * bpf_run_monitor - load and run a BPF monitor + * + * Returns 1 if monitor was found and executed, 0 if not found, -1 on error + */ +int bpf_run_monitor(char *monitor_name, int argc, char **argv) +{ + struct bpf_link *links[MAX_LINKS] =3D {0}; + struct bpf_monitor_ctx ctx =3D {0}; + struct ring_buffer *rb =3D NULL; + struct bpf_object *obj =3D NULL; + char structops_pin[MAX_PATH]; + int res, link_count =3D 0, retval =3D -1; + + /* If struct_ops is not registered this is not a BPF monitor */ + snprintf(structops_pin, sizeof(structops_pin), "%s/rv_%s_kern", + BPF_PIN_BASE_PATH, monitor_name); + if (access(structops_pin, F_OK) !=3D 0) + return 0; + + if (__ikm_read_enable(monitor_name) =3D=3D 1) { + err_msg("bpf: monitor %s (BPF) is already enabled\n", monitor_name); + return -1; + } + + strncpy(ctx.monitor_name, monitor_name, sizeof(ctx.monitor_name) - 1); + + res =3D parse_arguments(monitor_name, argc, argv); + if (res) + mon_usage(1, monitor_name, "bpf: failed parsing arguments"); + + ikm_set_reactor(monitor_name); + + libbpf_set_print(libbpf_print_fn); + + obj =3D open_bpf_monitor(monitor_name, NULL); + if (!obj) + goto cleanup; + + if (config.trace) { + rb =3D bpf_setup_ring_buffer(obj, &ctx); + if (!rb) + goto cleanup; + } + + reset_monitor_maps(obj); + + res =3D attach_bpf_handlers(monitor_name, obj, links, &link_count); + if (res < 0) + goto cleanup; + + res =3D ikm_enable(monitor_name); + if (res < 0) { + err_msg("bpf: error enabling the monitor: %s\n", monitor_name); + goto cleanup; + } + + if (config.trace) + bpf_print_header(); + + while (!should_stop()) { + if (!config.trace) { + sleep(1); + continue; + } + res =3D ring_buffer__poll(rb, 100); + if (res =3D=3D -EINTR) + break; + if (res < 0) { + err_msg("bpf: error polling ring buffer: %s\n", strerror(-res)); + goto cleanup; + } + } + retval =3D 1; + +cleanup: + ikm_disable(monitor_name); + reset_monitor_maps(obj); + ikm_reset_reactor(monitor_name); + + for (int i =3D 0; i < link_count; i++) { + bpf_link__unpin(links[i]); + bpf_link__destroy(links[i]); + } + + if (config.trace) + ring_buffer__free(rb); + + bpf_object__close(obj); + + return retval; +} diff --git a/tools/verification/rv/src/rv.c b/tools/verification/rv/src/rv.c index 09e0d8598619..e957e45ee2b1 100644 --- a/tools/verification/rv/src/rv.c +++ b/tools/verification/rv/src/rv.c @@ -13,6 +13,7 @@ #include #include #include +#include =20 static int stop_session; =20 @@ -123,7 +124,10 @@ static void rv_mon(int argc, char **argv) * Call all possible monitor implementations, looking * for the [monitor]. */ - run +=3D ikm_run_monitor(monitor_name, argc-1, &argv[1]); + run +=3D bpf_run_monitor(monitor_name, argc-1, &argv[1]); + + if (!run) + run +=3D ikm_run_monitor(monitor_name, argc-1, &argv[1]); =20 if (!run) err_msg("rv: monitor %s does not exist\n", monitor_name); --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 79C0B3DAAD9 for ; Mon, 31 Aug 2026 09:08:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167284; cv=none; b=tUlBE1DxlxfH/B83fV8zcjyStJfTf/KFoAhk8RvXYrafVootnADbQ+fosJrmFiQeWRsL4Tpt4K6oq87lui3IcJdzGYBEryPUpUvoluZSN98GJ1UWW2HliFR8XNSTFLRU/GtVjRrGcGk3OxQsrxauxPtEGyLD+mmcr8c8Ey/4bsA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167284; c=relaxed/simple; bh=9TuIq3wJtcCMx9IPEWJoDwyQnj7w/CXofFuvtgGhiZ4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=n2ojguj81c80sJx2TSmbp75KMebwKEXnvTSxYLBLRU+alb/BsD2x+OmoBoLaNrXkcneBpBqFNixwOXhUtoWPXepGrtbk4ZztIja9H5mi+h/G6itZQSt/BlopracpJL7UNCyix+iAHwVlcayJWZ74xUEuoJrnCLZMXr1sDHYBzUY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=C1+0RMrL; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="C1+0RMrL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167280; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3Gn6KUnO72LwEsrI5QgHpm6UHRTiVPqLtbbYl9Aw8D4=; b=C1+0RMrLdh4mpquNVZ/WUeFFeIMEixCZoS0++jC/9LVwZ7Wo+BehoZB6Gl3ag0VX0Asjt5 CfzHbcpyki78Jh307XxScKkYyudWe3ZXxRH3Wq26S477LVizd9QxsRolBCY8AZ/g4L7U03 93m7o9kDoqVdMNdE9jmNnwV+Tf5lUoY= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-473-MW5EDFuLN2uHpyHmxO_gmg-1; Mon, 31 Aug 2026 05:07:54 -0400 X-MC-Unique: MW5EDFuLN2uHpyHmxO_gmg-1 X-Mimecast-MFC-AGG-ID: MW5EDFuLN2uHpyHmxO_gmg_1788167273 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 854471944A92; Mon, 31 Aug 2026 09:07:53 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9E94D180034F; Mon, 31 Aug 2026 09:07:50 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 14/20] tools/rv: Implement BPF monitor registration logic Date: Mon, 31 Aug 2026 11:05:18 +0200 Message-ID: <20260831090524.106845-15-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add support for registering and unregistering BPF monitors from userspace via the struct_ops mechanism. The implementation scans known paths for BPF monitor objects, loads them, and attaches their struct_ops maps. After registration, BPF monitors appear as normal in-kernel monitors the RV sysfs interface works seamlessly (besides tracepoints!). Signed-off-by: Gabriele Monaco --- tools/verification/rv/include/bpf_monitor.h | 7 + tools/verification/rv/src/bpf_monitor.c | 338 ++++++++++++++++++++ tools/verification/rv/src/rv.c | 4 + 3 files changed, 349 insertions(+) diff --git a/tools/verification/rv/include/bpf_monitor.h b/tools/verificati= on/rv/include/bpf_monitor.h index 60ce23589102..beb98b63c5f8 100644 --- a/tools/verification/rv/include/bpf_monitor.h +++ b/tools/verification/rv/include/bpf_monitor.h @@ -4,11 +4,18 @@ =20 #ifdef HAVE_LIBBPF int bpf_run_monitor(char *monitor_name, int argc, char **argv); +void rv_bpf(int argc, char **argv); #else static inline int bpf_run_monitor(char *monitor_name, int argc, char **arg= v) { return 0; } + +static inline void rv_bpf(int argc, char **argv) +{ + fprintf(stderr, "rv: BPF support not compiled in\n"); + exit(1); +} #endif /* HAVE_LIBBPF */ =20 #endif diff --git a/tools/verification/rv/src/bpf_monitor.c b/tools/verification/r= v/src/bpf_monitor.c index e13ae35678cb..7e24a71dfac7 100644 --- a/tools/verification/rv/src/bpf_monitor.c +++ b/tools/verification/rv/src/bpf_monitor.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -679,3 +680,340 @@ int bpf_run_monitor(char *monitor_name, int argc, cha= r **argv) =20 return retval; } + +/* + * register_monitor_from_file - register a single BPF monitor via struct_o= ps + * + * Opens, loads, and attaches a BPF monitor's struct_ops map, then pins the + * resulting link. + * + * Returns 0 on success, -1 on error + */ +static int register_monitor_from_file(const char *path, const char *name) +{ + struct bpf_object *obj =3D NULL; + struct bpf_link *link =3D NULL; + struct bpf_map *map; + char map_name[MAX_DA_NAME_LEN + 8]; + char pin_path[MAX_PATH]; + int res, retval =3D -1; + + obj =3D open_bpf_monitor(name, path); + if (!obj) + goto cleanup; + + snprintf(map_name, sizeof(map_name), "rv_%s_kern", name); + map =3D bpf_object__find_map_by_name(obj, map_name); + if (!map) { + err_msg("bpf: error finding struct_ops map for %s\n", name); + goto cleanup; + } + + link =3D bpf_map__attach_struct_ops(map); + if (!link) { + err_msg("bpf: error attaching struct_ops for %s: %s\n", + name, strerror(errno)); + goto cleanup; + } + + snprintf(pin_path, sizeof(pin_path), "%s/%s", BPF_PIN_BASE_PATH, map_name= ); + res =3D bpf_link__pin(link, pin_path); + if (res) { + err_msg("bpf: error pinning link for %s: %s\n", + name, strerror(-res)); + goto cleanup; + } + + debug_msg("bpf: registered %s\n", name); + retval =3D 0; + +cleanup: + bpf_link__destroy(link); + bpf_object__close(obj); + + return retval; +} + +/* + * register_monitors_from_path - register all BPF monitors from a path + * + * Scans directory for *.o files and registers each one via struct_ops. + * + * Returns number of monitors registered from this path + */ +static int register_monitors_from_path(const char *path, bool *error) +{ + struct dirent *entry; + DIR *dir; + char *ext; + int count =3D 0; + + dir =3D opendir(path); + if (!dir) + return 0; + + while ((entry =3D readdir(dir)) !=3D NULL) { + char name[MAX_DA_NAME_LEN], mon_path[MAX_PATH]; + size_t size; + + if (entry->d_name[0] =3D=3D '.') + continue; + + ext =3D strrchr(entry->d_name, '.'); + if (!ext || strcmp(ext, ".o") !=3D 0) + continue; + + size =3D snprintf(mon_path, sizeof(mon_path), "%s/%s", + path, entry->d_name); + if (size >=3D MAX_PATH) { + err_msg("bpf: path too long: %s/%s\n", path, entry->d_name); + *error =3D true; + continue; + } + + strncpy(name, entry->d_name, sizeof(name) - 1); + name[sizeof(name) - 1] =3D '\0'; + ext =3D strrchr(name, '.'); + if (ext) + *ext =3D '\0'; + + if (register_monitor_from_file(mon_path, name) =3D=3D 0) + count++; + else + *error =3D true; + } + + closedir(dir); + return count; +} + +/* + * bpf_struct_ops_supported - check if the kernel supports BPF monitors + */ +static bool bpf_struct_ops_supported(void) +{ + struct btf *btf; + int type_id; + + btf =3D btf__load_vmlinux_btf(); + if (!btf) + return false; + + type_id =3D btf__find_by_name_kind(btf, "bpf_struct_ops_rv_monitor", BTF_= KIND_STRUCT); + btf__free(btf); + + if (type_id <=3D 0) + return false; + + return true; +} + +/* + * bpf_register_monitors - register all BPF monitors via struct_ops + * + * Scans known paths for BPF monitor objects, loads them, and attaches the= ir + * struct_ops maps. The resulting links are pinned so monitors remain + * registered with the kernel RV subsystem even after this process exits. + * + * Returns command exit status (SUCCESS/FAILURE) + */ +static int bpf_register_monitors(void) +{ + int count =3D 0; + bool error =3D false; + + bpf_fill_monitor_paths(); + + for (int i =3D 0; bpf_monitor_paths[i][0]; i++) + count +=3D register_monitors_from_path(bpf_monitor_paths[i], &error); + + printf("registered %d BPF monitor(s)\n", count); + + return error ? EXIT_FAILURE : EXIT_SUCCESS; +} + +/* + * is_struct_ops - return true if d_name matches rv__kern + * + * Also store in name_out when returning true. + */ +static bool is_struct_ops(char *d_name, char *name_out) +{ + const int rvlen =3D strlen("rv_"), kernlen =3D strlen("_kern"); + int len =3D strlen(d_name); + + if (len > rvlen + kernlen && !strncmp(d_name, "rv_", rvlen) && + !strcmp(d_name + len - kernlen, "_kern")) { + len -=3D rvlen + kernlen; + if (name_out) { + if (len >=3D MAX_DA_NAME_LEN) + len =3D MAX_DA_NAME_LEN - 1; + strncpy(name_out, d_name + rvlen, len); + name_out[len] =3D '\0'; + } + return true; + } + return false; +} + +enum unregister_pass { + CHECK_ACTIVE, + UNLINK_HANDLERS, + UNLINK_STRUCT_OPS, + MAX_PASSES, +}; + +/* + * bpf_unregister_monitors - unregister all BPF monitors + * + * Removes all pinned links and maps from BPF_PIN_BASE_PATH, including the + * struct_ops. This unregisters the monitors from the RV subsystem and cle= ans + * up all associated resources. + * + * First iterate over the directory to check if any BPF monitor is active, + * this is best effort. Then unlink all handlers and at last all struct_op= s. + * + * Returns command exit status (SUCCESS/FAILURE) + */ +static int bpf_unregister_monitors(void) +{ + struct dirent *entry; + DIR *dir; + int count =3D 0; + + dir =3D opendir(BPF_PIN_BASE_PATH); + if (!dir) { + err_msg("bpf: cannot open %s: %s\n", + BPF_PIN_BASE_PATH, strerror(errno)); + return EXIT_FAILURE; + } + + for (int pass =3D CHECK_ACTIVE; pass < MAX_PASSES; pass++) { + rewinddir(dir); + while ((entry =3D readdir(dir)) !=3D NULL) { + char pin_path[MAX_PATH]; + char mon_name[MAX_DA_NAME_LEN]; + int is_ops; + + if (entry->d_name[0] =3D=3D '.') + continue; + + is_ops =3D is_struct_ops(entry->d_name, mon_name); + + switch (pass) { + case CHECK_ACTIVE: + if (is_ops && __ikm_read_enable(mon_name) =3D=3D 1) { + err_msg("bpf: monitor %s is enabled, cannot unregister\n", + mon_name); + closedir(dir); + return EXIT_FAILURE; + } + continue; + case UNLINK_HANDLERS: + if (is_ops) + continue; + fallthrough; + case UNLINK_STRUCT_OPS: + snprintf(pin_path, sizeof(pin_path), "%s/%s", + BPF_PIN_BASE_PATH, entry->d_name); + + if (unlink(pin_path)) { + err_msg("bpf: failed to unlink %s: %s\n", pin_path, + strerror(errno)); + } else if (is_ops) { + count++; + debug_msg("bpf: unregistered %s\n", mon_name); + } + break; + } + } + } + + closedir(dir); + + printf("unregistered %d BPF monitor(s)\n", count); + return EXIT_SUCCESS; +} + +/* + * rv_bpf - handle BPF monitor registration commands + */ +void rv_bpf(int argc, char **argv) +{ + static const char *const usage[] =3D { + "", + " usage: rv bpf [-h] [-v] {register,unregister}", + "", + "\tmanage BPF monitor registration", + "", + "\t-h/--help: print this menu", + "\t-v/--verbose: print debug messages", + "", + "\tregister: register all available BPF monitors", + "\tunregister: unregister all BPF monitors", + NULL, + }; + int print_help =3D 0, retval =3D EXIT_SUCCESS; + + while (1) { + static struct option long_options[] =3D { + {"help", no_argument, 0, 'h'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + int option_index =3D 0; + int c =3D getopt_long(argc, argv, "hv", long_options, &option_index); + + /* detect the end of the options */ + if (c =3D=3D -1) + break; + + switch (c) { + case 'h': + print_help =3D 1; + retval =3D EXIT_SUCCESS; + break; + case 'v': + config.debug =3D 1; + break; + default: + print_help =3D 1; + retval =3D EXIT_FAILURE; + break; + } + } + + /* requires at least one argument after options */ + if (optind >=3D argc && !print_help) { + print_help =3D 1; + retval =3D EXIT_FAILURE; + } + + if (print_help) { + fprintf(stderr, "rv version %s\n", VERSION); + for (int i =3D 0; usage[i]; i++) + fprintf(stderr, "%s\n", usage[i]); + exit(retval); + } + + if (!bpf_struct_ops_supported()) { + err_msg("bpf: kernel does not support BPF monitors\n"); + exit(EXIT_FAILURE); + } + + if (!strcmp(argv[optind], "register")) { + retval =3D bpf_register_monitors(); + exit(retval); + } + + if (!strcmp(argv[optind], "unregister")) { + retval =3D bpf_unregister_monitors(); + exit(retval); + } + + /* invalid sub-command */ + fprintf(stderr, "rv version %s\n", VERSION); + for (int i =3D 0; usage[i]; i++) + fprintf(stderr, "%s\n", usage[i]); + exit(EXIT_FAILURE); +} diff --git a/tools/verification/rv/src/rv.c b/tools/verification/rv/src/rv.c index e957e45ee2b1..3e6e5e786746 100644 --- a/tools/verification/rv/src/rv.c +++ b/tools/verification/rv/src/rv.c @@ -149,6 +149,7 @@ static void usage(int exit_val, const char *fmt, ...) " command: run one of the following command:", " list: list all available monitors", " mon: run a monitor", + " bpf: manage BPF monitors registration", "", " [command options]: each command has its own set of options", " run rv command -h for further information", @@ -189,6 +190,9 @@ int main(int argc, char **argv) if (!strcmp(argv[1], "list")) rv_list(--argc, &argv[1]); =20 + if (!strcmp(argv[1], "bpf")) + rv_bpf(argc - 1, &argv[1]); + if (!strcmp(argv[1], "mon")) { /* * monitor's main should monitor should_stop() function. --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CBC7F31194C for ; Mon, 31 Aug 2026 09:08:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167285; cv=none; b=apQjttywYFGCAD0HN1c7PKBzgXdJWNZuRpSTd4ajjxDS++O5ptxLGMyhyP0Z7plJcWgIegy9gaghDkq73jwX4H9iYzdSrAWCeYE24BBDNhsoJHdygb9P7UPRg2cHe4oNaFOShQRFuKBF5hJO6YkIgtRxtowkpd9xE8Hn2WsjM+U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167285; c=relaxed/simple; bh=FTrTAjgbEPiB3dcqQvf9b9uX941Z63zFqOYQnxzO63w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q781Sz7EaCSdcYw5Gb1r+UJiHYHmvHaoaqym5K0minOoqINF0Gyw+9VFHzjbGqU1eYDeEXVxmO0/x2NTC5hBN/grmJS3vshBMeE2r6cpZie1CHzzuaflOXZ2bFIh4FoxMVZd4hxBS3LQQXrEDyURa+Mqn2sLFgHxvrWQ+YQPIeA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=dfkZ6HGO; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="dfkZ6HGO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167282; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZW/lx6DUV16jrQ8XfWDIKuBRm3R/7XC0QoFfh8n8doM=; b=dfkZ6HGOd0R4R5Iejn8PtkavWNPqf0RYUItHI2prLulq1l/k4YyhU/PWvb0kSC8ZaUs8/6 a3zRChtlXgVwrFu6WJFfWOn6zAhJ8xb2OA/+ipNjXcIDGr1iujumAR56x12no/pVec49fp nyFzwGIa1O6jzrwhMbI0yIUrhlQPbCs= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-374-jgjeStvFMpe7PCboyesNeA-1; Mon, 31 Aug 2026 05:07:58 -0400 X-MC-Unique: jgjeStvFMpe7PCboyesNeA-1 X-Mimecast-MFC-AGG-ID: jgjeStvFMpe7PCboyesNeA_1788167277 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8201D1954B11; Mon, 31 Aug 2026 09:07:57 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9D4C618005BB; Mon, 31 Aug 2026 09:07:54 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 15/20] tools/rv: Copy stripped bpf_atomic.h from libarena Date: Mon, 31 Aug 2026 11:05:19 +0200 Message-ID: <20260831090524.106845-16-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add bpf_atomic.h including atomic read/write macros like READ_ONCE() and try_cmpxchg(). This version is a stripped down copy of the one currently present in selftests/bpf/libarena. Signed-off-by: Gabriele Monaco --- .../verification/rv/bpf_monitors/bpf_atomic.h | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tools/verification/rv/bpf_monitors/bpf_atomic.h diff --git a/tools/verification/rv/bpf_monitors/bpf_atomic.h b/tools/verifi= cation/rv/bpf_monitors/bpf_atomic.h new file mode 100644 index 000000000000..f834ea91c9d3 --- /dev/null +++ b/tools/verification/rv/bpf_monitors/bpf_atomic.h @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ +#ifndef BPF_ATOMIC_H +#define BPF_ATOMIC_H + +#include +#include + +extern bool CONFIG_X86_64 __kconfig __weak; + +/* + * __unqual_typeof(x) - Declare an unqualified scalar type, leaving + * non-scalar types unchanged, + * + * Prefer C11 _Generic for better compile-times and simpler code. Note: 'c= har' + * is not type-compatible with 'signed char', and we define a separate cas= e. + * + * This is copied verbatim from kernel's include/linux/compiler_types.h, b= ut + * with default expression (for pointers) changed from (x) to (typeof(x)0). + * + * This is because LLVM has a bug where for lvalue (x), it does not get ri= d of + * an extra address_space qualifier, but does in case of rvalue (typeof(x)= 0). + * Hence, for pointers, we need to create an rvalue expression to get the + * desired type. See https://github.com/llvm/llvm-project/issues/53400. + */ +#define __scalar_type_to_expr_cases(type) \ + unsigned type : (unsigned type)0, signed type : (signed type)0 + +#define __unqual_typeof(x) \ + typeof(_Generic((x), \ + char: (char)0, \ + __scalar_type_to_expr_cases(char), \ + __scalar_type_to_expr_cases(short), \ + __scalar_type_to_expr_cases(int), \ + __scalar_type_to_expr_cases(long), \ + __scalar_type_to_expr_cases(long long), \ + default: (typeof(x))0)) + +/* No-op for BPF */ +#define cpu_relax() ({}) + +#define READ_ONCE(x) (*(volatile typeof(x) *)&(x)) + +#ifndef WRITE_ONCE +#define WRITE_ONCE(x, val) ((*(volatile typeof(x) *)&(x)) =3D (val)) +#endif + +#define cmpxchg(p, old, new) __sync_val_compare_and_swap((p), old, new) + +#define try_cmpxchg(p, pold, new) \ + ({ \ + __unqual_typeof(*(pold)) __o =3D *(pold); \ + __unqual_typeof(*(p)) __r =3D cmpxchg(p, __o, new); \ + if (__r !=3D __o) \ + *(pold) =3D __r; \ + __r =3D=3D __o; \ + }) + +#define try_cmpxchg_relaxed(p, pold, new) try_cmpxchg(p, pold, new) + +#define try_cmpxchg_acquire(p, pold, new) try_cmpxchg(p, pold, new) + +#define smp_mb() \ + ({ \ + volatile unsigned long __val; \ + __sync_fetch_and_add(&__val, 0); \ + }) + +#define smp_rmb() \ + ({ \ + if (!CONFIG_X86_64) \ + smp_mb(); \ + else \ + barrier(); \ + }) + +#define smp_wmb() \ + ({ \ + if (!CONFIG_X86_64) \ + smp_mb(); \ + else \ + barrier(); \ + }) + +/* Control dependency provides LOAD->STORE, provide LOAD->LOAD */ +#define smp_acquire__after_ctrl_dep() ({ smp_rmb(); }) + +#define smp_load_acquire(p) \ + ({ \ + __unqual_typeof(*(p)) __v =3D READ_ONCE(*(p)); \ + if (!CONFIG_X86_64) \ + smp_mb(); \ + barrier(); \ + __v; \ + }) + +#define smp_store_release(p, val) \ + ({ \ + if (!CONFIG_X86_64) \ + smp_mb(); \ + barrier(); \ + WRITE_ONCE(*(p), val); \ + }) + +#endif /* BPF_ATOMIC_H */ --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 096673DAAD9 for ; Mon, 31 Aug 2026 09:08:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167293; cv=none; b=iNSYJFZsq0oXzlsLSczfhG3jxuSgsrOzR87XAkL4MdgoA+xJtf2xDbs5pglljb/ehVQpKtKZRERm80Gu6KHEwYNnxP/kl7j3Tbv48kh2mTQv4TTTJmxAqQDNdh3nOJ1qXabVdbXU1lXOiBcO7GVDBRNiOR9+rUVL4bx+B+mHam8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167293; c=relaxed/simple; bh=IIzjq26ynBk+9gurYoQZnZz5kkfRbRZrXQS7SBBvTGc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sR2V/zC22lnP0xFKCZipRIy0T8I1iib3GC+qt9Jcq6WX5SWFsgvO5SVjMAoDDtm5NOP9pzNYw09VGahkwiQKon5R+Fo7l1CxtzTpC4SDDcKv0HuXdG50w1qdsXcy0wZO3geTKkM1cIY/aB2PJ4vghyqR+H94y5He3ZGz4G9FpFU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=F7D/Jp9F; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="F7D/Jp9F" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167289; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8enAaYlbOjsQYEkEXA5I6d8WEuohtQB634sOCHnSKr0=; b=F7D/Jp9FmV1dqK8ynl65HhmUonsTviu0tgtRj1dKeHBTUamMah7PudQnZrblKGkBrQS9XI uVe04Fnx0HLl5ON9Jybmn1kY4WcOqHOiVEVxtjjpJN/hfdLwdRHG+/W0Yd6DOLAj90+KND LD2EvQHAicMyckDz3QEaS2DSfUbh1k4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-577-qtoY_nVxPXabpiHsLF6jfQ-1; Mon, 31 Aug 2026 05:08:04 -0400 X-MC-Unique: qtoY_nVxPXabpiHsLF6jfQ-1 X-Mimecast-MFC-AGG-ID: qtoY_nVxPXabpiHsLF6jfQ_1788167283 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0F1F219540E2; Mon, 31 Aug 2026 09:08:03 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 29C9418005BB; Mon, 31 Aug 2026 09:07:59 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 16/20] tools/rv: Add BPF monitors Date: Mon, 31 Aug 2026 11:05:20 +0200 Message-ID: <20260831090524.106845-17-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add the code for 2 initial BPF monitors, both DA (the only currently supported type): * queue: per-task monitor stating tasks alternate enqueue and dequeue. * nohz: per-cpu monitor stating the scheduler tick don't run when stopped and can run only after being resumed. BPF monitors can include the in-kernel da_monitor.h, which is now adapted to share as much common code and conditionally compile what needs to be BPF or kernel specific. Integrate BPF monitor building into main rv Makefile, if all tools are available on the system. Signed-off-by: Gabriele Monaco --- include/rv/da_monitor.h | 27 +- tools/verification/models/nohz.dot | 16 + tools/verification/models/tqueue.dot | 15 + tools/verification/rv/Makefile | 43 +- tools/verification/rv/Makefile.config | 26 ++ tools/verification/rv/Makefile.rv | 5 + tools/verification/rv/bpf_monitors/.gitignore | 2 + .../rv/bpf_monitors/da_monitor_bpf.h | 400 ++++++++++++++++++ tools/verification/rv/bpf_monitors/nohz.c | 47 ++ tools/verification/rv/bpf_monitors/nohz.h | 49 +++ tools/verification/rv/bpf_monitors/tqueue.c | 35 ++ tools/verification/rv/bpf_monitors/tqueue.h | 47 ++ 12 files changed, 702 insertions(+), 10 deletions(-) create mode 100644 tools/verification/models/nohz.dot create mode 100644 tools/verification/models/tqueue.dot create mode 100644 tools/verification/rv/bpf_monitors/.gitignore create mode 100644 tools/verification/rv/bpf_monitors/da_monitor_bpf.h create mode 100644 tools/verification/rv/bpf_monitors/nohz.c create mode 100644 tools/verification/rv/bpf_monitors/nohz.h create mode 100644 tools/verification/rv/bpf_monitors/tqueue.c create mode 100644 tools/verification/rv/bpf_monitors/tqueue.h diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h index 7f0bdfd7cce3..a02837c4110d 100644 --- a/include/rv/da_monitor.h +++ b/include/rv/da_monitor.h @@ -14,14 +14,19 @@ #ifndef _RV_DA_MONITOR_H #define _RV_DA_MONITOR_H =20 -#include -#include +#ifndef __BPF__ +/* Kernel includes */ #include -#include #include #include #include #include +#endif /* __BPF__ */ + +#include +#include +#include +#include =20 /* * Per-cpu variables require a unique name although static in some @@ -29,8 +34,6 @@ */ #define DA_MON_NAME CONCATENATE(da_mon_, MONITOR_NAME) =20 -static struct rv_monitor rv_this; - /* * Hook to allow the implementation of hybrid automata: define it with a * function that takes curr_state, event and next_state and returns true i= f the @@ -77,6 +80,12 @@ static struct rv_monitor rv_this; #define da_id_type int #endif =20 +#ifdef __BPF__ +#include "da_monitor_bpf.h" +#else +static struct rv_monitor rv_this; +#endif + static void react(enum states curr_state, enum events event) { rv_react(&rv_this, @@ -128,6 +137,7 @@ static inline bool da_monitoring(struct da_monitor *da_= mon) return smp_load_acquire(&da_mon->monitoring); } =20 +#ifndef __BPF__ /* * da_monitor_enabled - checks if the monitor is enabled */ @@ -143,6 +153,7 @@ static inline bool da_monitor_enabled(void) =20 return 1; } +#endif =20 /* * da_monitor_handling_event - checks if the monitor is ready to handle ev= ents @@ -159,6 +170,7 @@ static inline bool da_monitor_handling_event(struct da_= monitor *da_mon) return 1; } =20 +#ifndef __BPF__ #if RV_MON_TYPE =3D=3D RV_MON_GLOBAL /* * Functions to define, init and get a global monitor. @@ -685,6 +697,7 @@ static inline void da_trace_error(struct da_monitor *da= _mon, model_get_event_name(event)); } #endif /* RV_MON_TYPE */ +#endif /* __BPF__ */ =20 /* * da_event - handle an event for the da_mon @@ -806,7 +819,7 @@ static inline bool da_handle_start_run_event(enum event= s event) return __da_handle_start_run_event(da_get_monitor(), event, 0); } =20 -#elif RV_MON_TYPE =3D=3D RV_MON_PER_TASK +#elif !defined(__BPF__) && RV_MON_TYPE =3D=3D RV_MON_PER_TASK /* * Handle event for per task. */ @@ -847,7 +860,7 @@ static inline bool da_handle_start_run_event(struct tas= k_struct *tsk, return __da_handle_start_run_event(da_get_monitor(tsk), event, tsk->pid); } =20 -#elif RV_MON_TYPE =3D=3D RV_MON_PER_OBJ +#elif !defined(__BPF__) && RV_MON_TYPE =3D=3D RV_MON_PER_OBJ /* * Handle event for per object. */ diff --git a/tools/verification/models/nohz.dot b/tools/verification/models= /nohz.dot new file mode 100644 index 000000000000..49adb25e32d8 --- /dev/null +++ b/tools/verification/models/nohz.dot @@ -0,0 +1,16 @@ +digraph state_automaton { + {node [shape =3D circle] "stopped"}; + {node [shape =3D plaintext, style=3Dinvis, label=3D""] "__init_running"}; + {node [shape =3D doublecircle] "running"}; + {node [shape =3D circle] "running"}; + "__init_running" -> "running"; + "stopped" [label =3D "stopped"]; + "stopped" -> "running" [ label =3D "tick_restart" ]; + "running" [label =3D "running"]; + "running" -> "running" [ label =3D "sched_tick" ]; + "running" -> "stopped" [ label =3D "tick_stop" ]; + { rank =3D min ; + "__init_running"; + "running"; + } +} diff --git a/tools/verification/models/tqueue.dot b/tools/verification/mode= ls/tqueue.dot new file mode 100644 index 000000000000..7aadf99ed29d --- /dev/null +++ b/tools/verification/models/tqueue.dot @@ -0,0 +1,15 @@ +digraph state_automaton { + {node [shape =3D circle] "enqueued"}; + {node [shape =3D plaintext, style=3Dinvis, label=3D""] "__init_dequeued"}; + {node [shape =3D doublecircle] "dequeued"}; + {node [shape =3D circle] "dequeued"}; + "__init_dequeued" -> "dequeued"; + "enqueued" [label =3D "enqueued"]; + "enqueued" -> "dequeued" [ label =3D "sched_dequeue" ]; + "dequeued" [label =3D "dequeued"]; + "dequeued" -> "enqueued" [ label =3D "sched_enqueue" ]; + { rank =3D min ; + "__init_dequeued"; + "dequeued"; + } +} diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile index af83566b930c..bdd28dc1fd2f 100644 --- a/tools/verification/rv/Makefile +++ b/tools/verification/rv/Makefile @@ -35,9 +35,13 @@ DOCSRC :=3D ../../../Documentation/tools/rv/ FEATURE_TESTS :=3D libtraceevent FEATURE_TESTS +=3D libtracefs FEATURE_TESTS +=3D libbpf +FEATURE_TESTS +=3D clang-bpf-co-re +FEATURE_TESTS +=3D bpftool-btf FEATURE_DISPLAY :=3D libtraceevent FEATURE_DISPLAY +=3D libtracefs FEATURE_DISPLAY +=3D libbpf +FEATURE_DISPLAY +=3D clang-bpf-co-re +FEATURE_DISPLAY +=3D bpftool-btf =20 all: $(RV) =20 @@ -45,7 +49,7 @@ include $(srctree)/tools/build/Makefile.include include Makefile.rv =20 # check for dependencies only on required targets -NON_CONFIG_TARGETS :=3D clean install doc doc_clean doc_install +NON_CONFIG_TARGETS :=3D clean install doc doc_clean doc_install bpf =20 config :=3D 1 ifdef MAKECMDGOALS @@ -70,19 +74,52 @@ static: $(RV_IN) $(eval LDFLAGS +=3D -static) $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RV)-static $(RV_IN) $(EXTLIBS) =20 +BPF_DIR :=3D bpf_monitors +BPF_SOURCES :=3D $(wildcard $(BPF_DIR)/*.c) +BPF_OBJECTS :=3D $(BPF_SOURCES:.c=3D.o) +VMLINUX_H :=3D $(BPF_DIR)/vmlinux.h + +BPF_INCLUDES :=3D -I$(srctree)/tools/lib +BPF_INCLUDES +=3D -I$(srctree)/include/uapi +BPF_INCLUDES +=3D -I$(srctree)/include +BPF_INCLUDES +=3D -I$(BPF_DIR) + +BPF_CFLAGS :=3D -g -O2 -target bpf -MMD -MP $(BPF_INCLUDES) +BPF_CFLAGS +=3D -Wall -Wno-unused-function -Wno-missing-declarations + +VMLINUX :=3D ../../../vmlinux +VMLINUX_BTF ?=3D $(if $(wildcard $(VMLINUX)) , $(VMLINUX), /sys/kernel/btf= /vmlinux) + +$(VMLINUX_H): $(VMLINUX_BTF) + $(QUIET_GEN)$(SYSTEM_BPFTOOL) btf dump file $< format c > $@ + +$(BPF_DIR)/%.o: $(BPF_DIR)/%.c $(VMLINUX_H) + $(QUIET_CLANG)$(CLANG) $(BPF_CFLAGS) -c $< -o $@ + $(Q)$(LLVM_STRIP) -g $@ + $(Q)$(LLVM_OBJCOPY) --remove-section=3D.rel.rodata $@ + +-include $(BPF_SOURCES:.c=3D.d) + +bpf: $(BPF_OBJECTS) + rv.%: fixdep FORCE make -f $(srctree)/tools/build/Makefile.build dir=3D. $@ =20 $(RV_IN): fixdep FORCE make $(build)=3Drv =20 +ifeq ($(BUILD_BPF_OBJS),1) +all: bpf +endif + clean: doc_clean fixdep-clean $(call QUIET_CLEAN, rv) - $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d= ' -delete + $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '*.d' = -delete $(Q)rm -f rv rv-static fixdep FEATURE-DUMP rv-* + $(Q)rm -f $(VMLINUX_H) $(Q)rm -rf feature =20 check: $(RV) RV=3D$(RV) prove -o --directives -f tests/ =20 -.PHONY: FORCE clean check +.PHONY: FORCE clean check bpf diff --git a/tools/verification/rv/Makefile.config b/tools/verification/rv/= Makefile.config index 0600170ac217..1caad39ab0c9 100644 --- a/tools/verification/rv/Makefile.config +++ b/tools/verification/rv/Makefile.config @@ -66,6 +66,32 @@ ifeq ($(BUILD_BPF),1) $(call lib_setup,bpf) endif =20 +# Building BPF monitors requires clang and bpftool, RV with BPF monitors +# support can still run without building monitors +ifndef BUILD_BPF_OBJS + BUILD_BPF_OBJS :=3D $(BUILD_BPF) +endif + +ifeq ($(BUILD_BPF_OBJS),1) + $(call feature_check,clang-bpf-co-re) + ifeq ($(feature-clang-bpf-co-re), 1) + $(call detected,CONFIG_CLANG_BPF_CO_RE) + else + $(info clang is missing or does not support BPF CO-RE, cannot build BP= F monitors.) + $(info Please install clang) + BUILD_BPF_OBJS :=3D 0 + endif + + $(call feature_check,bpftool-btf) + ifeq ($(feature-bpftool-btf), 1) + $(call detected,CONFIG_BPFTOOL_BTF) + else + $(info bpftool is missing or does not support btf, cannot build BPF mo= nitors.) + $(info Please install bpftool) + BUILD_BPF_OBJS :=3D 0 + endif +endif + ifeq ($(STOP_ERROR),1) $(error Please, check the errors above.) endif diff --git a/tools/verification/rv/Makefile.rv b/tools/verification/rv/Make= file.rv index 2497fb96c83d..418748bc3aa1 100644 --- a/tools/verification/rv/Makefile.rv +++ b/tools/verification/rv/Makefile.rv @@ -33,12 +33,17 @@ INSTALL :=3D install MKDIR :=3D mkdir STRIP :=3D strip BINDIR :=3D /usr/bin +BPF_MON_DIR :=3D /usr/share/rv/bpf_monitors =20 .PHONY: install install: doc_install $(Q)$(MKDIR) -p $(DESTDIR)$(BINDIR) $(call QUIET_INSTALL,rv)$(INSTALL) $(OUTPUT)rv -m 755 $(DESTDIR)$(BINDIR) $(Q)@$(STRIP) $(DESTDIR)$(BINDIR)/rv +ifneq ($(wildcard bpf_monitors/*.o),) + $(Q)$(MKDIR) -p $(DESTDIR)$(BPF_MON_DIR) + $(call QUIET_INSTALL,bpf_monitors)$(INSTALL) bpf_monitors/*.o -m 644 $(DE= STDIR)$(BPF_MON_DIR) +endif =20 .PHONY: doc doc_clean doc_install doc: diff --git a/tools/verification/rv/bpf_monitors/.gitignore b/tools/verifica= tion/rv/bpf_monitors/.gitignore new file mode 100644 index 000000000000..e5add9141ef5 --- /dev/null +++ b/tools/verification/rv/bpf_monitors/.gitignore @@ -0,0 +1,2 @@ +*.d +vmlinux.h diff --git a/tools/verification/rv/bpf_monitors/da_monitor_bpf.h b/tools/ve= rification/rv/bpf_monitors/da_monitor_bpf.h new file mode 100644 index 000000000000..ee421ebcf1b5 --- /dev/null +++ b/tools/verification/rv/bpf_monitors/da_monitor_bpf.h @@ -0,0 +1,400 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * BPF support for DA monitors. + * + * BPF programs can include the in-kernel da_monitor directly, this + * header contains all the BPF compatibility layer. + * + * Copyright (C) 2026 Red Hat Inc, Gabriele Monaco + */ + +#ifndef _DA_MONITOR_BPF_H +#define _DA_MONITOR_BPF_H + +#include +#include +#include +#include "bpf_atomic.h" + +/* BPF monitors don't support these */ +#define trace_rv_retries_error(...) do {} while (0) +#define pr_warn(fmt, ...) bpf_printk(fmt, ##__VA_ARGS__) +#define da_monitor_enabled() likely(da_monitor_enabled_bpf()) +#define da_implicit_guard() +#define IS_ENABLED(conf) 0 + +#define RV_TRACE_EVENT 0 +#define RV_TRACE_ERROR 1 + +/* + * BPF ring buffer for trace events + * Events and errors are sent to userspace via this ringbuf + */ +struct rv_trace_entry { + uint8_t event_type; + uint8_t is_final; + char comm[TASK_COMM_LEN]; +#if RV_MON_TYPE =3D=3D RV_MON_PER_TASK || RV_MON_TYPE =3D=3D RV_MON_PER_OBJ + uint32_t id; +#endif + uint32_t pid; + uint32_t cpu; + uint32_t curr_state; + uint32_t event; + uint32_t next_state; +}; + +#define da_monitor_map CONCATENATE(da_monitor_map_, MONITOR_NAME) +#define da_ringbuf CONCATENATE(da_ringbuf_, MONITOR_NAME) +#define rv_this_enabled CONCATENATE(rv_enabled_, MONITOR_NAME) + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} da_ringbuf SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, bool); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} rv_this_enabled SEC(".maps"); + +#ifndef __used +#define __used __attribute__((used)) +#endif + +/* Force types to be included in BTF for userspace parsing */ +static const enum states __used _btf_states; +static const enum events __used _btf_events; +static const struct rv_trace_entry __used *_btf_trace; + +static inline void da_monitor_reset(struct da_monitor *da_mon); + +static inline bool da_monitor_enabled_bpf(void) +{ + uint32_t key =3D 0; + bool *enabled =3D bpf_map_lookup_elem(&rv_this_enabled, &key); + + return enabled && *enabled; +} + +void bpf_rv_react(char *name__str, char *msg, u32 msg__sz) __ksym; + +#define rv_react(mon, fmt, ...) \ + ({ \ + char ___msg[256]; \ + \ + if (BPF_SNPRINTF(___msg, sizeof(___msg), fmt, ##__VA_ARGS__) > 0) \ + bpf_rv_react(__stringify(MONITOR_NAME), ___msg, \ + sizeof(___msg)); \ + }) + +/* + * BPF monitor implementations + * These use BPF maps instead of kernel data structures + */ + +#if RV_MON_TYPE =3D=3D RV_MON_GLOBAL +/* + * BPF Global monitor - uses a single-entry BPF array map + */ + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, union rv_task_monitor); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} da_monitor_map SEC(".maps"); + +static inline struct da_monitor *da_get_monitor(void) +{ + __u32 key =3D 0; + union rv_task_monitor *mon =3D bpf_map_lookup_elem(&da_monitor_map, &key); + + return &mon->da_mon; +} + +#elif RV_MON_TYPE =3D=3D RV_MON_PER_CPU +/* + * BPF Per-CPU monitor - uses BPF per-cpu array map + */ + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, union rv_task_monitor); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} da_monitor_map SEC(".maps"); + +static inline struct da_monitor *da_get_monitor(void) +{ + __u32 key =3D 0; + union rv_task_monitor *mon =3D bpf_map_lookup_elem(&da_monitor_map, &key); + + return &mon->da_mon; +} + +#elif RV_MON_TYPE =3D=3D RV_MON_PER_OBJ || RV_MON_TYPE =3D=3D RV_MON_PER_T= ASK +/* + * BPF Per-Object monitor - uses BPF hash map + * Note: monitor_target_bpf type must be compatible with BPF + * Types and structs must be different not to collide with vmlinux.h + */ + +#if RV_MON_TYPE =3D=3D RV_MON_PER_TASK +/* + * BPF Per-Task monitor - uses BPF hash map indexed by PID + * + * Just a special case of per-object monitor with API consistent with in-k= ernel + * monitors (no need to pass the id). + */ + +#define da_get_monitor(tsk) da_get_monitor_bpf(BPF_CORE_READ(tsk, pid), ts= k) +#define da_handle_event(tsk, event) \ + da_handle_event_bpf(BPF_CORE_READ(tsk, pid), tsk, event) +#define da_handle_start_event(tsk, event) \ + da_handle_start_event_bpf(BPF_CORE_READ(tsk, pid), tsk, event) +#define da_handle_start_run_event(tsk, event) \ + da_handle_start_run_event_bpf(BPF_CORE_READ(tsk, pid), tsk, event) + +typedef struct task_struct *monitor_target_bpf; +static inline void da_destroy_storage(da_id_type id); + +SEC("tp_btf/sched_process_exit") +int BPF_PROG(handle_obj_cleanup, struct task_struct *p, bool group_dead) +{ + da_destroy_storage(p->pid); + return 0; +} + +#else + +#define da_get_monitor da_get_monitor_bpf +#define da_handle_event da_handle_event_bpf +#define da_handle_start_event da_handle_start_event_bpf +#define da_handle_start_run_event da_handle_start_run_event_bpf + +#endif /* RV_MON_PER_TASK */ + +struct da_monitor_storage_bpf { + da_id_type id; + monitor_target_bpf target; + union rv_task_monitor rv; +}; + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10240); + __type(key, da_id_type); + __type(value, struct da_monitor_storage_bpf); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} da_monitor_map SEC(".maps"); + +static inline struct da_monitor *da_get_monitor_bpf(da_id_type id, monitor= _target_bpf target) +{ + struct da_monitor_storage_bpf *storage; + + storage =3D bpf_map_lookup_elem(&da_monitor_map, &id); + return storage ? &storage->rv.da_mon : NULL; +} + +static inline struct da_monitor *da_create_storage(da_id_type id, + monitor_target_bpf target, + struct da_monitor *da_mon) +{ + struct da_monitor_storage_bpf new_storage =3D { + .id =3D id, + .target =3D target, + }; + + if (da_mon) + return da_mon; + /* Possible with monitor manually disabled: handlers still active */ + if (unlikely(!da_monitor_enabled())) + return NULL; + + bpf_map_update_elem(&da_monitor_map, &id, &new_storage, BPF_NOEXIST); + return da_get_monitor_bpf(id, target); +} + +static inline void da_destroy_storage(da_id_type id) +{ + bpf_map_delete_elem(&da_monitor_map, &id); +} + +static inline da_id_type da_get_id(struct da_monitor *da_mon) +{ + return container_of(da_mon, struct da_monitor_storage_bpf, rv.da_mon)->id; +} + +static inline monitor_target_bpf da_get_target(struct da_monitor *da_mon) +{ + return container_of(da_mon, struct da_monitor_storage_bpf, rv.da_mon)->ta= rget; +} + +/* + * Handle event for per object and per task + */ + +static inline void __da_handle_event(struct da_monitor *da_mon, + enum events event, da_id_type id); +static inline bool __da_handle_start_event(struct da_monitor *da_mon, + enum events event, da_id_type id); +static inline bool __da_handle_start_run_event(struct da_monitor *da_mon, + enum events event, da_id_type id); + +/* + * da_handle_event - handle an event + */ +static inline void da_handle_event_bpf(da_id_type id, monitor_target_bpf t= arget, enum events event) +{ + struct da_monitor *da_mon; + + da_mon =3D da_get_monitor_bpf(id, target); + if (likely(da_mon)) + __da_handle_event(da_mon, event, id); +} + +/* + * da_handle_start_event - start monitoring or handle event + * + * This function is used to notify the monitor that the system is returning + * to the initial state, so the monitor can start monitoring in the next e= vent. + * Thus: + * + * If the monitor already started, handle the event. + * If the monitor did not start yet, start the monitor but skip the event. + */ +static inline bool da_handle_start_event_bpf(da_id_type id, monitor_target= _bpf target, + enum events event) +{ + struct da_monitor *da_mon; + + da_mon =3D da_get_monitor_bpf(id, target); + da_mon =3D da_create_storage(id, target, da_mon); + if (unlikely(!da_mon)) + return 0; + return __da_handle_start_event(da_mon, event, id); +} + +/* + * da_handle_start_run_event - start monitoring and handle event + * + * This function is used to notify the monitor that the system is in the + * initial state, so the monitor can start monitoring and handling event. + */ +static inline bool da_handle_start_run_event_bpf(da_id_type id, monitor_ta= rget_bpf target, + enum events event) +{ + struct da_monitor *da_mon; + + da_mon =3D da_get_monitor_bpf(id, target); + da_mon =3D da_create_storage(id, target, da_mon); + if (unlikely(!da_mon)) + return 0; + return __da_handle_start_run_event(da_mon, event, id); +} + +static inline void da_reset_bpf(da_id_type id, monitor_target_bpf target) +{ + struct da_monitor *da_mon; + + da_mon =3D da_get_monitor_bpf(id, target); + if (likely(da_mon)) + da_monitor_reset(da_mon); +} + +#endif /* RV_MON_TYPE */ + +static inline void *_da_trace_common(enum states curr_state, enum events e= vent, + uint8_t type) +{ + struct rv_trace_entry *entry; + static const char stub_comm[] =3D ""; + + entry =3D bpf_ringbuf_reserve(&da_ringbuf, sizeof(*entry), 0); + if (!entry) + return NULL; + entry->event_type =3D type; + entry->cpu =3D bpf_get_smp_processor_id(); + entry->pid =3D bpf_get_current_pid_tgid() & 0xffffffff; + if (bpf_get_current_comm(entry->comm, TASK_COMM_LEN)) + __builtin_memcpy(entry->comm, stub_comm, sizeof(stub_comm)); + entry->curr_state =3D curr_state; + entry->event =3D event; + + return entry; +} + +#if RV_MON_TYPE =3D=3D RV_MON_PER_TASK || RV_MON_TYPE =3D=3D RV_MON_PER_OBJ +static inline void _da_trace_id(struct rv_trace_entry *entry, da_id_type i= d) +{ + entry->id =3D id; +} +#else +static inline void _da_trace_id(struct rv_trace_entry *entry, da_id_type i= d) { } +#endif + +/* + * BPF trace events implementation using ring buffer + */ +static inline void da_trace_event(struct da_monitor *da_mon, + enum states curr_state, enum events event, + enum states next_state, + da_id_type id) +{ + struct rv_trace_entry *entry =3D _da_trace_common(curr_state, event, RV_T= RACE_EVENT); + + if (!entry) + return; + _da_trace_id(entry, id); + entry->is_final =3D model_is_final_state(next_state); + entry->next_state =3D next_state; + + bpf_ringbuf_submit(entry, 0); +} + +static inline void da_trace_error(struct da_monitor *da_mon, + enum states curr_state, enum events event, + da_id_type id) +{ + struct rv_trace_entry *entry =3D _da_trace_common(curr_state, event, RV_T= RACE_ERROR); + + if (!entry) + return; + _da_trace_id(entry, id); + + bpf_ringbuf_submit(entry, 0); +} + +SEC("struct_ops/enable") +int da_monitor_enable_bpf(void) +{ + uint32_t key =3D 0; + bool enabled =3D true; + + bpf_map_update_elem(&rv_this_enabled, &key, &enabled, BPF_ANY); + return 0; +} + +SEC("struct_ops/disable") +void da_monitor_disable_bpf(void) +{ + uint32_t key =3D 0; + bool enabled =3D false; + + bpf_map_update_elem(&rv_this_enabled, &key, &enabled, BPF_ANY); +} + +SEC("struct_ops/reset") +void da_monitor_reset_bpf(void) +{ + /* Userspace resets maps */ +} + +#endif // _DA_MONITOR_BPF_H diff --git a/tools/verification/rv/bpf_monitors/nohz.c b/tools/verification= /rv/bpf_monitors/nohz.c new file mode 100644 index 000000000000..5bded9408b6d --- /dev/null +++ b/tools/verification/rv/bpf_monitors/nohz.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" + +#define RV_MON_TYPE RV_MON_PER_CPU +#include "nohz.h" +#include + +/* + * This monitor is broken on purpose to test errors, sched_tick can run wi= th + * stopped ticks for one last time (deferred tick reprogram). + * A way to fix the monitor is to allow a single optional sched_tick from = the + * stopped state in the model. + */ +SEC("fentry/sched_tick") +int BPF_PROG(handle_sched_tick) +{ + da_handle_start_event(sched_tick_nohz); + return 0; +} + +SEC("fentry/tick_nohz_restart_sched_tick") +int BPF_PROG(handle_tick_restart) +{ + da_handle_start_event(tick_restart_nohz); + return 0; +} + +SEC("tp_btf/tick_stop") +int BPF_PROG(handle_tick_stop, int success, int dependency) +{ + if (success) + da_handle_event(tick_stop_nohz); + return 0; +} + +SEC(".struct_ops.link") +struct rv_monitor rv_nohz_kern =3D { + .name =3D "nohz", + .description =3D "tick does not run when stopped.", + .enable =3D da_monitor_enable_bpf, + .disable =3D da_monitor_disable_bpf, + .reset =3D da_monitor_reset_bpf, + .enabled =3D 0, +}; + +char LICENSE[] SEC("license") =3D "GPL"; diff --git a/tools/verification/rv/bpf_monitors/nohz.h b/tools/verification= /rv/bpf_monitors/nohz.h new file mode 100644 index 000000000000..ef1c88f31f51 --- /dev/null +++ b/tools/verification/rv/bpf_monitors/nohz.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Automatically generated C representation of nohz automaton + * For further information about this format, see kernel documentation: + * Documentation/trace/rv/deterministic_automata.rst + */ + +#define MONITOR_NAME nohz + +enum states_nohz { + running_nohz, + stopped_nohz, + state_max_nohz, +}; + +#define INVALID_STATE state_max_nohz + +enum events_nohz { + sched_tick_nohz, + tick_restart_nohz, + tick_stop_nohz, + event_max_nohz, +}; + +struct automaton_nohz { + char state_names[state_max_nohz][32]; + char event_names[event_max_nohz][32]; + unsigned char function[state_max_nohz][event_max_nohz]; + unsigned char initial_state; + bool final_states[state_max_nohz]; +}; + +static const struct automaton_nohz automaton_nohz =3D { + .state_names =3D { + "running", + "stopped", + }, + .event_names =3D { + "sched_tick", + "tick_restart", + "tick_stop", + }, + .function =3D { + { running_nohz, INVALID_STATE, stopped_nohz }, + { INVALID_STATE, running_nohz, INVALID_STATE }, + }, + .initial_state =3D running_nohz, + .final_states =3D { 1, 0 }, +}; diff --git a/tools/verification/rv/bpf_monitors/tqueue.c b/tools/verificati= on/rv/bpf_monitors/tqueue.c new file mode 100644 index 000000000000..c7516da01b65 --- /dev/null +++ b/tools/verification/rv/bpf_monitors/tqueue.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" + +#define RV_MON_TYPE RV_MON_PER_TASK +#include "tqueue.h" +#include +#define PF_EXITING 0x00000004 + +SEC("tp_btf/sched_dequeue_tp") +int BPF_PROG(handle_sched_dequeue, struct task_struct *tsk, int cpu) +{ + if (!(tsk->flags & PF_EXITING)) + da_handle_start_event(tsk, sched_dequeue_tqueue); + return 0; +} + +SEC("tp_btf/sched_enqueue_tp") +int BPF_PROG(handle_sched_enqueue, struct task_struct *tsk, int cpu) +{ + da_handle_event(tsk, sched_enqueue_tqueue); + return 0; +} + +SEC(".struct_ops.link") +struct rv_monitor rv_tqueue_kern =3D { + .name =3D "tqueue", + .description =3D "enqueue and dequeue tasks.", + .enable =3D da_monitor_enable_bpf, + .disable =3D da_monitor_disable_bpf, + .reset =3D da_monitor_reset_bpf, + .enabled =3D 0, +}; + +char LICENSE[] SEC("license") =3D "GPL"; diff --git a/tools/verification/rv/bpf_monitors/tqueue.h b/tools/verificati= on/rv/bpf_monitors/tqueue.h new file mode 100644 index 000000000000..64a0af1dc924 --- /dev/null +++ b/tools/verification/rv/bpf_monitors/tqueue.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Automatically generated C representation of tqueue automaton + * For further information about this format, see kernel documentation: + * Documentation/trace/rv/deterministic_automata.rst + */ + +#define MONITOR_NAME tqueue + +enum states_tqueue { + dequeued_tqueue, + enqueued_tqueue, + state_max_tqueue, +}; + +#define INVALID_STATE state_max_tqueue + +enum events_tqueue { + sched_dequeue_tqueue, + sched_enqueue_tqueue, + event_max_tqueue, +}; + +struct automaton_tqueue { + char state_names[state_max_tqueue][32]; + char event_names[event_max_tqueue][32]; + unsigned char function[state_max_tqueue][event_max_tqueue]; + unsigned char initial_state; + bool final_states[state_max_tqueue]; +}; + +static const struct automaton_tqueue automaton_tqueue =3D { + .state_names =3D { + "dequeued", + "enqueued", + }, + .event_names =3D { + "sched_dequeue", + "sched_enqueue", + }, + .function =3D { + { INVALID_STATE, enqueued_tqueue }, + { dequeued_tqueue, INVALID_STATE }, + }, + .initial_state =3D dequeued_tqueue, + .final_states =3D { 1, 0 }, +}; --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 102273D9DA8 for ; Mon, 31 Aug 2026 09:08:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167294; cv=none; b=ZfRJ3ant+cTT7CMpwEEFVux8/gE9GMNm763dIDIeLBCegBiKN1nJ0BnefBCGMchNdicdFzmAV/Egl8VU207SSptBMfcOCVetbFGdrXCDONm7FmSyaVgpjck5dsoli9Qk3pgWnqknzeKUk3crP8YKgkc5Op+LfnKdrQvm2bmKtE8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167294; c=relaxed/simple; bh=tMK+rhnH9c6uPCT5UekXLsRXMQc1quMUh3HQmjUsB00=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q209SLwSRIDQVEbHWhgy7TKclEb4/McYiK6iWlaOxj+MgrGXDKlcx5mQYlGnk1JuI3sj7lGLRXjFGnJHdMncfyI3+TP7CBMhZV2YXDWsuNOxzPDJX22SytIPRvA9VdsXoAHegKr78gpURPhbZkuAj7rqXGgIyNXpZ0cwLuaIZ1E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=NoeVcr3P; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="NoeVcr3P" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167292; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lnKaODZGqlYN5mbvfy8Z28vyw8EwegzzHDVkYNnOU+o=; b=NoeVcr3P5QZgSa8C0xSFpbH3yUjrGjAkjyZFKfj727C9s69B2+/ryTWW/0eEHHanRE4NOK 855VvBVKKgw77OiC3Eq7hkBZzSHdOGQWKJqfqOgVpSxyZHh2coozkInRjNbbUvvEksosEL 9+1ZPFDFVaVKQP1tNO3o2UbZ2+y7Qio= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-208-6QsakI4GMUeTsUGdKBeXzQ-1; Mon, 31 Aug 2026 05:08:08 -0400 X-MC-Unique: 6QsakI4GMUeTsUGdKBeXzQ-1 X-Mimecast-MFC-AGG-ID: 6QsakI4GMUeTsUGdKBeXzQ_1788167286 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D20B618301B7; Mon, 31 Aug 2026 09:08:06 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E8314180034F; Mon, 31 Aug 2026 09:08:03 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 17/20] tools/rv: Define CONFIG_X86_64 statically for BPF monitors Date: Mon, 31 Aug 2026 11:05:21 +0200 Message-ID: <20260831090524.106845-18-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" BPF atomic macros require CONFIG_X86_64 to determine barrier instructions. Reading this from the system Kconfig can fail if the configuration is missing or in an unexpected location, causing the loading phase to fail. Since the rv tool is compiled for the target architecture, the architecture is known at compile-time. Define the CONFIG_X86_64 value statically via the libbpf open options to bypass Kconfig dependency and ensure reliable loading. Signed-off-by: Gabriele Monaco --- tools/verification/rv/src/bpf_monitor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/verification/rv/src/bpf_monitor.c b/tools/verification/r= v/src/bpf_monitor.c index 7e24a71dfac7..d2d1d90bbf73 100644 --- a/tools/verification/rv/src/bpf_monitor.c +++ b/tools/verification/rv/src/bpf_monitor.c @@ -505,6 +505,12 @@ static struct bpf_object *open_bpf_monitor(const char = *monitor_name, const char =20 LIBBPF_OPTS(bpf_object_open_opts, opts, .pin_root_path =3D BPF_PIN_BASE_PATH, + /* Define statically as arch is known, Kconfig may not be available */ +#ifdef __x86_64__ + .kconfig =3D "CONFIG_X86_64=3Dy\n", +#else + .kconfig =3D "CONFIG_X86_64=3Dn\n", +#endif ); =20 if (!path) { --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B6033DDB00 for ; Mon, 31 Aug 2026 09:08:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167299; cv=none; b=PB5SxJmSDZeZDFzXYfBc+yq+fgkhhzCniP8cV3u0lefh600v+7B6nZlTHL0dCv0+HqN/kN8G3TtnAlGu51HbkQaMU15JVPK3QkRIhnNtogetzFEQUkxOHIUb0G3ga7EjQu/QqMgWau1l75sxJTsprzS8YjNfMMH7OOAY0QxLDt4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167299; c=relaxed/simple; bh=x4mfE5nkoCS5iWbLR124NBerkKg3QWDRrgzXTXkU6OQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qUo9XcuDki1iThZBVkgJqPCXyYOulPAXPFOGY6WaRAva8CLGBu71LHIhMk1Pr+OmkGYKylemjNpxJKq9vBbISpcrD+putNEWlqs9FxkTONJLztY3nQSIg4uOanerMF0uOgFgaQNmzkyfThgbi3F+6ligojXcIrKa/QY32qf4XJw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=VQv9+6ZD; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="VQv9+6ZD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167296; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uvSgUNymrhgeiKJforbaZlCZZ1wsFbegexlUCEoOVV0=; b=VQv9+6ZDFEqi4+SVAWC3im6NfxCOPHBhjPtYlDawAPC8p7yOPlJ0ICqTa5UcxmerMvJpWI 7PovWp5PeRGKf6/K/fjhTAa6xDiPpmdHaoEp/VHV56cHVeV0ErJf2fbAlZ2h8XNTkkbSjO yFRnVR8v1nUBqBYse9JKJhv/jnk+Bho= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-619-Vs3UoQNpNzWxzTceuuaa1g-1; Mon, 31 Aug 2026 05:08:12 -0400 X-MC-Unique: Vs3UoQNpNzWxzTceuuaa1g-1 X-Mimecast-MFC-AGG-ID: Vs3UoQNpNzWxzTceuuaa1g_1788167291 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8A51B18333D3; Mon, 31 Aug 2026 09:08:11 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8B33F180034F; Mon, 31 Aug 2026 09:08:08 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 18/20] verification/rvgen: Add support for BPF monitors Date: Mon, 31 Aug 2026 11:05:22 +0200 Message-ID: <20260831090524.106845-19-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add the -b flag to rvgen monitor to generate a bpf monitor. By default the code is generated in a folder with the same name as the model just like in-kernel monitors, although only the source and header are meaningful here. Passing -a moves the sources to tools/verification/rv/bpf_monitors/ where they can be built directly. Currently BPF monitors are only supported for DA. Signed-off-by: Gabriele Monaco --- tools/verification/rvgen/__main__.py | 15 ++++++++--- tools/verification/rvgen/rvgen/dot2c.py | 15 ++++++++--- tools/verification/rvgen/rvgen/dot2k.py | 22 +++++++++++++--- tools/verification/rvgen/rvgen/generator.py | 26 ++++++++++++++----- .../rvgen/rvgen/templates/dot2k/main_bpf.c | 26 +++++++++++++++++++ 5 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 tools/verification/rvgen/rvgen/templates/dot2k/main_bpf= .c diff --git a/tools/verification/rvgen/__main__.py b/tools/verification/rvge= n/__main__.py index 246b43fa29f1..16ce9b512fbb 100644 --- a/tools/verification/rvgen/__main__.py +++ b/tools/verification/rvgen/__main__.py @@ -39,6 +39,8 @@ if __name__ =3D=3D '__main__': help=3D"Monitor specification file") monitor_parser.add_argument('-t', "--monitor_type", dest=3D"monitor_ty= pe", required=3DTrue, help=3Df"Available options: {', '.join(Mon= itor.monitor_types.keys())}") + monitor_parser.add_argument('-b', "--bpf", dest=3D"bpf", action=3D"sto= re_true", + required=3DFalse, help=3D"Generate a BPF m= onitor") =20 container_parser =3D subparsers.add_parser("container", parents=3D[par= ent_parser]) container_parser.add_argument('-n', "--model_name", dest=3D"model_name= ", required=3DTrue) @@ -50,6 +52,9 @@ if __name__ =3D=3D '__main__': =20 params =3D parser.parse_args() =20 + if params.subcmd =3D=3D "monitor" and params.bpf and params.monitor_cl= ass !=3D "da": + parser.error("BPF monitors (-b/--bpf) are only supported for deter= ministic automaton (-c da)") + try: if params.subcmd =3D=3D "monitor": print(f"Opening and parsing the specification file {params.spe= c}") @@ -80,7 +85,9 @@ if __name__ =3D=3D '__main__': print("Almost done, checklist") if params.subcmd =3D=3D "monitor": print(f" - Edit the {monitor.name}/{monitor.name}.c to add the in= strumentation") - print(monitor.fill_tracepoint_tooltip()) - print(monitor.fill_makefile_tooltip()) - print(monitor.fill_kconfig_tooltip()) - print(monitor.fill_monitor_tooltip()) + if not params.bpf: + print(monitor.fill_tracepoint_tooltip()) + if not params.subcmd =3D=3D "monitor" or not params.bpf: + print(monitor.fill_makefile_tooltip()) + print(monitor.fill_kconfig_tooltip()) + print(monitor.fill_monitor_tooltip()) diff --git a/tools/verification/rvgen/rvgen/dot2c.py b/tools/verification/r= vgen/rvgen/dot2c.py index 22938ce1bf6c..5be9fe44a19b 100644 --- a/tools/verification/rvgen/rvgen/dot2c.py +++ b/tools/verification/rvgen/rvgen/dot2c.py @@ -111,10 +111,17 @@ class Dot2c(Automata): min_type =3D self.get_minimun_type() buff =3D [] buff.append(f"struct {self.struct_automaton_def} {{") - buff.append(f"\tchar *state_names[state_max{self.enum_suffix}];") - buff.append(f"\tchar *event_names[event_max{self.enum_suffix}];") - if self.is_hybrid_automata(): - buff.append(f"\tchar *env_names[env_max{self.enum_suffix}];") + if self.bpf: + # BPF struggles with non-fixed string pointers + buff.append(f"\tchar state_names[state_max{self.enum_suffix}][= 32];") + buff.append(f"\tchar event_names[event_max{self.enum_suffix}][= 32];") + if self.is_hybrid_automata(): + buff.append(f"\tchar env_names[env_max{self.enum_suffix}][= 32];") + else: + buff.append(f"\tchar *state_names[state_max{self.enum_suffix}]= ;") + buff.append(f"\tchar *event_names[event_max{self.enum_suffix}]= ;") + if self.is_hybrid_automata(): + buff.append(f"\tchar *env_names[env_max{self.enum_suffix}]= ;") buff.append(f"\t{min_type} function[state_max{self.enum_suffix}][e= vent_max{self.enum_suffix}];") buff.append(f"\t{min_type} initial_state;") buff.append(f"\tbool final_states[state_max{self.enum_suffix}];") diff --git a/tools/verification/rvgen/rvgen/dot2k.py b/tools/verification/r= vgen/rvgen/dot2k.py index fd3254ea5b4d..6600bfa0f20f 100644 --- a/tools/verification/rvgen/rvgen/dot2k.py +++ b/tools/verification/rvgen/rvgen/dot2k.py @@ -30,14 +30,19 @@ class dot2k(Monitor, Dot2c): buff =3D [ self.monitor_type.upper() ] buff +=3D self._fill_timer_type() if self.monitor_type =3D=3D "per_obj": - buff.append("typedef /* XXX: define the target type */ *monito= r_target;") + pad =3D "_bpf" if self.bpf else "" + buff.append(f"typedef /* XXX: define the target type */ *monit= or_target{pad};") return "\n".join(buff) =20 def fill_tracepoint_handlers_skel(self) -> str: buff =3D [] buff +=3D self._fill_hybrid_definitions() for event in self.events: - buff.append(f"static void handle_{event}(void *data, /* XXX: f= ill header */)") + if self.bpf: + buff.append("SEC(/* XXX: tracepoint or other probe */)") + buff.append(f"int BPF_PROG(handle_{event}, /* XXX: fill he= ader */)") + else: + buff.append(f"static void handle_{event}(void *data, /* XX= X: fill header */)") buff.append("{") handle =3D "handle_event" if self.is_start_event(event): @@ -50,19 +55,28 @@ class dot2k(Monitor, Dot2c): buff.append("\tstruct task_struct *p =3D /* XXX: how do I = get p? */;") buff.append(f"\tda_{handle}(p, {event}{self.enum_suffix});= ") elif self.monitor_type =3D=3D "per_obj": + pad =3D "_bpf" if self.bpf else "" buff.append("\tint id =3D /* XXX: how do I get the id? */;= ") - buff.append("\tmonitor_target t =3D /* XXX: how do I get t= ? */;") + buff.append(f"\tmonitor_target{pad} t =3D /* XXX: how do I= get t? */;") buff.append(f"\tda_{handle}(id, t, {event}{self.enum_suffi= x});") else: buff.append(f"\tda_{handle}({event}{self.enum_suffix});") + if self.bpf: + buff.append("\treturn 0;") buff.append("}") buff.append("") if self.monitor_type =3D=3D "per_obj": buff.append("/* XXX: obj is being destroyed, remove if not req= uired (e.g. obj is static) */") - buff.append(f"static void handle_{self.cleanup_marker}(void *d= ata, /* XXX: fill header */)") + if self.bpf: + buff.append("SEC(/* XXX: tracepoint or other probe */)") + buff.append(f"int BPF_PROG(handle_{self.cleanup_marker}, /= * XXX: fill header */)") + else: + buff.append(f"static void handle_{self.cleanup_marker}(voi= d *data, /* XXX: fill header */)") buff.append("{") buff.append("\tint id =3D /* XXX: how do I get the id? */;") buff.append("\tda_destroy_storage(id);") + if self.bpf: + buff.append("\treturn 0;") buff.append("}") buff.append("") return '\n'.join(buff) diff --git a/tools/verification/rvgen/rvgen/generator.py b/tools/verificati= on/rvgen/rvgen/generator.py index 45e2bab26cb5..b7985ff84521 100644 --- a/tools/verification/rvgen/rvgen/generator.py +++ b/tools/verification/rvgen/rvgen/generator.py @@ -11,18 +11,22 @@ from pathlib import Path =20 class RVGenerator: rv_dir =3D "kernel/trace/rv" + rv_tool_dir =3D "../../../tools/verification/rv/bpf_monitors/" =20 def __init__(self, extra_params=3D{}): self.name =3D extra_params.get("model_name") self.parent =3D extra_params.get("parent") + self.bpf =3D extra_params.get("bpf") self.abs_template_dir =3D \ Path(__file__).resolve().parent / "templates" / self.template_= dir - self.main_c =3D self._read_template_file("main.c") + self.main_c =3D self._read_template_file("main.c" if not self.bpf + else "main_bpf.c") self.kconfig =3D self._read_template_file("Kconfig") self.description =3D extra_params.get("description", self.name) or= "auto-generated" self.auto_patch =3D extra_params.get("auto_patch") if self.auto_patch: self._fill_rv_kernel_dir() + self.rv_tool_dir =3D (Path(self.rv_dir) / self.rv_tool_dir).re= solve() =20 def _fill_rv_kernel_dir(self): # find the kernel tree root relative to this file's location @@ -191,6 +195,9 @@ obj-$(CONFIG_RV_MON_{name_up}) +=3D monitors/{name}/{na= me}.o def __create_directory(self): path =3D Path(self.name) if self.auto_patch: + if self.bpf: + # no directory for BPF monitors + return path =3D Path(self.rv_dir) / "monitors" / path path.mkdir(exist_ok=3DTrue) =20 @@ -202,6 +209,8 @@ obj-$(CONFIG_RV_MON_{name_up}) +=3D monitors/{name}/{na= me}.o path =3D Path(self.name) / file_name if self.auto_patch: path =3D Path(self.rv_dir) / "monitors" / self.name / file_name + if self.bpf: + path =3D Path(self.rv_tool_dir) / file_name self.__write_file(path, content) =20 def print_files(self): @@ -216,8 +225,9 @@ obj-$(CONFIG_RV_MON_{name_up}) +=3D monitors/{name}/{na= me}.o path =3D f"{self.name}.h" self._create_file(path, model_h) =20 - kconfig =3D self.fill_kconfig() - self._create_file("Kconfig", kconfig) + if not self.bpf: + kconfig =3D self.fill_kconfig() + self._create_file("Kconfig", kconfig) =20 =20 class Monitor(RVGenerator): @@ -225,7 +235,8 @@ class Monitor(RVGenerator): =20 def __init__(self, extra_params=3D{}): super().__init__(extra_params) - self.trace_h =3D self._read_template_file("trace.h") + if not self.bpf: + self.trace_h =3D self._read_template_file("trace.h") =20 def fill_trace_h(self): trace_h =3D self.trace_h @@ -245,6 +256,7 @@ class Monitor(RVGenerator): =20 def print_files(self): super().print_files() - trace_h =3D self.fill_trace_h() - path =3D f"{self.name}_trace.h" - self._create_file(path, trace_h) + if not self.bpf: + trace_h =3D self.fill_trace_h() + path =3D f"{self.name}_trace.h" + self._create_file(path, trace_h) diff --git a/tools/verification/rvgen/rvgen/templates/dot2k/main_bpf.c b/to= ols/verification/rvgen/rvgen/templates/dot2k/main_bpf.c new file mode 100644 index 000000000000..7af176ea0a29 --- /dev/null +++ b/tools/verification/rvgen/rvgen/templates/dot2k/main_bpf.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" + +#define RV_MON_TYPE RV_MON_%%MONITOR_TYPE%% +#include "%%MODEL_NAME%%.h" +#include + +/* + * This is the instrumentation part of the monitor. + * + * This is the section where manual work is required. Here the kernel even= ts + * are translated into model's event. + */ +%%TRACEPOINT_HANDLERS_SKEL%% +SEC(".struct_ops.link") +struct rv_monitor rv_%%MODEL_NAME%%_kern =3D { + .name =3D "%%MODEL_NAME%%", + .description =3D "%%DESCRIPTION%%", + .enable =3D da_monitor_enable_bpf, + .disable =3D da_monitor_disable_bpf, + .reset =3D da_monitor_reset_bpf, + .enabled =3D 0, +}; + +char LICENSE[] SEC("license") =3D "GPL"; --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 422993E3D8F for ; Mon, 31 Aug 2026 09:08:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167303; cv=none; b=Bg8pmUQqn6NIyOgGs/IFsONSEX4PqgjSp8gGN1var9mBGQDbEexzdYyPGNywsOPme20ajpTJ1AVRIJkix7j8UBMXET3THnJLwjd2JB8LmmMmc8CnJpRVBtgkfvaoSqjRZ+sGXOPIiwZD5dSwdBYP9YWx4TWHb2FP1O90mgur4e8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167303; c=relaxed/simple; bh=oeem+Ud3nm5ioBpJp2KL8Nu2qrfTVVl1ppFm5CYlXxc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W2mTugzorzT5JMdyRUenoCa15yWvNeJq16pcHHLwu2q1GEcXS1A5ktNqStGEp+neIOwVDuu0X5lmJZSymp6orbNlogrv++oONpnKrkFhHE/D8KWEBwMuYeFeUzHPDbF9AEwjvaCK4O9p51irVVs3UdZKssbdpwwPgKG202AXS80= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=EClISDcD; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="EClISDcD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167300; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aOLKnqkN3lriGbQvo7O/1UtI9sEeayBnWBcR41PD8ek=; b=EClISDcDZk4yNhqJi4Gntk9YQg4a6k1Mpouxm+kZ2uwWEhtCtfHpUIm53gpxc3VF2rW7s/ OS+rpFNVaIWPOvFc8wWxicSa3/e8ivg3B+uKNooBZ+1Dm4kDYw1y2ouAKFd/6WfnHGKRvu PHFJVz1X8jR5xkm3UqlztiwPRFfPcpY= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-62-GGUQI_VxN0Kx0I7vfJHHgw-1; Mon, 31 Aug 2026 05:08:16 -0400 X-MC-Unique: GGUQI_VxN0Kx0I7vfJHHgw-1 X-Mimecast-MFC-AGG-ID: GGUQI_VxN0Kx0I7vfJHHgw_1788167295 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7C473195411C; Mon, 31 Aug 2026 09:08:15 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A365118005BB; Mon, 31 Aug 2026 09:08:12 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 19/20] tools/rv: Add selftest for rv bpf Date: Mon, 31 Aug 2026 11:05:23 +0200 Message-ID: <20260831090524.106845-20-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add selftest cases for the rv userspace tool BPF commands and monitors, test BPF monitors registration, unregistration and functionality, including traces and reactors. Signed-off-by: Gabriele Monaco --- tools/verification/rv/tests/rv_bpf.t | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 tools/verification/rv/tests/rv_bpf.t diff --git a/tools/verification/rv/tests/rv_bpf.t b/tools/verification/rv/t= ests/rv_bpf.t new file mode 100644 index 000000000000..902343f0d3f1 --- /dev/null +++ b/tools/verification/rv/tests/rv_bpf.t @@ -0,0 +1,104 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +source ../tests/engine.sh +test_begin + +set_timeout 30s + +RVDIR=3D/sys/kernel/tracing/rv + +check "verify bpf subcommand help" \ + "$RV bpf --help" 0 "manage BPF monitor registration" + +if $RV bpf unregister 2>&1 | grep -q "kernel does not support BPF monitors= "; then + test_end + exit 0 +fi + +if ! mount | grep -q /sys/fs/bpf; then + mount -t bpf bpf /sys/fs/bpf +fi + +check "nohz does not exist before register" \ + "$RV mon nohz" 1 "monitor nohz does not exist" + +check "tqueue does not exist before register" \ + "$RV mon tqueue" 1 "monitor tqueue does not exist" + +check "register BPF monitors" \ + "$RV bpf register" 0 "registered [0-9]\+ BPF monitor(s)" + +set_expected_timeout 2s + +header=3D"^[[:space:]]\+\(\([][A-Z_x<>-]\+\||\)[[:space:]]*\)\+$" +type=3D"\(event\|error\)[[:space:]]\+" +genpid=3D"[0-9]\+[[:space:]]\+" +selfpid=3D"\$pid[[:space:]]\+" +cpu=3D"\[[0-9]\{3\}\][[:space:]]\+" +state=3D"[a-z_]\+ " +trace_task=3D"${genpid}${cpu}${type}${genpid}${state}" +trace_task_self=3D"${genpid}${cpu}${type}${selfpid}${state}" +trace_cpu=3D"${genpid}${cpu}${type}${state}" +trace_cpu_self=3D"${selfpid}${cpu}${type}${state}" + +check_if_exists "run a BPF monitor without parameters" \ + "$RV mon nohz" "$RVDIR/monitors/nohz" "" "." + +check_if_exists "run a per-task BPF monitor without parameters" \ + "$RV mon tqueue" "$RVDIR/monitors/tqueue" "" "." + +check_if_exists "run per-task BPF monitor with tracing" \ + "$RV mon tqueue -t" "$RVDIR/monitors/tqueue" \ + "$header" "$trace_task_self" "\($header\|$trace_task\)" + +check_if_exists "run per-task BPF monitor tracing also self" \ + "$RV mon tqueue -t -s" "$RVDIR/monitors/tqueue" \ + "$trace_task_self" "" "\($header\|$trace_task\)" + +check_if_exists "run per-cpu BPF monitor with tracing" \ + "$RV mon nohz -t" "$RVDIR/monitors/nohz" \ + "$header" "$trace_cpu_self" "\($header\|$trace_cpu\)" + +# This is unstable, we may never see events from self +#check_if_exists "run per-cpu BPF monitor tracing also self" \ +# "$RV mon nohz -t -s" "$RVDIR/monitors/nohz" \ +# "$trace_cpu_self" "" "\($header\|$trace_cpu\)" + +lines_before=3D$(($(dmesg | wc -l) + 1)) +check_if_exists "run a BPF monitor with a reactor" \ + "$RV mon nohz -r printk && dmesg | tail -n +$lines_before" "$RVDIR/monito= rs/nohz" \ + "rv: monitor nohz does not allow event" + +set_timeout 30s + +check "already enabled monitor returns error" \ + "echo 1 > $RVDIR/monitors/nohz/enable; $RV mon nohz" 1 \ + "monitor nohz (BPF) is already enabled" +[ -n "$TEST_COUNT" ] && echo 0 > $RVDIR/monitors/nohz/enable + +check "already enabled monitor prevents unregistration" \ + "echo 1 > $RVDIR/monitors/nohz/enable; $RV bpf unregister" 1 \ + "monitor nohz is enabled, cannot unregister" \ + "unregistered [0-9]\+ BPF monitor(s)" +[ -n "$TEST_COUNT" ] && echo 0 > $RVDIR/monitors/nohz/enable + +check "unregister BPF monitors" \ + "$RV bpf unregister" 0 "unregistered [0-9]\+ BPF monitor(s)" + +check "nohz does not exist after unregister" \ + "$RV mon nohz" 1 "monitor nohz does not exist" + +check "tqueue does not exist after unregister" \ + "$RV mon tqueue" 1 "monitor tqueue does not exist" + +check "nothing left to unregister" \ + "$RV bpf unregister" 0 "unregistered 0 BPF monitor(s)" + +# Error handling tests +check "bpf without subcommand" \ + "$RV bpf" 1 "usage: rv bpf" + +check "invalid bpf subcommand" \ + "$RV bpf invalid" 1 "usage: rv bpf" + +test_end --=20 2.55.0 From nobody Sat Sep 26 19:34:29 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8692C3E4C75 for ; Mon, 31 Aug 2026 09:08:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167308; cv=none; b=tp59DqvsfSNaGqDfyohjlS/agouLgSvrY7ZRXtCjq2+VYxCGpz9Euz8akIG74QL21cmEqqGdWvmIquL8id9Bm8KNJkmdfzRVIf8WyyTteP3wAj53WWCcTJDQBOKBAXv+OBYCbHfK3zHXzt6co5s4cCqRd/tLK1ZslqJ73GzPZ4Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788167308; c=relaxed/simple; bh=07G9mbWUZANCVxFbifnelQ/MS9URdMr6lWuIx/p3RwA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ndwKfG3e2WkXK2oyqftIaxtIZ26AqEn0H4K+31Jtb7O+/QkEEl3Yve/v7wkrswEXCx+IhsWoMC73awjZpo6Z6UCxvOgXMD5yL8H/9wxz4aKApcZJyhAAzUk1bMTpsTc6d9+KfDUZiHfd9bkxVa/KpRcNnJwlL+P3TUVoy2jFcrY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=eloseH4X; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="eloseH4X" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1788167305; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HZqEJDnBRZEwxmWnx5FvxUNAzxzmaxFYz8vRpvX4T0E=; b=eloseH4XoujPaNRqLRPWj7TwU7QNd3EVsskmvnQgygsy2xsrhC9eE9XzdF9hcwxZUiKjTS TpSM03JB9GChuYom22raL4QVr8R+spAysyMlvzbvwHw1f5QPrzSj6Y/3CdUr2IvhQdVJil DUDJcd1NQ5zCS7gZA1nQnGdfbT8zcTo= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-240-mnOYfhuoMCa0Prfhzlo2Hw-1; Mon, 31 Aug 2026 05:08:21 -0400 X-MC-Unique: mnOYfhuoMCa0Prfhzlo2Hw-1 X-Mimecast-MFC-AGG-ID: mnOYfhuoMCa0Prfhzlo2Hw_1788167300 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 29C491944D41; Mon, 31 Aug 2026 09:08:20 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 298B2180034F; Mon, 31 Aug 2026 09:08:16 +0000 (UTC) From: Gabriele Monaco To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, Steven Rostedt , Gabriele Monaco Cc: Nam Cao , Wen Yang , Tobias Schaffner , Viktor Malik Subject: [RFC PATCH 20/20] verification/rvgen: Add selftest for rvgen -b Date: Mon, 31 Aug 2026 11:05:24 +0200 Message-ID: <20260831090524.106845-21-gmonaco@redhat.com> In-Reply-To: <20260831090524.106845-1-gmonaco@redhat.com> References: <20260831090524.106845-1-gmonaco@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add selftest cases for BPF monitors generation. Signed-off-by: Gabriele Monaco --- .../tests/golden/da_bpf_cpu/da_bpf_cpu.c | 40 ++++++++++++++ .../tests/golden/da_bpf_cpu/da_bpf_cpu.h | 47 ++++++++++++++++ .../tests/golden/da_bpf_obj/da_bpf_obj.c | 54 +++++++++++++++++++ .../tests/golden/da_bpf_obj/da_bpf_obj.h | 47 ++++++++++++++++ .../verification/rvgen/tests/rvgen_monitor.t | 11 ++++ 5 files changed, 199 insertions(+) create mode 100644 tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf= _cpu.c create mode 100644 tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf= _cpu.h create mode 100644 tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf= _obj.c create mode 100644 tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf= _obj.h diff --git a/tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf_cpu.c = b/tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf_cpu.c new file mode 100644 index 000000000000..37659b2ebce2 --- /dev/null +++ b/tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf_cpu.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" + +#define RV_MON_TYPE RV_MON_PER_CPU +#include "da_bpf_cpu.h" +#include + +/* + * This is the instrumentation part of the monitor. + * + * This is the section where manual work is required. Here the kernel even= ts + * are translated into model's event. + */ +SEC(/* XXX: tracepoint or other probe */) +int BPF_PROG(handle_event_1, /* XXX: fill header */) +{ + da_handle_event(event_1_da_bpf_cpu); + return 0; +} + +SEC(/* XXX: tracepoint or other probe */) +int BPF_PROG(handle_event_2, /* XXX: fill header */) +{ + /* XXX: validate that this event always leads to the initial state */ + da_handle_start_event(event_2_da_bpf_cpu); + return 0; +} + +SEC(".struct_ops.link") +struct rv_monitor rv_da_bpf_cpu_kern =3D { + .name =3D "da_bpf_cpu", + .description =3D "auto-generated", + .enable =3D da_monitor_enable_bpf, + .disable =3D da_monitor_disable_bpf, + .reset =3D da_monitor_reset_bpf, + .enabled =3D 0, +}; + +char LICENSE[] SEC("license") =3D "GPL"; diff --git a/tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf_cpu.h = b/tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf_cpu.h new file mode 100644 index 000000000000..fd8125118d81 --- /dev/null +++ b/tools/verification/rvgen/tests/golden/da_bpf_cpu/da_bpf_cpu.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Automatically generated C representation of da_bpf_cpu automaton + * For further information about this format, see kernel documentation: + * Documentation/trace/rv/deterministic_automata.rst + */ + +#define MONITOR_NAME da_bpf_cpu + +enum states_da_bpf_cpu { + state_a_da_bpf_cpu, + state_b_da_bpf_cpu, + state_max_da_bpf_cpu, +}; + +#define INVALID_STATE state_max_da_bpf_cpu + +enum events_da_bpf_cpu { + event_1_da_bpf_cpu, + event_2_da_bpf_cpu, + event_max_da_bpf_cpu, +}; + +struct automaton_da_bpf_cpu { + char state_names[state_max_da_bpf_cpu][32]; + char event_names[event_max_da_bpf_cpu][32]; + unsigned char function[state_max_da_bpf_cpu][event_max_da_bpf_cpu]; + unsigned char initial_state; + bool final_states[state_max_da_bpf_cpu]; +}; + +static const struct automaton_da_bpf_cpu automaton_da_bpf_cpu =3D { + .state_names =3D { + "state_a", + "state_b", + }, + .event_names =3D { + "event_1", + "event_2", + }, + .function =3D { + { state_b_da_bpf_cpu, state_a_da_bpf_cpu }, + { INVALID_STATE, state_a_da_bpf_cpu }, + }, + .initial_state =3D state_a_da_bpf_cpu, + .final_states =3D { 1, 0 }, +}; diff --git a/tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf_obj.c = b/tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf_obj.c new file mode 100644 index 000000000000..bbd46615a1a5 --- /dev/null +++ b/tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf_obj.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" + +#define RV_MON_TYPE RV_MON_PER_OBJ +typedef /* XXX: define the target type */ *monitor_target_bpf; +#include "da_bpf_obj.h" +#include + +/* + * This is the instrumentation part of the monitor. + * + * This is the section where manual work is required. Here the kernel even= ts + * are translated into model's event. + */ +SEC(/* XXX: tracepoint or other probe */) +int BPF_PROG(handle_event_1, /* XXX: fill header */) +{ + int id =3D /* XXX: how do I get the id? */; + monitor_target_bpf t =3D /* XXX: how do I get t? */; + da_handle_event(id, t, event_1_da_bpf_obj); + return 0; +} + +SEC(/* XXX: tracepoint or other probe */) +int BPF_PROG(handle_event_2, /* XXX: fill header */) +{ + /* XXX: validate that this event always leads to the initial state */ + int id =3D /* XXX: how do I get the id? */; + monitor_target_bpf t =3D /* XXX: how do I get t? */; + da_handle_start_event(id, t, event_2_da_bpf_obj); + return 0; +} + +/* XXX: obj is being destroyed, remove if not required (e.g. obj is static= ) */ +SEC(/* XXX: tracepoint or other probe */) +int BPF_PROG(handle_obj_cleanup, /* XXX: fill header */) +{ + int id =3D /* XXX: how do I get the id? */; + da_destroy_storage(id); + return 0; +} + +SEC(".struct_ops.link") +struct rv_monitor rv_da_bpf_obj_kern =3D { + .name =3D "da_bpf_obj", + .description =3D "auto-generated", + .enable =3D da_monitor_enable_bpf, + .disable =3D da_monitor_disable_bpf, + .reset =3D da_monitor_reset_bpf, + .enabled =3D 0, +}; + +char LICENSE[] SEC("license") =3D "GPL"; diff --git a/tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf_obj.h = b/tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf_obj.h new file mode 100644 index 000000000000..385006098049 --- /dev/null +++ b/tools/verification/rvgen/tests/golden/da_bpf_obj/da_bpf_obj.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Automatically generated C representation of da_bpf_obj automaton + * For further information about this format, see kernel documentation: + * Documentation/trace/rv/deterministic_automata.rst + */ + +#define MONITOR_NAME da_bpf_obj + +enum states_da_bpf_obj { + state_a_da_bpf_obj, + state_b_da_bpf_obj, + state_max_da_bpf_obj, +}; + +#define INVALID_STATE state_max_da_bpf_obj + +enum events_da_bpf_obj { + event_1_da_bpf_obj, + event_2_da_bpf_obj, + event_max_da_bpf_obj, +}; + +struct automaton_da_bpf_obj { + char state_names[state_max_da_bpf_obj][32]; + char event_names[event_max_da_bpf_obj][32]; + unsigned char function[state_max_da_bpf_obj][event_max_da_bpf_obj]; + unsigned char initial_state; + bool final_states[state_max_da_bpf_obj]; +}; + +static const struct automaton_da_bpf_obj automaton_da_bpf_obj =3D { + .state_names =3D { + "state_a", + "state_b", + }, + .event_names =3D { + "event_1", + "event_2", + }, + .function =3D { + { state_b_da_bpf_obj, state_a_da_bpf_obj }, + { INVALID_STATE, state_a_da_bpf_obj }, + }, + .initial_state =3D state_a_da_bpf_obj, + .final_states =3D { 1, 0 }, +}; diff --git a/tools/verification/rvgen/tests/rvgen_monitor.t b/tools/verific= ation/rvgen/tests/rvgen_monitor.t index 5f2562600bad..3d71685a7ad5 100644 --- a/tools/verification/rvgen/tests/rvgen_monitor.t +++ b/tools/verification/rvgen/tests/rvgen_monitor.t @@ -47,6 +47,17 @@ check_and_compare_folder "LTL per_task with parent and d= escription (default name "$RVGEN monitor -c ltl -s tests/specs/test_ltl.ltl -t per_task -p ltl_par= ent -D 'Simple description'" \ "test_ltl" "LTL_MON_EVENTS_ID" =20 +# BPF monitor test +check_and_compare_folder "DA BPF per_cpu" \ + "$RVGEN monitor -b -c da -s tests/specs/test_da.dot -t per_cpu -n da_bpf_= cpu" \ + "da_bpf_cpu" "Edit the da_bpf_cpu/da_bpf_cpu.c to add the instrumentation= " \ + "Edit kernel/trace/rv/Makefile" + +check_and_compare_folder "DA BPF per_obj" \ + "$RVGEN monitor -b -c da -s tests/specs/test_da.dot -t per_obj -n da_bpf_= obj" \ + "da_bpf_obj" "Edit the da_bpf_obj/da_bpf_obj.c to add the instrumentation= " \ + "Edit kernel/trace/rv/Kconfig" + # Error handling tests check "missing required spec argument" \ "$RVGEN monitor -c da -t per_cpu" 2 \ --=20 2.55.0