From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 C93951FC3; Fri, 4 Jul 2025 13:20:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635233; cv=none; b=EkfUoKbB/xpoY27qZgXVS1o+tzc5masHnrBCGFbwX3f+LWUbExr4XkUOhiINbceFBgZI8bui7FgCmyMjnZP7XiYn7PPwLqSjiZchMppQvJ/fjxmXyDhSkTeYuHTwoZ1JkTbavQFMzNo04E+B3t9cspx4TNXf+bl3x6xFEXatY4U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635233; c=relaxed/simple; bh=9REGFnfyFOEyIjAE1cjJKsPFnrPKw4O7e9wg4waN3vU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=sAO93MicFvNusEgktQ91FWekdzzvS0VYE1RjqngK4wOeJsLdYxssl7la0FPK6XsKRCSo8h0ynUAUi5PGzT14bhpMsgdi5jaXrpW0/yDATu5xdzNvVoRlRmJo6MjdGaCU5qb0IqV6xJ/JkuSr9kID9yIzHsMu4Dxw1lvrwiKWHJ8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=o71t87yN; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=/xtVsI6x; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="o71t87yN"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="/xtVsI6x" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635230; 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=9REGFnfyFOEyIjAE1cjJKsPFnrPKw4O7e9wg4waN3vU=; b=o71t87yN4pUXKTRJVq52dE+wQJSMLrSGiHo8JF8xqKOHTKnIQ7r83os7xAdF+WUXyAUWhq GeLLRNltLivSDdoVkbqVXsgFJiW+UW1mCykhPYcEom+kqxqO4ST0rk4hJ3Zn7OtupHO3ss BEN3MqRi73RHyN8GWx/ThdJqxJdkUPXRD1fMdXUERl0TOF7r2Td+rG/M+WR4laBHlujGf0 CYtlzRYnhmvNMoAHcOR4nqA71J4zt6WeCDU8pITF/BOjVZYlbw6q+oEIxnYVelNzYuevNk i1lTOagS/5DvtKhSiDCeJKEboYDisH0wG5OrLmeYD8KcupBJeF8L+/j6nmUZEQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635230; 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=9REGFnfyFOEyIjAE1cjJKsPFnrPKw4O7e9wg4waN3vU=; b=/xtVsI6x0OrnCSmxhpCNj4mhbrg49Bnl1hTfCklZkZ5QslphSJ3gkv49IaKFjvau8JvLQT 60chLHn4eQ7T6YCQ== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 01/21] rv: Add #undef TRACE_INCLUDE_FILE Date: Fri, 4 Jul 2025 15:19:53 +0200 Message-Id: <9c8e7fce68d4b30568ffaf9e8cc02ae311600997.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Without "#undef TRACE_INCLUDE_FILE", there could be a build error due to TRACE_INCLUDE_FILE being redefined. Therefore add it. Also fix a typo while at it. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- kernel/trace/rv/rv_trace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h index 422b75f58891..99c3801616d4 100644 --- a/kernel/trace/rv/rv_trace.h +++ b/kernel/trace/rv/rv_trace.h @@ -129,8 +129,9 @@ DECLARE_EVENT_CLASS(error_da_monitor_id, #endif /* CONFIG_DA_MON_EVENTS_ID */ #endif /* _TRACE_RV_H */ =20 -/* This part ust be outside protection */ +/* This part must be outside protection */ #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE rv_trace #include --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 555E02FA635; Fri, 4 Jul 2025 13:20:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635233; cv=none; b=sZm/4H3SN0hLeGpniYf0bOoBAh3SyxZVlOeNVghJTkvIfv3Xyf0M2LgxwrfPEjx/d2MMzCwS9BfK9tc/jP9n1Z2bTQ2XMF7EoGj9O4B2mnAicwFdJRl0HtQBRSpPk8yNBNq3Cr8qet6wVibnT60F6vc3GimcduNRDCwHhMeFHos= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635233; c=relaxed/simple; bh=LurusvvHwNK7NPOvQtdp7+qI68/QKgI/S7v9tnjBiFU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=MlqJwoeq+BScTPfghDTJzVygoX4VaaUYwz3vyu4z4cRkV4GrCIRKkWqkUJnn7ym4kJGLa+wLlOSeCRbRlZWuru45cLbVoIok1N/NrjYercH3ySts5IHMIL2cz8Kr6mLP/AvqzWbd6rLm/22HNhSosoYoLWpv7jCjlQ/AuF1mg9Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=sv79dZEZ; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=KPIun16L; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="sv79dZEZ"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="KPIun16L" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635230; 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=inKkGcOaoWCjFkpqnB1GAtsANxmMpso8C0jLuD9eLHQ=; b=sv79dZEZJx7oTKuEV7UnJuWKWUsGC2h4y1431LkMSfHF1ObDjfKLPRh5gO+9oODhVA1VSR GRg5NfqVHCmGJicj84bQBYPZOFuq+H13rORZNdFLin/QWnr4E4hc3MEo71wN8bKg3EN/wf eCWswT4JbgsT7YnS8E/bm+I72GLVIVadFFP37g/YqkNwWa8C1Sw3B2BoMnvS07Ug8MXScC VkrZyotaH+O522xz8NJ+tx+vEBX0pgP+B0ikG1gdioL06ZzieaX95dY0xKV2xaHXocrBoi T4qQl+XzrEbiSVJ3NXl+SkmYgVOImZsOTtrJd3oAGhQG0kv7XcW7BEJfyF6tHA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635230; 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=inKkGcOaoWCjFkpqnB1GAtsANxmMpso8C0jLuD9eLHQ=; b=KPIun16LYgfLYdvcAU/XDhet+CUwdS9m1g0vCKhMwpThCqscQRjAqDpzbhewg3VGF7VLyO VGRvao2T48qlSrCg== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao , Petr Mladek , Sergey Senozhatsky Subject: [PATCH v11 02/21] printk: Make vprintk_deferred() public Date: Fri, 4 Jul 2025 15:19:54 +0200 Message-Id: <6e110a17d50d7d6954e17f3194f555d18fe521af.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" vprintk_deferred() is useful for implementing runtime verification reactors. Make it public. Signed-off-by: Nam Cao Reviewed-by: Petr Mladek --- Cc: John Ogness Cc: Sergey Senozhatsky --- include/linux/printk.h | 5 +++++ kernel/printk/internal.h | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index 5b462029d03c..08f1775c60fd 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -154,6 +154,7 @@ int vprintk_emit(int facility, int level, =20 asmlinkage __printf(1, 0) int vprintk(const char *fmt, va_list args); +__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args); =20 asmlinkage __printf(1, 2) __cold int _printk(const char *fmt, ...); @@ -214,6 +215,10 @@ int vprintk(const char *s, va_list args) { return 0; } +__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args) +{ + return 0; +} static inline __printf(1, 2) __cold int _printk(const char *s, ...) { diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 48a24e7b309d..bbed41ad29cf 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -72,7 +72,6 @@ int vprintk_store(int facility, int level, const char *fmt, va_list args); =20 __printf(1, 0) int vprintk_default(const char *fmt, va_list args); -__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args); =20 void __printk_safe_enter(void); void __printk_safe_exit(void); --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 D64982F85DA; Fri, 4 Jul 2025 13:20:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635234; cv=none; b=PiT8AlPH0Xu4yhgNhpFubney8ptrzdUoNK0J9l/s/dNLCI52f0OagsCnDcn1XTN06Gpt8MeF0QT9KRkIhMWoJc+362/n8u/NfsKDnXoiufpPJs+St4AcBypoypcnMUH1qeUxWuiOc2WZnOTUf+16k6V+ENMXiR6jIuRDtzRECzM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635234; c=relaxed/simple; bh=2IXfDh1oS1h6wWEMQZiEwy1hIKMEajle4bNe7OQluPA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bta7PWw2XGodDo+JvszjETjAc4nASkZxOjLktFzB0TcEGYXZNqCtPS6kmBOMMMTYfpEqk1fksrh4lWuPWttHhN+VzAUCfwQf+BBPQrYhv0s0wgqRJdP72LxqwXXgZ3sBvkR0WTlSEUo0+h6PMS195/qeSir2yKIGaNpnx1PTnCk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=zBHSAIMT; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=69Qs/5MK; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="zBHSAIMT"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="69Qs/5MK" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635231; 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=BWqBXMYBmwEqdQKIVhrED21UDRTdi5qDQ7ZTDhJVn3E=; b=zBHSAIMTNYhJIRUIaP0y0Ygqe86ekgDt5DglgIKLsbRJh5MX4l5u+3BmhhDRZMDOj6z+9j 1ZcAVTIMxfdmLuhVxSNHOCO18U2ZWsARLCdT7yeerMHOtKN5xjgDVhWPxx3+f7lblPodBL oyOVKiyxsJdes5GFd9je87w/vy0JHvenKmkUxY5TQ7KPBJOdaGwiGvTLAfK+Nd/Df2lW1p 9hpzX2jmBh4sAHr6Olo1fw54W+05osxixP1HRWtGO1UNTsiLT1/8BaiUCtsoI6MxZWEEb/ KLcUuBWH9tf448Gg18dIq+9g6++/98VeRqwDp7naPVcFRHjAn/ROY26vfVLPGg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635231; 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=BWqBXMYBmwEqdQKIVhrED21UDRTdi5qDQ7ZTDhJVn3E=; b=69Qs/5MKLbVXsXzNVwAwHDNXrI8jRMQfgOH0faQiQ8S8hzqsC7goUshffC+Mi/HLb26Eq1 ozM9UHWPD7wgq6Dw== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao , Petr Mladek , Sergey Senozhatsky Subject: [PATCH v11 03/21] panic: Add vpanic() Date: Fri, 4 Jul 2025 15:19:55 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" vpanic() is useful for implementing runtime verification reactors. Add it. Signed-off-by: Nam Cao Reviewed-by: Petr Mladek --- Cc: John Ogness Cc: Sergey Senozhatsky --- include/linux/panic.h | 3 +++ kernel/panic.c | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/linux/panic.h b/include/linux/panic.h index 4adc65766935..0332c6d6771f 100644 --- a/include/linux/panic.h +++ b/include/linux/panic.h @@ -3,6 +3,7 @@ #define _LINUX_PANIC_H =20 #include +#include #include =20 struct pt_regs; @@ -10,6 +11,8 @@ struct pt_regs; extern long (*panic_blink)(int state); __printf(1, 2) void panic(const char *fmt, ...) __noreturn __cold; +__printf(1, 0) +void vpanic(const char *fmt, va_list args) __noreturn __cold; void nmi_panic(struct pt_regs *regs, const char *msg); void check_panic_on_warn(const char *origin); extern void oops_enter(void); diff --git a/kernel/panic.c b/kernel/panic.c index b0b9a8bf4560..6a1823c383d0 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -309,13 +309,13 @@ static void panic_other_cpus_shutdown(bool crash_kexe= c) /** * panic - halt the system * @fmt: The text string to print + * @args: Arguments for the format string * * Display a message, then perform cleanups. This function never returns. */ -void panic(const char *fmt, ...) +void vpanic(const char *fmt, va_list args) { static char buf[1024]; - va_list args; long i, i_next =3D 0, len; int state =3D 0; int old_cpu, this_cpu; @@ -366,9 +366,7 @@ void panic(const char *fmt, ...) =20 console_verbose(); bust_spinlocks(1); - va_start(args, fmt); len =3D vscnprintf(buf, sizeof(buf), fmt, args); - va_end(args); =20 if (len && buf[len - 1] =3D=3D '\n') buf[len - 1] =3D '\0'; @@ -505,7 +503,17 @@ void panic(const char *fmt, ...) mdelay(PANIC_TIMER_STEP); } } +EXPORT_SYMBOL(vpanic); =20 +/* Identical to vpanic(), except it takes variadic arguments instead of va= _list */ +void panic(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vpanic(fmt, args); + va_end(args); +} EXPORT_SYMBOL(panic); =20 #define TAINT_FLAG(taint, _c_true, _c_false, _module) \ --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 569692F85DD; Fri, 4 Jul 2025 13:20:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635235; cv=none; b=cLsoLBMmUlAg7JVp/aqIJwl7hJWysPsd/pd/1R+vqeMero1tj+Q5nq48lRuN6XwWuEBt50GejehwBaQYnrmwwbcqEbvvhMs9+KFUvH59solE4BeL3iAh9gjwIYnP/FsyA/WqtybRKE7lhLyD6Rd2Z2b/vpf993oftean48cxTvs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635235; c=relaxed/simple; bh=wn2eJuS+zEx8XuEUjHUhCIJA/y0N3h9PIoDYfiC14KY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=WtyhsnUx0KRvUHMkpxbvKg71qnk+HRxVIdM/31vU9h62Ozis0LmWOKnEFk+Ygo/ONCx62vpw9ejYM851Hw6o8BWwDAu5vfz+6st/x9GC0n0kkru9wv6ubh1IIVXfw3+FgpsrDZBKfsvJen0rCm6ITuVHFXmpPCJz174CC+eb7L4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=em2QGl0E; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=ilaLwozY; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="em2QGl0E"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="ilaLwozY" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635231; 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=X6K97kNqS9iVwLaZLV56vbzJZXc6QFuHBHlvLvdFEbg=; b=em2QGl0E+FgENDbpGiB/nB24acfOML27rqIwGpw+cMM7pv17+/Eg5S6pe2vWvBuNfAIah2 l/JhhXERLOk9F5l3RvOfhLWiMPf4ypOuyCu8vqtKKDMi5gsnyob5uxkARFFJZ27cuKJXIs myg8TOk4Z6zBYPP4bC10J4i2JSH9yxxncJ6lew5IhCftwrhzUUEsqCznkC2UwSj32JJYK9 eMEZ3iMisCSU5FVOuLXtFMnCyR94iZz2JhFLIZkZhUMFzEMmXhBTPR+tpNG/gZkm8rjd+X NdPkDyOVUIUh+gfauSDSaAeRZr8bcqzFO7k5CyPBgkOoeQH4pz1pF3DqAEasyA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635231; 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=X6K97kNqS9iVwLaZLV56vbzJZXc6QFuHBHlvLvdFEbg=; b=ilaLwozYtacA3w2ihisCliqhR/WtERzqhhNQ5Dzq3mXJwY/6RAueUFt89uSAaYyPQAnwu3 aGB+Jw+dEvnWwoBA== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao , Petr Mladek , Sergey Senozhatsky Subject: [PATCH v11 04/21] rv: Let the reactors take care of buffers Date: Fri, 4 Jul 2025 15:19:56 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Each RV monitor has one static buffer to send to the reactors. If multiple errors are detected simultaneously, the one buffer could be overwritten. Instead, leave it to the reactors to handle buffering. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- Cc: Petr Mladek Cc: John Ogness Cc: Sergey Senozhatsky --- include/linux/rv.h | 9 +++++-- include/rv/da_monitor.h | 45 +++++++------------------------- kernel/trace/rv/reactor_panic.c | 8 ++++-- kernel/trace/rv/reactor_printk.c | 8 ++++-- kernel/trace/rv/rv_reactors.c | 2 +- 5 files changed, 30 insertions(+), 42 deletions(-) diff --git a/include/linux/rv.h b/include/linux/rv.h index 3452b5e4b29e..9428e62eb8e9 100644 --- a/include/linux/rv.h +++ b/include/linux/rv.h @@ -38,7 +38,7 @@ union rv_task_monitor { struct rv_reactor { const char *name; const char *description; - void (*react)(char *msg); + __printf(1, 2) void (*react)(const char *msg, ...); }; #endif =20 @@ -50,7 +50,7 @@ struct rv_monitor { void (*disable)(void); void (*reset)(void); #ifdef CONFIG_RV_REACTORS - void (*react)(char *msg); + __printf(1, 2) void (*react)(const char *msg, ...); #endif }; =20 @@ -64,6 +64,11 @@ void rv_put_task_monitor_slot(int slot); bool rv_reacting_on(void); int rv_unregister_reactor(struct rv_reactor *reactor); int rv_register_reactor(struct rv_reactor *reactor); +#else +static inline bool rv_reacting_on(void) +{ + return false; +} #endif /* CONFIG_RV_REACTORS */ =20 #endif /* CONFIG_RV */ diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h index 510c88bfabd4..15f9ed4e4bb6 100644 --- a/include/rv/da_monitor.h +++ b/include/rv/da_monitor.h @@ -19,45 +19,22 @@ #ifdef CONFIG_RV_REACTORS =20 #define DECLARE_RV_REACTING_HELPERS(name, type) \ -static char REACT_MSG_##name[1024]; \ - \ -static inline char *format_react_msg_##name(type curr_state, type event) = \ -{ \ - snprintf(REACT_MSG_##name, 1024, \ - "rv: monitor %s does not allow event %s on state %s\n", \ - #name, \ - model_get_event_name_##name(event), \ - model_get_state_name_##name(curr_state)); \ - return REACT_MSG_##name; \ -} \ - \ -static void cond_react_##name(char *msg) \ +static void cond_react_##name(type curr_state, type event) \ { \ - if (rv_##name.react) \ - rv_##name.react(msg); \ -} \ - \ -static bool rv_reacting_on_##name(void) \ -{ \ - return rv_reacting_on(); \ + if (!rv_reacting_on() || !rv_##name.react) \ + return; \ + rv_##name.react("rv: monitor %s does not allow event %s on state %s\n", = \ + #name, \ + model_get_event_name_##name(event), \ + model_get_state_name_##name(curr_state)); \ } =20 #else /* CONFIG_RV_REACTOR */ =20 #define DECLARE_RV_REACTING_HELPERS(name, type) \ -static inline char *format_react_msg_##name(type curr_state, type event) = \ -{ \ - return NULL; \ -} \ - \ -static void cond_react_##name(char *msg) \ +static void cond_react_##name(type curr_state, type event) \ { \ return; \ -} \ - \ -static bool rv_reacting_on_##name(void) \ -{ \ - return 0; \ } #endif =20 @@ -170,8 +147,7 @@ da_event_##name(struct da_monitor *da_mon, enum events_= ##name event) \ return true; \ } \ \ - if (rv_reacting_on_##name()) \ - cond_react_##name(format_react_msg_##name(curr_state, event)); \ + cond_react_##name(curr_state, event); \ \ trace_error_##name(model_get_state_name_##name(curr_state), \ model_get_event_name_##name(event)); \ @@ -202,8 +178,7 @@ static inline bool da_event_##name(struct da_monitor *d= a_mon, struct task_struct return true; \ } \ \ - if (rv_reacting_on_##name()) \ - cond_react_##name(format_react_msg_##name(curr_state, event)); \ + cond_react_##name(curr_state, event); \ \ trace_error_##name(tsk->pid, \ model_get_state_name_##name(curr_state), \ diff --git a/kernel/trace/rv/reactor_panic.c b/kernel/trace/rv/reactor_pani= c.c index 0186ff4cbd0b..74c6bcc2c749 100644 --- a/kernel/trace/rv/reactor_panic.c +++ b/kernel/trace/rv/reactor_panic.c @@ -13,9 +13,13 @@ #include #include =20 -static void rv_panic_reaction(char *msg) +__printf(1, 2) static void rv_panic_reaction(const char *msg, ...) { - panic(msg); + va_list args; + + va_start(args, msg); + vpanic(msg, args); + va_end(args); } =20 static struct rv_reactor rv_panic =3D { diff --git a/kernel/trace/rv/reactor_printk.c b/kernel/trace/rv/reactor_pri= ntk.c index 178759dbf89f..2dae2916c05f 100644 --- a/kernel/trace/rv/reactor_printk.c +++ b/kernel/trace/rv/reactor_printk.c @@ -12,9 +12,13 @@ #include #include =20 -static void rv_printk_reaction(char *msg) +__printf(1, 2) static void rv_printk_reaction(const char *msg, ...) { - printk_deferred(msg); + va_list args; + + va_start(args, msg); + vprintk_deferred(msg, args); + va_end(args); } =20 static struct rv_reactor rv_printk =3D { diff --git a/kernel/trace/rv/rv_reactors.c b/kernel/trace/rv/rv_reactors.c index 9501ca886d83..740603670dd1 100644 --- a/kernel/trace/rv/rv_reactors.c +++ b/kernel/trace/rv/rv_reactors.c @@ -490,7 +490,7 @@ void reactor_cleanup_monitor(struct rv_monitor_def *mde= f) /* * Nop reactor register */ -static void rv_nop_reaction(char *msg) +__printf(1, 2) static void rv_nop_reaction(const char *msg, ...) { } =20 --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 C22EC2FC3DA; Fri, 4 Jul 2025 13:20:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635236; cv=none; b=Wutr8FtAyEwktFHVwCeyrPsjVWZ4tT1vDmNqokJfwu9f4xqmWlGmL2forDG8nrOh0ybSjABigSlPxD0MglKHUYoPNPXx+791qNRDR/XmD+En3nTNJ+So++NmF3xVx8CKqHSoZTDkx0PVVLDhxUG7hitxh8n/y/ShvLp3Qx1QfP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635236; c=relaxed/simple; bh=1tyueKVzM1VJ1WDma6WPKB1nQNEG95uHkefHtTlXLuY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=k6+MJpiUnN0QuOk8cQQykJUt/yZSCPPPbcbd/zPmAVK8m75C/2Hw7nZmTHM8CqJ6pF+vqwF1aW2Aqt6mZkdZne/Y5ZHkV7TTRHinNyxcrXIuv0ZFlkqJVRM6RibjetzbU3+VYpjRJ4vg68GNzcQYvdg5IIV14AqLwesLnPViPZo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=B268iHKV; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=7NSSG9lH; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="B268iHKV"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="7NSSG9lH" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635232; 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=quxmvFOpWEdlDXGAnbEr+RnyianRn/nmBROLE3F3T+I=; b=B268iHKV5vbhNOKPH3U1IHBYWgMwoiK7hk2tzXbWoAXU+yZ50zE2Oq3JsZGG1DnjWOP9U/ f8XLN090hhRVIJreb385k1XyUPdNipSlDBMqe3x2EEWUGUSiDduk6Zm3iImypBScy5XWoj g85Yu5bYMp2ljexo/eAtqyMxFrQLzV1BnXcE7jS4zW4FJxw/4fSNLk0fIqWOY8dJhVWLHT 0HV1hBAQCN2hnepJ3KLHG+E0m+7K8iCEItRAxSr/XiSy/KnhsiddDLibVoGTvyWISdA/08 jpyqklmeBE9Zp3/ccEofAbL584E3JQCKQfIzQwv5NQyjBhWKaa1A3J9yQePlBA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635232; 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=quxmvFOpWEdlDXGAnbEr+RnyianRn/nmBROLE3F3T+I=; b=7NSSG9lH8jJ1Hy/7l4y/FN8IsIinvYjrWw2Kd/smLlMErRTPmTHeV3SM1+PNnKZeKA5MCG vyYGtIFWzIuy9OAQ== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 05/21] verification/dot2k: Make a separate dot2k_templates/Kconfig_container Date: Fri, 4 Jul 2025 15:19:57 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" A generated container's Kconfig has an incorrect line: select DA_MON_EVENTS_IMPLICIT This is due to container generation uses the same template Kconfig file as deterministic automaton monitor. Therefore, make a separate Kconfig template for container which has only the necessaries for container. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- Alternatively, we could also modify the Python scripts. I tried both and this solution seems cleaner. --- tools/verification/dot2/dot2k.py | 3 ++- tools/verification/dot2/dot2k_templates/Kconfig_container | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tools/verification/dot2/dot2k_templates/Kconfig_contain= er diff --git a/tools/verification/dot2/dot2k.py b/tools/verification/dot2/dot= 2k.py index 745d35a4a379..dd4b5528a4f2 100644 --- a/tools/verification/dot2/dot2k.py +++ b/tools/verification/dot2/dot2k.py @@ -35,6 +35,7 @@ class dot2k(Dot2c): self.states =3D [] self.main_c =3D self.__read_file(self.monitor_templates_dir + = "main_container.c") self.main_h =3D self.__read_file(self.monitor_templates_dir + = "main_container.h") + self.kconfig =3D self.__read_file(self.monitor_templates_dir += "Kconfig_container") else: super().__init__(file_path, extra_params.get("model_name")) =20 @@ -44,7 +45,7 @@ class dot2k(Dot2c): self.monitor_type =3D MonitorType self.main_c =3D self.__read_file(self.monitor_templates_dir + = "main.c") self.trace_h =3D self.__read_file(self.monitor_templates_dir += "trace.h") - self.kconfig =3D self.__read_file(self.monitor_templates_dir + "Kc= onfig") + self.kconfig =3D self.__read_file(self.monitor_templates_dir += "Kconfig") self.enum_suffix =3D "_%s" % self.name self.description =3D extra_params.get("description", self.name) or= "auto-generated" self.auto_patch =3D extra_params.get("auto_patch") diff --git a/tools/verification/dot2/dot2k_templates/Kconfig_container b/to= ols/verification/dot2/dot2k_templates/Kconfig_container new file mode 100644 index 000000000000..a606111949c2 --- /dev/null +++ b/tools/verification/dot2/dot2k_templates/Kconfig_container @@ -0,0 +1,5 @@ +config RV_MON_%%MODEL_NAME_UP%% + depends on RV + bool "%%MODEL_NAME%% monitor" + help + %%DESCRIPTION%% --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 A0AA62F948D; Fri, 4 Jul 2025 13:20:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635236; cv=none; b=qUbsucX5OmG0VsrgW2GffLC6K3g+G+ivaAlUkFMxO4VxpluhXNslY8ufolndiKGJOGQSkezHV6bqsmRYFzZ7J0BSXWzEE9oXc7Zl21R7Wdq5UJ+JhpX3gOy9BZF0rFsJBOYvNBfZv/y6p1a2ViNAVNmbYJz2qQwth9HFmRYIrww= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635236; c=relaxed/simple; bh=2mK6sinmKtyV1wCugMEgB2iIJSIT6o63JPL6+Fwhw2w=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=W04B57/7N2F4ouvv1Zk7zV+I8Ibo02Ni5dMDacoMBuzrx9rixxAyDW9AL2vZBBLvF2IxtUS2AMpWZo+x3rsbiduAxJsufnRS74xfrzQnAVC6csB+ILQaepQ+NmZXRyfMPlwLf4UyRvRQC39fa+NF3EUfrczI2LjjVce/EGFAOWE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=N5oSZICR; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=BFvc4WNI; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="N5oSZICR"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="BFvc4WNI" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635233; 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=+WCyvCXKRf/F4qW3dfDg+7ZIfppz2CYPNGxpMfZcwg0=; b=N5oSZICRtLrlxrRxLecbwDslgCok4Xzg6oOKgpvLunCQo/5x34oSEKuR9oxUCg4DBu80uC RhtdVYFLcGyDLH+ZT//DQ+EpOjOSFpCOTo/00jRLmNcqrh5ugezuP3AA/76EbJYfv4vBpI 9ZmQexGNWd9SMTsqYoxfVCclL82ChNzL4U2XgeouTdMHmP7NJ5iYbLGnFWO6Ro3CD22ono +IALe78EZRKaNjblMXZ36CREpyq+4Ifps2eXkKUYlTCB8Dy+X6YJ4+WcQ/xPLkNJAZhX4/ AfomGfIAL1jCZi//RzL9GeNXx2CjWhlb6YZnyWBJVhIXk98UbnfR+snyuc0k8Q== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635233; 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=+WCyvCXKRf/F4qW3dfDg+7ZIfppz2CYPNGxpMfZcwg0=; b=BFvc4WNIXMWt0P1xUQ3fCnnZjFVazuUEFl6BvfAK5XEstv/4Q+mlxxbaXmwEpF4h0hA7vB JBdr5Ml42HJxQ4DA== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 06/21] verification/dot2k: Remove __buff_to_string() Date: Fri, 4 Jul 2025 15:19:58 +0200 Message-Id: <860d6002659f604c743e0f23d5cf3c99ea6a82d8.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" str.join() can do what __buff_to_string() does. Therefore replace __buff_to_string() to make the scripts more pythonic. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- tools/verification/dot2/dot2k.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tools/verification/dot2/dot2k.py b/tools/verification/dot2/dot= 2k.py index dd4b5528a4f2..0922754454b9 100644 --- a/tools/verification/dot2/dot2k.py +++ b/tools/verification/dot2/dot2k.py @@ -109,15 +109,6 @@ class dot2k(Dot2c): fd.close() return content =20 - def __buff_to_string(self, buff): - string =3D "" - - for line in buff: - string =3D string + line + "\n" - - # cut off the last \n - return string[:-1] - def fill_monitor_type(self): return self.monitor_type.upper() =20 @@ -148,19 +139,19 @@ class dot2k(Dot2c): buff.append("\tda_%s_%s(%s%s);" % (handle, self.name, even= t, self.enum_suffix)); buff.append("}") buff.append("") - return self.__buff_to_string(buff) + return '\n'.join(buff) =20 def fill_tracepoint_attach_probe(self): buff =3D [] for event in self.events: buff.append("\trv_attach_trace_probe(\"%s\", /* XXX: tracepoin= t */, handle_%s);" % (self.name, event)) - return self.__buff_to_string(buff) + return '\n'.join(buff) =20 def fill_tracepoint_detach_helper(self): buff =3D [] for event in self.events: buff.append("\trv_detach_trace_probe(\"%s\", /* XXX: tracepoin= t */, handle_%s);" % (self.name, event)) - return self.__buff_to_string(buff) + return '\n'.join(buff) =20 def fill_main_c(self): main_c =3D self.main_c @@ -210,7 +201,7 @@ class dot2k(Dot2c): buff =3D self.fill_model_h_header() buff +=3D self.format_model() =20 - return self.__buff_to_string(buff) + return '\n'.join(buff) =20 def fill_monitor_class_type(self): if self.monitor_type =3D=3D "per_task": @@ -242,7 +233,7 @@ class dot2k(Dot2c): tp_args_c =3D ", ".join([b for a,b in tp_args]) buff.append(" TP_PROTO(%s)," % tp_proto_c) buff.append(" TP_ARGS(%s)" % tp_args_c) - return self.__buff_to_string(buff) + return '\n'.join(buff) =20 def fill_monitor_deps(self): buff =3D [] @@ -250,7 +241,7 @@ class dot2k(Dot2c): if self.parent: buff.append(" depends on RV_MON_%s" % self.parent.upper()) buff.append(" default y") - return self.__buff_to_string(buff) + return '\n'.join(buff) =20 def fill_trace_h(self): trace_h =3D self.trace_h --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 3DC352FCE2D; Fri, 4 Jul 2025 13:20:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635236; cv=none; b=clRmdvGnnZQ590hdAeJOQYqTB2a1xYRmuCeo52PPbGzFcXiBh6mXwfOYdM9wKyg4lNX4zbPw3JURGU72YMuuYj9hsS7ySXXZYZB6cqv/K5bM00HYxfrAws3VDjFRTiNYnDsWhlAasu60J3IgJiCHm7TVfGJgW1LIKa+Ls9+F8ws= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635236; c=relaxed/simple; bh=H9V8DEOULiOnbQER9jdq86jI9UV0AVKo/mqnQ8wukQU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=O635iALhQU8CBUOI33sj2VLHH4ThxreerCxoXeUUk5XR8Q+3UXvcDrvXPiTe5+iT1mm2VPHfrZQacACXs9bQJ+vNBeCBglzNoYLuTn5y6LqZMsPEnLbPtkfish6XF7mEJLP0HZsAG/EDfQP1lPK7QG6GB+/re3zewdEItz9ZADQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=DFkfRhjQ; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=PfCMDKHn; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="DFkfRhjQ"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="PfCMDKHn" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635233; 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=CbJkEpwB3OdGpjoifJXvu2A5D6lki3gos/XOzAV2UjA=; b=DFkfRhjQaZAKd6C6tLboQ63Eu5xJJygIRFMgj7LswzfNTiWtmYc9mNdyswqm4fDQLFmh9v 4KCcpN5T9EyxJMo06v7POGgRpuelmCdoiloAr0ZAS+OHPzsexshVl0mazTjWrho/Mos/ui q6F9XM6nAwpWd9J+69L7yLlKGCnfuUMD244aW1rfEsHrZwNAtH9+546Dz9Az1VX9P0AFYD bYR9FlN+JGzYf6T2elXTxK/pTPE+7C7atV6RMiSIMS3rIoIsEMbik5uw3Y33xUS6ymYz0F /7UI+SYjuPdtnjHFIiBLhwrQiCn7y5mYYTTqUD3BHZBjpf4+EFi9DUc93HL9Kg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635233; 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=CbJkEpwB3OdGpjoifJXvu2A5D6lki3gos/XOzAV2UjA=; b=PfCMDKHnjyCZSvJT9QVJXSj8vHDB8houniwT0PkGQwxe/VHZOy5omrQcbP9/S5O0A8NNE4 56a+tbW6n0yOv+Cg== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 07/21] verification/dot2k: Replace is_container() hack with subparsers Date: Fri, 4 Jul 2025 15:19:59 +0200 Message-Id: <23c4e3c6e10c39e86d8e6a289208dde407efc4a8.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" dot2k is used for both generating deterministic automaton (DA) monitor and generating container monitor. Generating DA monitor and generating container requires different parameters. This is implemented by peeking at sys.argv and check whether "--container" is specified, and use that information to make some parameters optional or required. This works, but is quite hacky and ugly. Replace this hack with Python's built-in subparsers. The old commands: python3 dot2/dot2k -d wip.dot -t per_cpu python3 dot2/dot2k -n sched --container are equivalent to the new commands: python3 dot2/dot2k monitor -d wip.dot -t per_cpu python3 dot2/dot2k container -n sched Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- tools/verification/dot2/dot2k | 37 +++++++++++++++++--------------- tools/verification/dot2/dot2k.py | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/tools/verification/dot2/dot2k b/tools/verification/dot2/dot2k index 767064f415e7..133fb17d9d47 100644 --- a/tools/verification/dot2/dot2k +++ b/tools/verification/dot2/dot2k @@ -13,30 +13,33 @@ if __name__ =3D=3D '__main__': import argparse import sys =20 - def is_container(): - """Should work even before parsing the arguments""" - return "-c" in sys.argv or "--container" in sys.argv - parser =3D argparse.ArgumentParser(description=3D'transform .dot file = into kernel rv monitor') - parser.add_argument('-d', "--dot", dest=3D"dot_file", required=3Dnot i= s_container()) - parser.add_argument('-t', "--monitor_type", dest=3D"monitor_type", req= uired=3Dnot is_container(), - help=3Df"Available options: {', '.join(dot2k.monit= or_types.keys())}") - parser.add_argument('-n', "--model_name", dest=3D"model_name", require= d=3Dis_container()) parser.add_argument("-D", "--description", dest=3D"description", requi= red=3DFalse) parser.add_argument("-a", "--auto_patch", dest=3D"auto_patch", action=3D"store_true", required=3DFalse, help=3D"Patch the kernel in place") - parser.add_argument("-p", "--parent", dest=3D"parent", - required=3DFalse, help=3D"Create a monitor nested = to parent") - parser.add_argument("-c", "--container", dest=3D"container", - action=3D"store_true", required=3DFalse, - help=3D"Create an empty monitor to be used as a co= ntainer") + + subparsers =3D parser.add_subparsers(dest=3D"subcmd", required=3DTrue) + + monitor_parser =3D subparsers.add_parser("monitor") + monitor_parser.add_argument('-n', "--model_name", dest=3D"model_name") + monitor_parser.add_argument("-p", "--parent", dest=3D"parent", + required=3DFalse, help=3D"Create a monitor= nested to parent") + monitor_parser.add_argument('-d', "--dot", dest=3D"dot_file") + monitor_parser.add_argument('-t', "--monitor_type", dest=3D"monitor_ty= pe", + help=3Df"Available options: {', '.join(dot= 2k.monitor_types.keys())}") + + container_parser =3D subparsers.add_parser("container") + container_parser.add_argument('-n', "--model_name", dest=3D"model_name= ", required=3DTrue) + params =3D parser.parse_args() =20 - if not is_container(): - print("Opening and parsing the dot file %s" % params.dot_file) try: - monitor=3Ddot2k(params.dot_file, params.monitor_type, vars(params)) + if params.subcmd =3D=3D "monitor": + print("Opening and parsing the dot file %s" % params.dot_file) + monitor =3D dot2k(params.dot_file, params.monitor_type, vars(p= arams)) + else: + monitor =3D dot2k(None, None, vars(params)) except Exception as e: print('Error: '+ str(e)) print("Sorry : :-(") @@ -45,7 +48,7 @@ if __name__ =3D=3D '__main__': print("Writing the monitor into the directory %s" % monitor.name) monitor.print_files() print("Almost done, checklist") - if not is_container(): + if params.subcmd =3D=3D "monitor": print(" - Edit the %s/%s.c to add the instrumentation" % (monitor= .name, monitor.name)) print(monitor.fill_tracepoint_tooltip()) print(monitor.fill_makefile_tooltip()) diff --git a/tools/verification/dot2/dot2k.py b/tools/verification/dot2/dot= 2k.py index 0922754454b9..9ec99e297012 100644 --- a/tools/verification/dot2/dot2k.py +++ b/tools/verification/dot2/dot2k.py @@ -19,7 +19,7 @@ class dot2k(Dot2c): monitor_type =3D "per_cpu" =20 def __init__(self, file_path, MonitorType, extra_params=3D{}): - self.container =3D extra_params.get("container") + self.container =3D extra_params.get("subcmd") =3D=3D "container" self.parent =3D extra_params.get("parent") self.__fill_rv_templates_dir() =20 --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 2ECD02FD588; Fri, 4 Jul 2025 13:20:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635238; cv=none; b=t5jmRwX97XUqJ7wQwZlUeiHk8TeTypjYuT9U/Tob4f2AMCu/ESX6YMtT3MaqGK8QSDNXzw4l2u21x9oc5Os1FM4rX1PxSGe/3SVVOW9oTYk6phpjBw/ESI6Z1haVqVdcyhEnsdCzSGODhUvHrsSis+UQYbn+GJiIcYWWc2hmRCA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635238; c=relaxed/simple; bh=MRg+w2iH0HGF5UyuFu3lFXx9krIj2AUo3GAFy7nbrK8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=pfh5oMbQFl6isbWOKCV0zsMh28P56/Dj1cgxKlYBcSmSl6ebaLkX7FQs6GwYAqwZrvPd1+O+/+ncf3Jex3EXmnz0i/eEtWbFStv8lfd0ekYTHIjI66h+696Yoc6tkToct0rlRyEX+NmzkwGJPDO7pihc4x+GxlnRRPYzWufmNOA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=bdlSgWiK; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=TjBqI7NG; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="bdlSgWiK"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="TjBqI7NG" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635234; 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=wd36I9Oi5n/Lmp8CkDPUxkaX/ZJRiNSgqZM9aUNzkIY=; b=bdlSgWiKDkRMQlDdQRAtbeXd8yCCOFmJ6fug3oCQdwnyXITSYBph3XXzJ3s9HJD2QaRDT0 DzS4tOtCzSbw/mIQ0Gp9RCtBRTXe4CV3z5gB7Kswy48XYv55QLDoaumklXOMO3PDRrRedh VXEPZPNllwT1mCJ3cJ9yWTMcf16buTfFcZ+crDbarUYpJkcJINzOXoMJTicyIe4Q5S+06Z FhibmgXc7F6j0zNstzmf1kSZkU35YpHhpVj9b4Hu8g8LoE8pK/vuwssK94TH+OW7EdfCJp eRgXlZhbc8/1Sru4D3ohOlfQEWM2jKH6bRv/589XJHKLBg6X9MlW710MoqfbIw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635234; 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=wd36I9Oi5n/Lmp8CkDPUxkaX/ZJRiNSgqZM9aUNzkIY=; b=TjBqI7NGwFvkllC5FwknBYrFafmiRnaoCFjf3BTvV1KJBqutesapgsWraDJHNzhcZXTCZ4 hQNZZKeVOsHrPvDg== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 08/21] rv: rename CONFIG_DA_MON_EVENTS to CONFIG_RV_MON_EVENTS Date: Fri, 4 Jul 2025 15:20:00 +0200 Message-Id: <69ad5df52ff99a08d0a855c425dfd18b9f59fbd9.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" CONFIG_DA_MON_EVENTS is not specific to deterministic automaton. It could be used for other monitor types. Therefore rename it to CONFIG_RV_MON_EVENTS. This prepares for the introduction of linear temporal logic monitor. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- kernel/trace/rv/Kconfig | 6 +++--- kernel/trace/rv/rv.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index b39f36013ef2..6cdffc04b73c 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -1,14 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only # -config DA_MON_EVENTS +config RV_MON_EVENTS bool =20 config DA_MON_EVENTS_IMPLICIT - select DA_MON_EVENTS + select RV_MON_EVENTS bool =20 config DA_MON_EVENTS_ID - select DA_MON_EVENTS + select RV_MON_EVENTS bool =20 menuconfig RV diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c index e4077500a91d..e25d65fe432a 100644 --- a/kernel/trace/rv/rv.c +++ b/kernel/trace/rv/rv.c @@ -143,7 +143,7 @@ #include #include =20 -#ifdef CONFIG_DA_MON_EVENTS +#ifdef CONFIG_RV_MON_EVENTS #define CREATE_TRACE_POINTS #include #endif --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 2F17A2FD58B; Fri, 4 Jul 2025 13:20:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635239; cv=none; b=jb+1IIo9mi+D/PAiAhy0i7vOQabvoxkk+LQsX0l8pkRXUAds6AoObfAdP71GSp9Q8jquvjXJmF72E+tpC4k5orlJxttxp1dRPPIhHKzdCSospkD1H9zVLB/5+yc1er+wrFQsUHcYncQlC04Lypz/ncUleidfoU/4F3hLDAkm3cM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635239; c=relaxed/simple; bh=x17mpZ7sX8jAXa8NPlj8BPti3RdNXLLznHqcgpSPNLE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nu9L6Vi0x3ug1X13OQLIGX0KEdmqgdzoNZkEcORQnSKwYrA05aCGySgUaQBjsmrMfBmRaJKgAd0bCvLnUIPPPIDwfL6ahapuiQZBywKwTcugDPszlRZBj2awD0ax59XVkcdep5z/Is10SGEGCQz80Uzy6zxfSdP294kIy9ko2oA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=06q8BPFr; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=DWI4I1Ez; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="06q8BPFr"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="DWI4I1Ez" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635234; 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=HqpK2ecQogzE/riTbJrIMj4alR3/q81koVHuN2ddxBw=; b=06q8BPFrHfzmSrunU0jHkXdzcd/OEM2gdigNj4+kvwCsDz1mM2/g3LK/BlJc/D71doVTzt TtvepcT5F+tjXbB8nkQzyDckrRPDpXy1Piv2m991lnYnvRcQIp8/r/L9pVP7ch7iNR8rHG Q9tNPbwvhDomIlmsUhztkTzLxaFzFIkTyReU7tbATEUOm/PXgGEVKYVvRqzi3McEUqTHXW 9rw3Fw6clo4i/h4H9l6Vd/d0d47faT890MYJPAryaq3SqvyLVxtd7gd55emVcmf7az2kNH mUXUHl+hOOEDyJUZWMgiVT2nAbZJTp2hOi1bR2S76QNA720YMHfPZHk0kVdKSw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635234; 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=HqpK2ecQogzE/riTbJrIMj4alR3/q81koVHuN2ddxBw=; b=DWI4I1Ezr4dRtYipBf6/AX1OXmXrdrzKFX53WszSF6+b3btp/btv5e7Y1Y6fMqp48DL5eh UrQLPDa5Oyx1HpDg== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 09/21] verification/dot2k: Prepare the frontend for LTL inclusion Date: Fri, 4 Jul 2025 15:20:01 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" The dot2k tool has some code that can be reused for linear temporal logic monitor. Prepare its frontend for LTL inclusion: 1. Rename to be generic: rvgen 2. Replace the parameter --dot with 2 parameters: --class: to specific the monitor class, can be 'da' or 'ltl' --spec: the monitor specification file, .dot file for DA, and .ltl file for LTL The old command: python3 dot2/dot2k monitor -d wip.dot -t per_cpu is equivalent to the new commands: python3 rvgen monitor -c da -s wip.dot -t per_cpu Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- tools/verification/{dot2 =3D> rvgen}/Makefile | 10 +++++----- .../{dot2/dot2k =3D> rvgen/__main__.py} | 18 +++++++++++++----- tools/verification/{dot2 =3D> rvgen}/dot2c | 2 +- .../{dot2 =3D> rvgen}/dot2k_templates/Kconfig | 0 .../dot2k_templates/Kconfig_container | 0 .../{dot2 =3D> rvgen}/dot2k_templates/main.c | 0 .../dot2k_templates/main_container.c | 0 .../dot2k_templates/main_container.h | 0 .../{dot2 =3D> rvgen}/dot2k_templates/trace.h | 0 .../{dot2 =3D> rvgen/rvgen}/automata.py | 0 .../{dot2 =3D> rvgen/rvgen}/dot2c.py | 2 +- .../{dot2 =3D> rvgen/rvgen}/dot2k.py | 10 +++++----- 12 files changed, 25 insertions(+), 17 deletions(-) rename tools/verification/{dot2 =3D> rvgen}/Makefile (55%) rename tools/verification/{dot2/dot2k =3D> rvgen/__main__.py} (72%) rename tools/verification/{dot2 =3D> rvgen}/dot2c (97%) rename tools/verification/{dot2 =3D> rvgen}/dot2k_templates/Kconfig (100%) rename tools/verification/{dot2 =3D> rvgen}/dot2k_templates/Kconfig_contai= ner (100%) rename tools/verification/{dot2 =3D> rvgen}/dot2k_templates/main.c (100%) rename tools/verification/{dot2 =3D> rvgen}/dot2k_templates/main_container= .c (100%) rename tools/verification/{dot2 =3D> rvgen}/dot2k_templates/main_container= .h (100%) rename tools/verification/{dot2 =3D> rvgen}/dot2k_templates/trace.h (100%) rename tools/verification/{dot2 =3D> rvgen/rvgen}/automata.py (100%) rename tools/verification/{dot2 =3D> rvgen/rvgen}/dot2c.py (99%) rename tools/verification/{dot2 =3D> rvgen/rvgen}/dot2k.py (98%) diff --git a/tools/verification/dot2/Makefile b/tools/verification/rvgen/Ma= kefile similarity index 55% rename from tools/verification/dot2/Makefile rename to tools/verification/rvgen/Makefile index 021beb07a521..cea9c21c3bce 100644 --- a/tools/verification/dot2/Makefile +++ b/tools/verification/rvgen/Makefile @@ -3,7 +3,7 @@ INSTALL=3Dinstall prefix ?=3D /usr bindir ?=3D $(prefix)/bin mandir ?=3D $(prefix)/share/man -miscdir ?=3D $(prefix)/share/dot2 +miscdir ?=3D $(prefix)/share/rvgen srcdir ?=3D $(prefix)/src =20 PYLIB ?=3D $(shell python3 -c 'import sysconfig; print (sysconfig.get_pa= th("purelib"))') @@ -16,11 +16,11 @@ clean: =20 .PHONY: install install: - $(INSTALL) automata.py -D -m 644 $(DESTDIR)$(PYLIB)/dot2/automata.py - $(INSTALL) dot2c.py -D -m 644 $(DESTDIR)$(PYLIB)/dot2/dot2c.py + $(INSTALL) rvgen/automata.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/automata.= py + $(INSTALL) rvgen/dot2c.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/dot2c.py $(INSTALL) dot2c -D -m 755 $(DESTDIR)$(bindir)/ - $(INSTALL) dot2k.py -D -m 644 $(DESTDIR)$(PYLIB)/dot2/dot2k.py - $(INSTALL) dot2k -D -m 755 $(DESTDIR)$(bindir)/ + $(INSTALL) rvgen/dot2k.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/dot2k.py + $(INSTALL) __main__.py -D -m 755 $(DESTDIR)$(bindir)/rvgen =20 mkdir -p ${miscdir}/ cp -rp dot2k_templates $(DESTDIR)$(miscdir)/ diff --git a/tools/verification/dot2/dot2k b/tools/verification/rvgen/__mai= n__.py similarity index 72% rename from tools/verification/dot2/dot2k rename to tools/verification/rvgen/__main__.py index 133fb17d9d47..994d320ad2d1 100644 --- a/tools/verification/dot2/dot2k +++ b/tools/verification/rvgen/__main__.py @@ -9,11 +9,11 @@ # Documentation/trace/rv/da_monitor_synthesis.rst =20 if __name__ =3D=3D '__main__': - from dot2.dot2k import dot2k + from rvgen.dot2k import dot2k import argparse import sys =20 - parser =3D argparse.ArgumentParser(description=3D'transform .dot file = into kernel rv monitor') + parser =3D argparse.ArgumentParser(description=3D'Generate kernel rv m= onitor') parser.add_argument("-D", "--description", dest=3D"description", requi= red=3DFalse) parser.add_argument("-a", "--auto_patch", dest=3D"auto_patch", action=3D"store_true", required=3DFalse, @@ -25,7 +25,9 @@ if __name__ =3D=3D '__main__': monitor_parser.add_argument('-n', "--model_name", dest=3D"model_name") monitor_parser.add_argument("-p", "--parent", dest=3D"parent", required=3DFalse, help=3D"Create a monitor= nested to parent") - monitor_parser.add_argument('-d', "--dot", dest=3D"dot_file") + monitor_parser.add_argument('-c', "--class", dest=3D"monitor_class", + help=3D"Monitor class, either \"da\" or \"= ltl\"") + monitor_parser.add_argument('-s', "--spec", dest=3D"spec", help=3D"Mon= itor specification file") monitor_parser.add_argument('-t', "--monitor_type", dest=3D"monitor_ty= pe", help=3Df"Available options: {', '.join(dot= 2k.monitor_types.keys())}") =20 @@ -36,8 +38,14 @@ if __name__ =3D=3D '__main__': =20 try: if params.subcmd =3D=3D "monitor": - print("Opening and parsing the dot file %s" % params.dot_file) - monitor =3D dot2k(params.dot_file, params.monitor_type, vars(p= arams)) + print("Opening and parsing the specification file %s" % params= .spec) + if params.monitor_class =3D=3D "da": + monitor =3D dot2k(params.spec, params.monitor_type, vars(p= arams)) + elif params.monitor_class =3D=3D "ltl": + raise NotImplementedError + else: + print("Unknown monitor class:", params.monitor_class) + sys.exit(1) else: monitor =3D dot2k(None, None, vars(params)) except Exception as e: diff --git a/tools/verification/dot2/dot2c b/tools/verification/rvgen/dot2c similarity index 97% rename from tools/verification/dot2/dot2c rename to tools/verification/rvgen/dot2c index 3fe89ab88b65..bf0c67c5b66c 100644 --- a/tools/verification/dot2/dot2c +++ b/tools/verification/rvgen/dot2c @@ -14,7 +14,7 @@ # Documentation/trace/rv/deterministic_automata.rst =20 if __name__ =3D=3D '__main__': - from dot2 import dot2c + from rvgen import dot2c import argparse import sys =20 diff --git a/tools/verification/dot2/dot2k_templates/Kconfig b/tools/verifi= cation/rvgen/dot2k_templates/Kconfig similarity index 100% rename from tools/verification/dot2/dot2k_templates/Kconfig rename to tools/verification/rvgen/dot2k_templates/Kconfig diff --git a/tools/verification/dot2/dot2k_templates/Kconfig_container b/to= ols/verification/rvgen/dot2k_templates/Kconfig_container similarity index 100% rename from tools/verification/dot2/dot2k_templates/Kconfig_container rename to tools/verification/rvgen/dot2k_templates/Kconfig_container diff --git a/tools/verification/dot2/dot2k_templates/main.c b/tools/verific= ation/rvgen/dot2k_templates/main.c similarity index 100% rename from tools/verification/dot2/dot2k_templates/main.c rename to tools/verification/rvgen/dot2k_templates/main.c diff --git a/tools/verification/dot2/dot2k_templates/main_container.c b/too= ls/verification/rvgen/dot2k_templates/main_container.c similarity index 100% rename from tools/verification/dot2/dot2k_templates/main_container.c rename to tools/verification/rvgen/dot2k_templates/main_container.c diff --git a/tools/verification/dot2/dot2k_templates/main_container.h b/too= ls/verification/rvgen/dot2k_templates/main_container.h similarity index 100% rename from tools/verification/dot2/dot2k_templates/main_container.h rename to tools/verification/rvgen/dot2k_templates/main_container.h diff --git a/tools/verification/dot2/dot2k_templates/trace.h b/tools/verifi= cation/rvgen/dot2k_templates/trace.h similarity index 100% rename from tools/verification/dot2/dot2k_templates/trace.h rename to tools/verification/rvgen/dot2k_templates/trace.h diff --git a/tools/verification/dot2/automata.py b/tools/verification/rvgen= /rvgen/automata.py similarity index 100% rename from tools/verification/dot2/automata.py rename to tools/verification/rvgen/rvgen/automata.py diff --git a/tools/verification/dot2/dot2c.py b/tools/verification/rvgen/rv= gen/dot2c.py similarity index 99% rename from tools/verification/dot2/dot2c.py rename to tools/verification/rvgen/rvgen/dot2c.py index fa2816ac7b61..6009caf568d9 100644 --- a/tools/verification/dot2/dot2c.py +++ b/tools/verification/rvgen/rvgen/dot2c.py @@ -13,7 +13,7 @@ # For further information, see: # Documentation/trace/rv/deterministic_automata.rst =20 -from dot2.automata import Automata +from .automata import Automata =20 class Dot2c(Automata): enum_suffix =3D "" diff --git a/tools/verification/dot2/dot2k.py b/tools/verification/rvgen/rv= gen/dot2k.py similarity index 98% rename from tools/verification/dot2/dot2k.py rename to tools/verification/rvgen/rvgen/dot2k.py index 9ec99e297012..e29462413194 100644 --- a/tools/verification/dot2/dot2k.py +++ b/tools/verification/rvgen/rvgen/dot2k.py @@ -8,13 +8,13 @@ # For further information, see: # Documentation/trace/rv/da_monitor_synthesis.rst =20 -from dot2.dot2c import Dot2c +from .dot2c import Dot2c import platform import os =20 class dot2k(Dot2c): monitor_types =3D { "global" : 1, "per_cpu" : 2, "per_task" : 3 } - monitor_templates_dir =3D "dot2/dot2k_templates/" + monitor_templates_dir =3D "rvgen/dot2k_templates/" rv_dir =3D "kernel/trace/rv" monitor_type =3D "per_cpu" =20 @@ -60,14 +60,14 @@ class dot2k(Dot2c): if platform.system() !=3D "Linux": raise OSError("I can only run on Linux.") =20 - kernel_path =3D "/lib/modules/%s/build/tools/verification/dot2/dot= 2k_templates/" % (platform.release()) + kernel_path =3D "/lib/modules/%s/build/tools/verification/rvgen/do= t2k_templates/" % (platform.release()) =20 if os.path.exists(kernel_path): self.monitor_templates_dir =3D kernel_path return =20 - if os.path.exists("/usr/share/dot2/dot2k_templates/"): - self.monitor_templates_dir =3D "/usr/share/dot2/dot2k_template= s/" + if os.path.exists("/usr/share/rvgen/dot2k_templates/"): + self.monitor_templates_dir =3D "/usr/share/rvgen/dot2k_templat= es/" return =20 raise FileNotFoundError("Could not find the template directory, do= you have the kernel source installed?") --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 84C1A2FF492; Fri, 4 Jul 2025 13:20:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635240; cv=none; b=iE5ANt06c4rdJ9C+pG4D+NyGTzGMxkIycpI3EcTajgJsgsQOczjC/OoHMuKzuIz0LMb2Idk/3kwj7RHvpJJRrSSnK1BR0Ff/mjNBy1N2vqWVA4SLpMy4zWE9i1NkV9KyVmlo3CG8J8O3aCOElgMPf25YiuISRkQD5yAet0nzdEg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635240; c=relaxed/simple; bh=WgE1aO9YUvOmlhuTjVRspOHWrraepbPoXdmSTVuPrz4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=A64ExRMbidpUQP9/jdkqCp3ENwPAMv/xTumiBmLBfb0yai2kfzgem+RCrRUzPDSfldG7tgGFGk8VboP/+BAI2mFH/nj5ReUdxId13uziU/Fb92PhOAGPrIm/tsUz+wecl54hVnd1h5ogzpSdYtdzIeC1ptxzA9n0nrDOVZ4n1lo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=pAgtoTwL; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=uQLC9bdl; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="pAgtoTwL"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="uQLC9bdl" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635234; 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=WwJdSQU9Mp7gY25s96zSaz0i/71ZPlHWpcJ0xxxuTBQ=; b=pAgtoTwLBpU5MrSFotMwA/D6E2PjCcHJklgVGNKRZKNs1OUVObmotzytCbPCOnC5fkW3wS L21eDGssK1oMC4JlVYDEWZDuuFVVFi38stN0sFxMME8D1PKoBZPBsBFani8y3ZqFU7Tv9a BWrBrjnKNqK6/sNaothpc4ffp61pGWNrgu7ltYLgLRpcyrHYTX7G1WMIicZN/ceThWzwyc ijJoM+e8w3Gw85OWvobzNAIZIb29JXWbwJOdPmkRKDGGdgrJBSahPi6QUYUd/3+F5TB+7B f82/LLrppdnJR3f5Y2VLUwvndYm+8/MaqvPNJ3+mkHp6Oyg2C+oL4AOCXQq9fA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635234; 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=WwJdSQU9Mp7gY25s96zSaz0i/71ZPlHWpcJ0xxxuTBQ=; b=uQLC9bdly0qhj4b2xgn0HAHHsDIaQLy+mgyMQVl6nuq6u6mzss5C5VGAPmg6KrAEz4HOuf 6gB+iSaTHdZw9RAg== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 10/21] Documentation/rv: Prepare monitor synthesis document for LTL inclusion Date: Fri, 4 Jul 2025 15:20:02 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Monitor synthesis from deterministic automaton and linear temporal logic have a lot in common. Therefore a single document should describe both. Change da_monitor_synthesis.rst to monitor_synthesis.rst. LTL monitor synthesis will be added to this file by a follow-up commit. This makes the diff far easier to read. If renaming and adding LTL info is done in a single commit, git wouldn't recognize it as a rename, but a file removal and a file addition. While at it, correct the old dot2k commands to the new rvgen commands. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- Documentation/trace/rv/index.rst | 2 +- ...or_synthesis.rst =3D> monitor_synthesis.rst} | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) rename Documentation/trace/rv/{da_monitor_synthesis.rst =3D> monitor_synth= esis.rst} (92%) diff --git a/Documentation/trace/rv/index.rst b/Documentation/trace/rv/inde= x.rst index e80e0057feb4..8e411b76ec82 100644 --- a/Documentation/trace/rv/index.rst +++ b/Documentation/trace/rv/index.rst @@ -8,7 +8,7 @@ Runtime Verification =20 runtime-verification.rst deterministic_automata.rst - da_monitor_synthesis.rst + monitor_synthesis.rst da_monitor_instrumentation.rst monitor_wip.rst monitor_wwnr.rst diff --git a/Documentation/trace/rv/da_monitor_synthesis.rst b/Documentatio= n/trace/rv/monitor_synthesis.rst similarity index 92% rename from Documentation/trace/rv/da_monitor_synthesis.rst rename to Documentation/trace/rv/monitor_synthesis.rst index 0a92729c8a9b..85624062073b 100644 --- a/Documentation/trace/rv/da_monitor_synthesis.rst +++ b/Documentation/trace/rv/monitor_synthesis.rst @@ -1,5 +1,5 @@ -Deterministic Automata Monitor Synthesis -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Runtime Verification Monitor Synthesis +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 The starting point for the application of runtime verification (RV) techni= ques is the *specification* or *modeling* of the desired (or undesired) behavior @@ -36,24 +36,24 @@ below:: | +----> panic ? +-------> =20 -DA monitor synthesis +RV monitor synthesis -------------------- =20 The synthesis of automata-based models into the Linux *RV monitor* abstrac= tion -is automated by the dot2k tool and the rv/da_monitor.h header file that +is automated by the rvgen tool and the rv/da_monitor.h header file that contains a set of macros that automatically generate the monitor's code. =20 -dot2k +rvgen ----- =20 -The dot2k utility leverages dot2c by converting an automaton model in +The rvgen utility leverages dot2c by converting an automaton model in the DOT format into the C representation [1] and creating the skeleton of a kernel monitor in C. =20 For example, it is possible to transform the wip.dot model present in [1] into a per-cpu monitor with the following command:: =20 - $ dot2k -d wip.dot -t per_cpu + $ rvgen monitor -c da -s wip.dot -t per_cpu =20 This will create a directory named wip/ with the following files: =20 @@ -87,7 +87,7 @@ the second for monitors with per-cpu instances, and the t= hird with per-task instances. =20 In all cases, the 'name' argument is a string that identifies the monitor,= and -the 'type' argument is the data type used by dot2k on the representation of +the 'type' argument is the data type used by rvgen on the representation of the model in C. =20 For example, the wip model with two states and three events can be @@ -134,7 +134,7 @@ Final remarks ------------- =20 With the monitor synthesis in place using the rv/da_monitor.h and -dot2k, the developer's work should be limited to the instrumentation +rvgen, the developer's work should be limited to the instrumentation of the system, increasing the confidence in the overall approach. =20 [1] For details about deterministic automata format and the translation @@ -142,6 +142,6 @@ from one representation to another, see:: =20 Documentation/trace/rv/deterministic_automata.rst =20 -[2] dot2k appends the monitor's name suffix to the events enums to +[2] rvgen appends the monitor's name suffix to the events enums to avoid conflicting variables when exporting the global vmlinux.h use by BPF programs. --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 CA3362FCFF7; Fri, 4 Jul 2025 13:20:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635238; cv=none; b=cQoNI0YWT2rc7Cn4CPD0hpIUhexweObS88ufZXLm/4O3px+sQRxb3PnLkjdjDLkpRTT+U09RzvSXLeeMeRvghwc7cVVarCA3wYybA42pAw2dojCpKbIeL7xQXrP5hURWE1Gaf6JpO6SNeIBEBaQxHiRDGPyUmlBrULsANV9B/nI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635238; c=relaxed/simple; bh=UszEQq6lsPFRfBHM7nHRRkL7K2X1EKuCM0p+KnG5igU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FeM6Jcp4P2mLsmUpB9XWuzv8Z5N3XFvsFZjUlKhG6agTZZ0p+VbHMrLK1iWFO+L5tEX54d/BN1lpCMSd6Tjh/eHVVBW+2MmzXBI1ISDby9ZYpfbtURyD3e9NxDBz0K5T4Wl/humID2DDicNPwXMkt8XFlNoWcDUAmj2bgOdZ3tc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=Fz1te9J8; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=S+PY5iH2; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="Fz1te9J8"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="S+PY5iH2" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635235; 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=NaFew1jGaEi6CxbD4hayUOm9FNrReyDgE4abUKZ5NBI=; b=Fz1te9J8XjoN6ox0ZRotQwHcUsKS4ZBLFHY+JWVw4iyvJiwYgrYlK4OdYXWJJvkrP+2Igm Kea9RoQ3sm0kwBblHGiWOSvIDU2yzTGcu2QIdbZP4AqsYro2ICVH6KfSMVf3bRqBbLZuFs iUnbn/QuuAeZ5IRDxl5XamGd7fS60J5Y5ejCp8GN5zyuSznEeHk1bHSHvx80wIVbwAPhha Kplfcrqq7r3jc1+t6PbFi2GWBvb9Hc0GzWBMydnq5tv6b2Pg6JUEcDxxgYNrPzBPuUiGFB FJ+WROSWk0lmbvBKjEVtqjofaXnDGeHeMU3ud+mM/z07AODmrnolwlxqsrGPCA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635235; 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=NaFew1jGaEi6CxbD4hayUOm9FNrReyDgE4abUKZ5NBI=; b=S+PY5iH2744MgzwtSWMj7GHgUa3T2BszotCzZh1VVwoQMmjt42pJjUfqk0vrrIl7bfF698 DZSuDmSafP8eEgAA== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 11/21] verification/rvgen: Restructure the templates files Date: Fri, 4 Jul 2025 15:20:03 +0200 Message-Id: <462d90273f96804d3ba850474877d5f727031258.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" To simply the scripts and to allow easy integration of new monitor types, restructure the template files as followed: 1. Move the template files to be in the same directory as the rvgen package. Furthermore, the installation will now only install the templates to the package directory, not /usr/share/. This simplify templates reading, as the scripts do not need to find the templates at multiple places. 2. Move dot2k_templates/* to: - templates/dot2k/ - templates/container/ This allows sharing templates reading code between DA monitor generation and container generation (and any future generation type). For template files which can be shared between different generation types, support putting them in templates/ This restructure aligns with the recommendation from: https://python-packaging.readthedocs.io/en/latest/non-code-files.html Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- tools/verification/rvgen/Makefile | 5 +- tools/verification/rvgen/rvgen/dot2k.py | 47 ++++++++----------- .../templates}/Kconfig | 0 .../templates/container/Kconfig} | 0 .../templates/container/main.c} | 0 .../templates/container/main.h} | 0 .../templates/dot2k}/main.c | 0 .../templates/dot2k}/trace.h | 0 8 files changed, 20 insertions(+), 32 deletions(-) rename tools/verification/rvgen/{dot2k_templates =3D> rvgen/templates}/Kco= nfig (100%) rename tools/verification/rvgen/{dot2k_templates/Kconfig_container =3D> rv= gen/templates/container/Kconfig} (100%) rename tools/verification/rvgen/{dot2k_templates/main_container.c =3D> rvg= en/templates/container/main.c} (100%) rename tools/verification/rvgen/{dot2k_templates/main_container.h =3D> rvg= en/templates/container/main.h} (100%) rename tools/verification/rvgen/{dot2k_templates =3D> rvgen/templates/dot2= k}/main.c (100%) rename tools/verification/rvgen/{dot2k_templates =3D> rvgen/templates/dot2= k}/trace.h (100%) diff --git a/tools/verification/rvgen/Makefile b/tools/verification/rvgen/M= akefile index cea9c21c3bce..8d08825e7e54 100644 --- a/tools/verification/rvgen/Makefile +++ b/tools/verification/rvgen/Makefile @@ -3,7 +3,6 @@ INSTALL=3Dinstall prefix ?=3D /usr bindir ?=3D $(prefix)/bin mandir ?=3D $(prefix)/share/man -miscdir ?=3D $(prefix)/share/rvgen srcdir ?=3D $(prefix)/src =20 PYLIB ?=3D $(shell python3 -c 'import sysconfig; print (sysconfig.get_pa= th("purelib"))') @@ -21,6 +20,4 @@ install: $(INSTALL) dot2c -D -m 755 $(DESTDIR)$(bindir)/ $(INSTALL) rvgen/dot2k.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/dot2k.py $(INSTALL) __main__.py -D -m 755 $(DESTDIR)$(bindir)/rvgen - - mkdir -p ${miscdir}/ - cp -rp dot2k_templates $(DESTDIR)$(miscdir)/ + cp -rp rvgen/templates $(DESTDIR)$(PYLIB)/rvgen/ diff --git a/tools/verification/rvgen/rvgen/dot2k.py b/tools/verification/r= vgen/rvgen/dot2k.py index e29462413194..a9ed97d0b224 100644 --- a/tools/verification/rvgen/rvgen/dot2k.py +++ b/tools/verification/rvgen/rvgen/dot2k.py @@ -14,14 +14,16 @@ import os =20 class dot2k(Dot2c): monitor_types =3D { "global" : 1, "per_cpu" : 2, "per_task" : 3 } - monitor_templates_dir =3D "rvgen/dot2k_templates/" rv_dir =3D "kernel/trace/rv" monitor_type =3D "per_cpu" =20 def __init__(self, file_path, MonitorType, extra_params=3D{}): self.container =3D extra_params.get("subcmd") =3D=3D "container" self.parent =3D extra_params.get("parent") - self.__fill_rv_templates_dir() + if self.container: + self.abs_template_dir =3D os.path.join(os.path.dirname(__file_= _), "templates/container") + else: + self.abs_template_dir =3D os.path.join(os.path.dirname(__file_= _), "templates/dot2k") =20 if self.container: if file_path: @@ -33,9 +35,7 @@ class dot2k(Dot2c): self.name =3D extra_params.get("model_name") self.events =3D [] self.states =3D [] - self.main_c =3D self.__read_file(self.monitor_templates_dir + = "main_container.c") - self.main_h =3D self.__read_file(self.monitor_templates_dir + = "main_container.h") - self.kconfig =3D self.__read_file(self.monitor_templates_dir += "Kconfig_container") + self.main_h =3D self._read_template_file("main.h") else: super().__init__(file_path, extra_params.get("model_name")) =20 @@ -43,35 +43,16 @@ class dot2k(Dot2c): if self.monitor_type is None: raise ValueError("Unknown monitor type: %s" % MonitorType) self.monitor_type =3D MonitorType - self.main_c =3D self.__read_file(self.monitor_templates_dir + = "main.c") - self.trace_h =3D self.__read_file(self.monitor_templates_dir += "trace.h") - self.kconfig =3D self.__read_file(self.monitor_templates_dir += "Kconfig") + self.trace_h =3D self._read_template_file("trace.h") + + self.main_c =3D self._read_template_file("main.c") + self.kconfig =3D self._read_template_file("Kconfig") self.enum_suffix =3D "_%s" % self.name 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() =20 - def __fill_rv_templates_dir(self): - - if os.path.exists(self.monitor_templates_dir): - return - - if platform.system() !=3D "Linux": - raise OSError("I can only run on Linux.") - - kernel_path =3D "/lib/modules/%s/build/tools/verification/rvgen/do= t2k_templates/" % (platform.release()) - - if os.path.exists(kernel_path): - self.monitor_templates_dir =3D kernel_path - return - - if os.path.exists("/usr/share/rvgen/dot2k_templates/"): - self.monitor_templates_dir =3D "/usr/share/rvgen/dot2k_templat= es/" - return - - raise FileNotFoundError("Could not find the template directory, do= you have the kernel source installed?") - def __fill_rv_kernel_dir(self): =20 # first try if we are running in the kernel tree root @@ -109,6 +90,16 @@ class dot2k(Dot2c): fd.close() return content =20 + def _read_template_file(self, file): + try: + path =3D os.path.join(self.abs_template_dir, file) + return self.__read_file(path) + except Exception: + # Specific template file not found. Try the generic template f= ile in the template/ + # directory, which is one level up + path =3D os.path.join(self.abs_template_dir, "..", file) + return self.__read_file(path) + def fill_monitor_type(self): return self.monitor_type.upper() =20 diff --git a/tools/verification/rvgen/dot2k_templates/Kconfig b/tools/verif= ication/rvgen/rvgen/templates/Kconfig similarity index 100% rename from tools/verification/rvgen/dot2k_templates/Kconfig rename to tools/verification/rvgen/rvgen/templates/Kconfig diff --git a/tools/verification/rvgen/dot2k_templates/Kconfig_container b/t= ools/verification/rvgen/rvgen/templates/container/Kconfig similarity index 100% rename from tools/verification/rvgen/dot2k_templates/Kconfig_container rename to tools/verification/rvgen/rvgen/templates/container/Kconfig diff --git a/tools/verification/rvgen/dot2k_templates/main_container.c b/to= ols/verification/rvgen/rvgen/templates/container/main.c similarity index 100% rename from tools/verification/rvgen/dot2k_templates/main_container.c rename to tools/verification/rvgen/rvgen/templates/container/main.c diff --git a/tools/verification/rvgen/dot2k_templates/main_container.h b/to= ols/verification/rvgen/rvgen/templates/container/main.h similarity index 100% rename from tools/verification/rvgen/dot2k_templates/main_container.h rename to tools/verification/rvgen/rvgen/templates/container/main.h diff --git a/tools/verification/rvgen/dot2k_templates/main.c b/tools/verifi= cation/rvgen/rvgen/templates/dot2k/main.c similarity index 100% rename from tools/verification/rvgen/dot2k_templates/main.c rename to tools/verification/rvgen/rvgen/templates/dot2k/main.c diff --git a/tools/verification/rvgen/dot2k_templates/trace.h b/tools/verif= ication/rvgen/rvgen/templates/dot2k/trace.h similarity index 100% rename from tools/verification/rvgen/dot2k_templates/trace.h rename to tools/verification/rvgen/rvgen/templates/dot2k/trace.h --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 42BD92F94A6; Fri, 4 Jul 2025 13:20:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635240; cv=none; b=R4elz3WUfDKSYJGmvfBcoq7Z+raKMTWWn8FrXvWaeBGoS/iPk5lDz8+vof0RjJjXLGDI8ZEqnAbw3bJ3BbyTvqCnNW8pXMhvD0wVt4onmLMFl66KbMB+MiZwbM95oBwv9Jx+ncBBITeAObGk9bbYl7CeHeKHPMYJ50aP1wykmwc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635240; c=relaxed/simple; bh=BlA6PQqIv5pTwbg7B8FRT8nV5ZlN/yyEq5hrwhrDLLc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rV02dxOMZqLLp7rNDrMlNQ47S8vwnKvuGbnmfk4YvVOqfOUQnDxzzBaE0yYuqf6K6BU6o2/kPj1G0/EAsLq2UHnxtf2PkWfZn1XiYROS2zBdr4z1g55xdiTXID/hHtTkgchw+LvRS5TcixGtQsw11z1XdXqdrsVztOrXz7h9B34= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=yIFeQf+J; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=uUcFQ6rD; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="yIFeQf+J"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="uUcFQ6rD" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635235; 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=J+RNWYu1SgSahorf/z3esUDvCmO80tzytOTkrZJG51I=; b=yIFeQf+JF3ujF7ljIO7pwkWRsBxFjdz+274SBIjPqfWZkJUHjpqG0A/cURMzZwemxqBEg4 8JzkzLbUnkV52TTskrmYz8lyAiVG46o+MqL8qbpEJHxi2qMAqix63ppASLnigJIOhvtiyQ 55g9l5OhWQne6wFUwjQViaaycdoMr8llAmz3R5Bag+7kvLFWFluaX1eG92eEWPcPR4pwIr GTc2cRBTuR/an5DVS7ORh1V+MXHp0Ud28YHJk08LOQQby3JXV/xVYhd5AxR8Hsxvu+8iEe o84iMv/nDYR3AEx9ZPBaw/gLeLtPP8TFcKuRpyACMHXARA1khXuAjb7FbSrKFQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635235; 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=J+RNWYu1SgSahorf/z3esUDvCmO80tzytOTkrZJG51I=; b=uUcFQ6rD3iTAfxVpivBMyxLLaJtobx7VaX1+4saIniJ4HI/X7W/Cgr18mEH50335O3zHuw aK7zCHDozI5uvxBA== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 12/21] verification/rvgen: Restructure the classes to prepare for LTL inclusion Date: Fri, 4 Jul 2025 15:20:04 +0200 Message-Id: <692137a581ba6bee7a64d37fb7173ae137c47bbd.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Both container generation and DA monitor generation is implemented in the class dot2k. That requires some ugly "if is_container ... else ...". If linear temporal logic support is added at the current state, the "if else" chain is longer and uglier. Furthermore, container generation is irrevelant to .dot files. It is therefore illogical to be implemented in class "dot2k". Clean it up, restructure the dot2k class into the following class hierarchy: (RVGenerator) /\ / \ / \ / \ / \ (Container) (Monitor) /\ / \ / \ / \ (dot2k) [ltl2k] <- intended This allows a simple and clean integration of LTL. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- tools/verification/rvgen/Makefile | 2 + tools/verification/rvgen/__main__.py | 6 +- tools/verification/rvgen/rvgen/container.py | 22 ++ tools/verification/rvgen/rvgen/dot2k.py | 275 ++------------------ tools/verification/rvgen/rvgen/generator.py | 264 +++++++++++++++++++ 5 files changed, 308 insertions(+), 261 deletions(-) create mode 100644 tools/verification/rvgen/rvgen/container.py create mode 100644 tools/verification/rvgen/rvgen/generator.py diff --git a/tools/verification/rvgen/Makefile b/tools/verification/rvgen/M= akefile index 8d08825e7e54..cca8c9ba82e8 100644 --- a/tools/verification/rvgen/Makefile +++ b/tools/verification/rvgen/Makefile @@ -19,5 +19,7 @@ install: $(INSTALL) rvgen/dot2c.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/dot2c.py $(INSTALL) dot2c -D -m 755 $(DESTDIR)$(bindir)/ $(INSTALL) rvgen/dot2k.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/dot2k.py + $(INSTALL) rvgen/container.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/containe= r.py + $(INSTALL) rvgen/generator.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/generato= r.py $(INSTALL) __main__.py -D -m 755 $(DESTDIR)$(bindir)/rvgen cp -rp rvgen/templates $(DESTDIR)$(PYLIB)/rvgen/ diff --git a/tools/verification/rvgen/__main__.py b/tools/verification/rvge= n/__main__.py index 994d320ad2d1..63ecf0c37034 100644 --- a/tools/verification/rvgen/__main__.py +++ b/tools/verification/rvgen/__main__.py @@ -10,6 +10,8 @@ =20 if __name__ =3D=3D '__main__': from rvgen.dot2k import dot2k + from rvgen.generator import Monitor + from rvgen.container import Container import argparse import sys =20 @@ -29,7 +31,7 @@ if __name__ =3D=3D '__main__': help=3D"Monitor class, either \"da\" or \"= ltl\"") monitor_parser.add_argument('-s', "--spec", dest=3D"spec", help=3D"Mon= itor specification file") monitor_parser.add_argument('-t', "--monitor_type", dest=3D"monitor_ty= pe", - help=3Df"Available options: {', '.join(dot= 2k.monitor_types.keys())}") + help=3Df"Available options: {', '.join(Mon= itor.monitor_types.keys())}") =20 container_parser =3D subparsers.add_parser("container") container_parser.add_argument('-n', "--model_name", dest=3D"model_name= ", required=3DTrue) @@ -47,7 +49,7 @@ if __name__ =3D=3D '__main__': print("Unknown monitor class:", params.monitor_class) sys.exit(1) else: - monitor =3D dot2k(None, None, vars(params)) + monitor =3D Container(vars(params)) except Exception as e: print('Error: '+ str(e)) print("Sorry : :-(") diff --git a/tools/verification/rvgen/rvgen/container.py b/tools/verificati= on/rvgen/rvgen/container.py new file mode 100644 index 000000000000..47d8ab2ad3ec --- /dev/null +++ b/tools/verification/rvgen/rvgen/container.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira +# +# Generator for runtime verification monitor container + +from . import generator + + +class Container(generator.RVGenerator): + template_dir =3D "container" + + def __init__(self, extra_params=3D{}): + super().__init__(extra_params) + self.name =3D extra_params.get("model_name") + self.main_h =3D self._read_template_file("main.h") + + def fill_model_h(self): + main_h =3D self.main_h + main_h =3D main_h.replace("%%MODEL_NAME%%", self.name) + return main_h diff --git a/tools/verification/rvgen/rvgen/dot2k.py b/tools/verification/r= vgen/rvgen/dot2k.py index a9ed97d0b224..ed0a3c901106 100644 --- a/tools/verification/rvgen/rvgen/dot2k.py +++ b/tools/verification/rvgen/rvgen/dot2k.py @@ -9,108 +9,21 @@ # Documentation/trace/rv/da_monitor_synthesis.rst =20 from .dot2c import Dot2c -import platform -import os +from .generator import Monitor =20 -class dot2k(Dot2c): - monitor_types =3D { "global" : 1, "per_cpu" : 2, "per_task" : 3 } - rv_dir =3D "kernel/trace/rv" - monitor_type =3D "per_cpu" =20 - def __init__(self, file_path, MonitorType, extra_params=3D{}): - self.container =3D extra_params.get("subcmd") =3D=3D "container" - self.parent =3D extra_params.get("parent") - if self.container: - self.abs_template_dir =3D os.path.join(os.path.dirname(__file_= _), "templates/container") - else: - self.abs_template_dir =3D os.path.join(os.path.dirname(__file_= _), "templates/dot2k") - - if self.container: - if file_path: - raise ValueError("A container does not require a dot file") - if MonitorType: - raise ValueError("A container does not require a monitor t= ype") - if self.parent: - raise ValueError("A container cannot have a parent") - self.name =3D extra_params.get("model_name") - self.events =3D [] - self.states =3D [] - self.main_h =3D self._read_template_file("main.h") - else: - super().__init__(file_path, extra_params.get("model_name")) +class dot2k(Monitor, Dot2c): + template_dir =3D "dot2k" =20 - self.monitor_type =3D self.monitor_types.get(MonitorType) - if self.monitor_type is None: - raise ValueError("Unknown monitor type: %s" % MonitorType) - self.monitor_type =3D MonitorType - self.trace_h =3D self._read_template_file("trace.h") - - self.main_c =3D self._read_template_file("main.c") - self.kconfig =3D self._read_template_file("Kconfig") + def __init__(self, file_path, MonitorType, extra_params=3D{}): + self.monitor_type =3D MonitorType + Monitor.__init__(self, extra_params) + Dot2c.__init__(self, file_path, extra_params.get("model_name")) self.enum_suffix =3D "_%s" % self.name - 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() - - def __fill_rv_kernel_dir(self): - - # first try if we are running in the kernel tree root - if os.path.exists(self.rv_dir): - return - - # offset if we are running inside the kernel tree from verificatio= n/dot2 - kernel_path =3D os.path.join("../..", self.rv_dir) - - if os.path.exists(kernel_path): - self.rv_dir =3D kernel_path - return - - if platform.system() !=3D "Linux": - raise OSError("I can only run on Linux.") - - kernel_path =3D os.path.join("/lib/modules/%s/build" % platform.re= lease(), self.rv_dir) - - # if the current kernel is from a distro this may not be a full ke= rnel tree - # verify that one of the files we are going to modify is available - if os.path.exists(os.path.join(kernel_path, "rv_trace.h")): - self.rv_dir =3D kernel_path - return - - raise FileNotFoundError("Could not find the rv directory, do you h= ave the kernel source installed?") - - def __read_file(self, path): - try: - fd =3D open(path, 'r') - except OSError: - raise Exception("Cannot open the file: %s" % path) - - content =3D fd.read() - - fd.close() - return content - - def _read_template_file(self, file): - try: - path =3D os.path.join(self.abs_template_dir, file) - return self.__read_file(path) - except Exception: - # Specific template file not found. Try the generic template f= ile in the template/ - # directory, which is one level up - path =3D os.path.join(self.abs_template_dir, "..", file) - return self.__read_file(path) =20 def fill_monitor_type(self): return self.monitor_type.upper() =20 - def fill_parent(self): - return "&rv_%s" % self.parent if self.parent else "NULL" - - def fill_include_parent(self): - if self.parent: - return "#include \n" % (self.parent, self.pa= rent) - return "" - def fill_tracepoint_handlers_skel(self): buff =3D [] for event in self.events: @@ -144,30 +57,6 @@ class dot2k(Dot2c): buff.append("\trv_detach_trace_probe(\"%s\", /* XXX: tracepoin= t */, handle_%s);" % (self.name, event)) return '\n'.join(buff) =20 - def fill_main_c(self): - main_c =3D self.main_c - monitor_type =3D self.fill_monitor_type() - min_type =3D self.get_minimun_type() - nr_events =3D len(self.events) - tracepoint_handlers =3D self.fill_tracepoint_handlers_skel() - tracepoint_attach =3D self.fill_tracepoint_attach_probe() - tracepoint_detach =3D self.fill_tracepoint_detach_helper() - parent =3D self.fill_parent() - parent_include =3D self.fill_include_parent() - - main_c =3D main_c.replace("%%MONITOR_TYPE%%", monitor_type) - main_c =3D main_c.replace("%%MIN_TYPE%%", min_type) - main_c =3D main_c.replace("%%MODEL_NAME%%", self.name) - main_c =3D main_c.replace("%%NR_EVENTS%%", str(nr_events)) - main_c =3D main_c.replace("%%TRACEPOINT_HANDLERS_SKEL%%", tracepoi= nt_handlers) - main_c =3D main_c.replace("%%TRACEPOINT_ATTACH%%", tracepoint_atta= ch) - main_c =3D main_c.replace("%%TRACEPOINT_DETACH%%", tracepoint_deta= ch) - main_c =3D main_c.replace("%%DESCRIPTION%%", self.description) - main_c =3D main_c.replace("%%PARENT%%", parent) - main_c =3D main_c.replace("%%INCLUDE_PARENT%%", parent_include) - - return main_c - def fill_model_h_header(self): buff =3D [] buff.append("/* SPDX-License-Identifier: GPL-2.0 */") @@ -226,147 +115,15 @@ class dot2k(Dot2c): buff.append(" TP_ARGS(%s)" % tp_args_c) return '\n'.join(buff) =20 - def fill_monitor_deps(self): - buff =3D [] - buff.append(" # XXX: add dependencies if there") - if self.parent: - buff.append(" depends on RV_MON_%s" % self.parent.upper()) - buff.append(" default y") - return '\n'.join(buff) - - def fill_trace_h(self): - trace_h =3D self.trace_h - monitor_class =3D self.fill_monitor_class() - monitor_class_type =3D self.fill_monitor_class_type() - tracepoint_args_skel_event =3D self.fill_tracepoint_args_skel("eve= nt") - tracepoint_args_skel_error =3D self.fill_tracepoint_args_skel("err= or") - trace_h =3D trace_h.replace("%%MODEL_NAME%%", self.name) - trace_h =3D trace_h.replace("%%MODEL_NAME_UP%%", self.name.upper()) - trace_h =3D trace_h.replace("%%MONITOR_CLASS%%", monitor_class) - trace_h =3D trace_h.replace("%%MONITOR_CLASS_TYPE%%", monitor_clas= s_type) - trace_h =3D trace_h.replace("%%TRACEPOINT_ARGS_SKEL_EVENT%%", trac= epoint_args_skel_event) - trace_h =3D trace_h.replace("%%TRACEPOINT_ARGS_SKEL_ERROR%%", trac= epoint_args_skel_error) - return trace_h - - def fill_kconfig(self): - kconfig =3D self.kconfig - monitor_class_type =3D self.fill_monitor_class_type() - monitor_deps =3D self.fill_monitor_deps() - kconfig =3D kconfig.replace("%%MODEL_NAME%%", self.name) - kconfig =3D kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper()) - kconfig =3D kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_clas= s_type) - kconfig =3D kconfig.replace("%%DESCRIPTION%%", self.description) - kconfig =3D kconfig.replace("%%MONITOR_DEPS%%", monitor_deps) - return kconfig - - def fill_main_container_h(self): - main_h =3D self.main_h - main_h =3D main_h.replace("%%MODEL_NAME%%", self.name) - return main_h - - def __patch_file(self, file, marker, line): - file_to_patch =3D os.path.join(self.rv_dir, file) - content =3D self.__read_file(file_to_patch) - content =3D content.replace(marker, line + "\n" + marker) - self.__write_file(file_to_patch, content) - - def fill_tracepoint_tooltip(self): - monitor_class_type =3D self.fill_monitor_class_type() - if self.auto_patch: - self.__patch_file("rv_trace.h", - "// Add new monitors based on CONFIG_%s here" = % monitor_class_type, - "#include " % (self.na= me, self.name)) - return " - Patching %s/rv_trace.h, double check the result" %= self.rv_dir - - return """ - Edit %s/rv_trace.h: -Add this line where other tracepoints are included and %s is defined: -#include -""" % (self.rv_dir, monitor_class_type, self.name, self.name) - - def fill_kconfig_tooltip(self): - if self.auto_patch: - self.__patch_file("Kconfig", - "# Add new monitors here", - "source \"kernel/trace/rv/monitors/%s/Kconfig\= "" % (self.name)) - return " - Patching %s/Kconfig, double check the result" % se= lf.rv_dir - - return """ - Edit %s/Kconfig: -Add this line where other monitors are included: -source \"kernel/trace/rv/monitors/%s/Kconfig\" -""" % (self.rv_dir, self.name) - - def fill_makefile_tooltip(self): - name =3D self.name - name_up =3D name.upper() - if self.auto_patch: - self.__patch_file("Makefile", - "# Add new monitors here", - "obj-$(CONFIG_RV_MON_%s) +=3D monitors/%s/%s.o= " % (name_up, name, name)) - return " - Patching %s/Makefile, double check the result" % s= elf.rv_dir - - return """ - Edit %s/Makefile: -Add this line where other monitors are included: -obj-$(CONFIG_RV_MON_%s) +=3D monitors/%s/%s.o -""" % (self.rv_dir, name_up, name, name) - - def fill_monitor_tooltip(self): - if self.auto_patch: - return " - Monitor created in %s/monitors/%s" % (self.rv_dir,= self. name) - return " - Move %s/ to the kernel's monitor directory (%s/monitor= s)" % (self.name, self.rv_dir) - - def __create_directory(self): - path =3D self.name - if self.auto_patch: - path =3D os.path.join(self.rv_dir, "monitors", path) - try: - os.mkdir(path) - except FileExistsError: - return - except: - print("Fail creating the output dir: %s" % self.name) - - def __write_file(self, file_name, content): - try: - file =3D open(file_name, 'w') - except: - print("Fail writing to file: %s" % file_name) - - file.write(content) - - file.close() - - def __create_file(self, file_name, content): - path =3D "%s/%s" % (self.name, file_name) - if self.auto_patch: - path =3D os.path.join(self.rv_dir, "monitors", path) - self.__write_file(path, content) - - def __get_main_name(self): - path =3D "%s/%s" % (self.name, "main.c") - if not os.path.exists(path): - return "main.c" - return "__main.c" - - def print_files(self): - main_c =3D self.fill_main_c() - - self.__create_directory() - - path =3D "%s.c" % self.name - self.__create_file(path, main_c) + def fill_main_c(self): + main_c =3D super().fill_main_c() =20 - if self.container: - main_h =3D self.fill_main_container_h() - path =3D "%s.h" % self.name - self.__create_file(path, main_h) - else: - model_h =3D self.fill_model_h() - path =3D "%s.h" % self.name - self.__create_file(path, model_h) + min_type =3D self.get_minimun_type() + nr_events =3D len(self.events) + monitor_type =3D self.fill_monitor_type() =20 - trace_h =3D self.fill_trace_h() - path =3D "%s_trace.h" % self.name - self.__create_file(path, trace_h) + main_c =3D main_c.replace("%%MIN_TYPE%%", min_type) + main_c =3D main_c.replace("%%NR_EVENTS%%", str(nr_events)) + main_c =3D main_c.replace("%%MONITOR_TYPE%%", monitor_type) =20 - kconfig =3D self.fill_kconfig() - self.__create_file("Kconfig", kconfig) + return main_c diff --git a/tools/verification/rvgen/rvgen/generator.py b/tools/verificati= on/rvgen/rvgen/generator.py new file mode 100644 index 000000000000..19d0078a3803 --- /dev/null +++ b/tools/verification/rvgen/rvgen/generator.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira +# +# Abtract class for generating kernel runtime verification monitors from s= pecification file + +import platform +import os + + +class RVGenerator: + rv_dir =3D "kernel/trace/rv" + + def __init__(self, extra_params=3D{}): + self.name =3D extra_params.get("model_name") + self.parent =3D extra_params.get("parent") + self.abs_template_dir =3D \ + os.path.join(os.path.dirname(__file__), "templates", self.temp= late_dir) + self.main_c =3D self._read_template_file("main.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() + + def __fill_rv_kernel_dir(self): + + # first try if we are running in the kernel tree root + if os.path.exists(self.rv_dir): + return + + # offset if we are running inside the kernel tree from verificatio= n/dot2 + kernel_path =3D os.path.join("../..", self.rv_dir) + + if os.path.exists(kernel_path): + self.rv_dir =3D kernel_path + return + + if platform.system() !=3D "Linux": + raise OSError("I can only run on Linux.") + + kernel_path =3D os.path.join("/lib/modules/%s/build" % platform.re= lease(), self.rv_dir) + + # if the current kernel is from a distro this may not be a full ke= rnel tree + # verify that one of the files we are going to modify is available + if os.path.exists(os.path.join(kernel_path, "rv_trace.h")): + self.rv_dir =3D kernel_path + return + + raise FileNotFoundError("Could not find the rv directory, do you h= ave the kernel source installed?") + + def _read_file(self, path): + try: + fd =3D open(path, 'r') + except OSError: + raise Exception("Cannot open the file: %s" % path) + + content =3D fd.read() + + fd.close() + return content + + def _read_template_file(self, file): + try: + path =3D os.path.join(self.abs_template_dir, file) + return self._read_file(path) + except Exception: + # Specific template file not found. Try the generic template f= ile in the template/ + # directory, which is one level up + path =3D os.path.join(self.abs_template_dir, "..", file) + return self._read_file(path) + + def fill_parent(self): + return "&rv_%s" % self.parent if self.parent else "NULL" + + def fill_include_parent(self): + if self.parent: + return "#include \n" % (self.parent, self.pa= rent) + return "" + + def fill_tracepoint_handlers_skel(self): + return "NotImplemented" + + def fill_tracepoint_attach_probe(self): + return "NotImplemented" + + def fill_tracepoint_detach_helper(self): + return "NotImplemented" + + def fill_main_c(self): + main_c =3D self.main_c + tracepoint_handlers =3D self.fill_tracepoint_handlers_skel() + tracepoint_attach =3D self.fill_tracepoint_attach_probe() + tracepoint_detach =3D self.fill_tracepoint_detach_helper() + parent =3D self.fill_parent() + parent_include =3D self.fill_include_parent() + + main_c =3D main_c.replace("%%MODEL_NAME%%", self.name) + main_c =3D main_c.replace("%%TRACEPOINT_HANDLERS_SKEL%%", tracepoi= nt_handlers) + main_c =3D main_c.replace("%%TRACEPOINT_ATTACH%%", tracepoint_atta= ch) + main_c =3D main_c.replace("%%TRACEPOINT_DETACH%%", tracepoint_deta= ch) + main_c =3D main_c.replace("%%DESCRIPTION%%", self.description) + main_c =3D main_c.replace("%%PARENT%%", parent) + main_c =3D main_c.replace("%%INCLUDE_PARENT%%", parent_include) + + return main_c + + def fill_model_h(self): + return "NotImplemented" + + def fill_monitor_class_type(self): + return "NotImplemented" + + def fill_monitor_class(self): + return "NotImplemented" + + def fill_tracepoint_args_skel(self, tp_type): + return "NotImplemented" + + def fill_monitor_deps(self): + buff =3D [] + buff.append(" # XXX: add dependencies if there") + if self.parent: + buff.append(" depends on RV_MON_%s" % self.parent.upper()) + buff.append(" default y") + return '\n'.join(buff) + + def fill_kconfig(self): + kconfig =3D self.kconfig + monitor_class_type =3D self.fill_monitor_class_type() + monitor_deps =3D self.fill_monitor_deps() + kconfig =3D kconfig.replace("%%MODEL_NAME%%", self.name) + kconfig =3D kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper()) + kconfig =3D kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_clas= s_type) + kconfig =3D kconfig.replace("%%DESCRIPTION%%", self.description) + kconfig =3D kconfig.replace("%%MONITOR_DEPS%%", monitor_deps) + return kconfig + + def __patch_file(self, file, marker, line): + file_to_patch =3D os.path.join(self.rv_dir, file) + content =3D self._read_file(file_to_patch) + content =3D content.replace(marker, line + "\n" + marker) + self.__write_file(file_to_patch, content) + + def fill_tracepoint_tooltip(self): + monitor_class_type =3D self.fill_monitor_class_type() + if self.auto_patch: + self.__patch_file("rv_trace.h", + "// Add new monitors based on CONFIG_%s here" = % monitor_class_type, + "#include " % (self.na= me, self.name)) + return " - Patching %s/rv_trace.h, double check the result" %= self.rv_dir + + return """ - Edit %s/rv_trace.h: +Add this line where other tracepoints are included and %s is defined: +#include +""" % (self.rv_dir, monitor_class_type, self.name, self.name) + + def fill_kconfig_tooltip(self): + if self.auto_patch: + self.__patch_file("Kconfig", + "# Add new monitors here", + "source \"kernel/trace/rv/monitors/%s/Kconfig\= "" % (self.name)) + return " - Patching %s/Kconfig, double check the result" % se= lf.rv_dir + + return """ - Edit %s/Kconfig: +Add this line where other monitors are included: +source \"kernel/trace/rv/monitors/%s/Kconfig\" +""" % (self.rv_dir, self.name) + + def fill_makefile_tooltip(self): + name =3D self.name + name_up =3D name.upper() + if self.auto_patch: + self.__patch_file("Makefile", + "# Add new monitors here", + "obj-$(CONFIG_RV_MON_%s) +=3D monitors/%s/%s.o= " % (name_up, name, name)) + return " - Patching %s/Makefile, double check the result" % s= elf.rv_dir + + return """ - Edit %s/Makefile: +Add this line where other monitors are included: +obj-$(CONFIG_RV_MON_%s) +=3D monitors/%s/%s.o +""" % (self.rv_dir, name_up, name, name) + + def fill_monitor_tooltip(self): + if self.auto_patch: + return " - Monitor created in %s/monitors/%s" % (self.rv_dir,= self. name) + return " - Move %s/ to the kernel's monitor directory (%s/monitor= s)" % (self.name, self.rv_dir) + + def __create_directory(self): + path =3D self.name + if self.auto_patch: + path =3D os.path.join(self.rv_dir, "monitors", path) + try: + os.mkdir(path) + except FileExistsError: + return + except: + print("Fail creating the output dir: %s" % self.name) + + def __write_file(self, file_name, content): + try: + file =3D open(file_name, 'w') + except: + print("Fail writing to file: %s" % file_name) + + file.write(content) + + file.close() + + def _create_file(self, file_name, content): + path =3D "%s/%s" % (self.name, file_name) + if self.auto_patch: + path =3D os.path.join(self.rv_dir, "monitors", path) + self.__write_file(path, content) + + def __get_main_name(self): + path =3D "%s/%s" % (self.name, "main.c") + if not os.path.exists(path): + return "main.c" + return "__main.c" + + def print_files(self): + main_c =3D self.fill_main_c() + + self.__create_directory() + + path =3D "%s.c" % self.name + self._create_file(path, main_c) + + model_h =3D self.fill_model_h() + path =3D "%s.h" % self.name + self._create_file(path, model_h) + + kconfig =3D self.fill_kconfig() + self._create_file("Kconfig", kconfig) + + +class Monitor(RVGenerator): + monitor_types =3D { "global" : 1, "per_cpu" : 2, "per_task" : 3 } + + def __init__(self, extra_params=3D{}): + super().__init__(extra_params) + self.trace_h =3D self._read_template_file("trace.h") + + def fill_trace_h(self): + trace_h =3D self.trace_h + monitor_class =3D self.fill_monitor_class() + monitor_class_type =3D self.fill_monitor_class_type() + tracepoint_args_skel_event =3D self.fill_tracepoint_args_skel("eve= nt") + tracepoint_args_skel_error =3D self.fill_tracepoint_args_skel("err= or") + trace_h =3D trace_h.replace("%%MODEL_NAME%%", self.name) + trace_h =3D trace_h.replace("%%MODEL_NAME_UP%%", self.name.upper()) + trace_h =3D trace_h.replace("%%MONITOR_CLASS%%", monitor_class) + trace_h =3D trace_h.replace("%%MONITOR_CLASS_TYPE%%", monitor_clas= s_type) + trace_h =3D trace_h.replace("%%TRACEPOINT_ARGS_SKEL_EVENT%%", trac= epoint_args_skel_event) + trace_h =3D trace_h.replace("%%TRACEPOINT_ARGS_SKEL_ERROR%%", trac= epoint_args_skel_error) + return trace_h + + def print_files(self): + super().print_files() + trace_h =3D self.fill_trace_h() + path =3D "%s_trace.h" % self.name + self._create_file(path, trace_h) --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 84CAD2FF497; Fri, 4 Jul 2025 13:20:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635240; cv=none; b=C0awIcdpYxx1p57KxJ341DVENMDKzaOf2ag65et5LvdP6y3RwuJDlgBD3o8CbPof69bHgcpVPTJda8l4BbWOMSED7XXu27CoiDRicWATxJGhHvn/00V1sNZFhNrwcv6GVG5NeWAS8QmMAZ9XaqQx0TmBFuIm4P18jZD2JIFjhKE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635240; c=relaxed/simple; bh=ej4y0chUHV1X9BRd0j3lK7NyOoVBhIdQuzQiHYUH+3A=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=MmYbeGp8/x45XWeCm9y2y+utRvbsTTTt208WszhwOBCbEMPizApQ1YYyd0bosMzaW98+7KJ0M//6TtJfwBqhypSEdwpOYihcFVuoNyd184Qc3I8FhyrFw2jSQunqgDqtume2jKd6VI3CrC6e4c65wmKVhgVhE43ZYfg+k++Kb9Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=fG1fjO6C; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=JGCFPOoP; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="fG1fjO6C"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="JGCFPOoP" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635236; 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=AXMNC3VDuZEOrDVFsrDc68QHYikn2X7hWmfHQcqaREo=; b=fG1fjO6C9X9jv7e8Jci03rPUl7C4znaHKn/wzFEi5Mdo0vR3KBO8kC25B0MuOdyVTSUV+v gIqeqHDIb9xA4uCDaX9ZznBVr1oLqcKK6LD/TROyfPedfiFDpr5XSvEMXG78JaF1Cx+cRK F2o2cPQeL77SeA2nhuPiayEkWdIqHghmMH9UqGXz4rtZcvscHZ0S2vALizOHM99YBQyeff HQRg5dKuniXxnet+cH/t+58nDiJ0lGucjFMl+//Yu0Rr/oqiVHSOmLRfF+GAw5C1pwnETw Aot97DGv/Io2YA8kkbVqYcgQbsL2/Dk2VucuVZmHLC44R086WBt3dpvgVvR89w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635236; 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=AXMNC3VDuZEOrDVFsrDc68QHYikn2X7hWmfHQcqaREo=; b=JGCFPOoPTTOmS8eIC2tGih1DzJsJJWSMEr+N5fHahyb+3Sx34XnNs9/+WkxUyKVGbuakG0 ytmnzQjgNtgO6bCg== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 13/21] rv: Add support for LTL monitors Date: Fri, 4 Jul 2025 15:20:05 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" While attempting to implement DA monitors for some complex specifications, deterministic automaton is found to be inappropriate as the specification language. The automaton is complicated, hard to understand, and error-prone. For these cases, linear temporal logic is more suitable as the specification language. Add support for linear temporal logic runtime verification monitor. Signed-off-by: Nam Cao --- v11: - Keep comments within 80 colums - Add '&' to make memset() looks "natural" - Split this part out from the bigger patch --- include/linux/rv.h | 63 ++++++++++++- include/rv/ltl_monitor.h | 184 +++++++++++++++++++++++++++++++++++++ kernel/fork.c | 5 +- kernel/trace/rv/Kconfig | 7 ++ kernel/trace/rv/rv_trace.h | 47 ++++++++++ 5 files changed, 298 insertions(+), 8 deletions(-) create mode 100644 include/rv/ltl_monitor.h diff --git a/include/linux/rv.h b/include/linux/rv.h index 9428e62eb8e9..1d5579f9b75a 100644 --- a/include/linux/rv.h +++ b/include/linux/rv.h @@ -10,6 +10,10 @@ #define MAX_DA_NAME_LEN 32 =20 #ifdef CONFIG_RV +#include +#include +#include + /* * Deterministic automaton per-object variables. */ @@ -18,6 +22,59 @@ struct da_monitor { unsigned int curr_state; }; =20 +#ifdef CONFIG_RV_LTL_MONITOR + +/* + * In the future, if the number of atomic propositions or the size of Buchi + * automaton is larger, we can switch to dynamic allocation. For now, the = code + * is simpler this way. + */ +#define RV_MAX_LTL_ATOM 32 +#define RV_MAX_BA_STATES 32 + +/** + * struct ltl_monitor - A linear temporal logic runtime verification monit= or + * @states: States in the Buchi automaton. As Buchi automaton is a + * non-deterministic state machine, the monitor can be in multiple + * states simultaneously. This is a bitmask of all possible states. + * If this is zero, that means either: + * - The monitor has not started yet (e.g. because not all + * atomic propositions are known). + * - There is no possible state to be in. In other words, a + * violation of the LTL property is detected. + * @atoms: The values of atomic propositions. + * @unknown_atoms: Atomic propositions which are still unknown. + */ +struct ltl_monitor { + DECLARE_BITMAP(states, RV_MAX_BA_STATES); + DECLARE_BITMAP(atoms, RV_MAX_LTL_ATOM); + DECLARE_BITMAP(unknown_atoms, RV_MAX_LTL_ATOM); +}; + +static inline bool rv_ltl_valid_state(struct ltl_monitor *mon) +{ + for (int i =3D 0; i < ARRAY_SIZE(mon->states); ++i) { + if (mon->states[i]) + return true; + } + return false; +} + +static inline bool rv_ltl_all_atoms_known(struct ltl_monitor *mon) +{ + for (int i =3D 0; i < ARRAY_SIZE(mon->unknown_atoms); ++i) { + if (mon->unknown_atoms[i]) + return false; + } + return true; +} + +#else + +struct ltl_monitor {}; + +#endif /* CONFIG_RV_LTL_MONITOR */ + /* * Per-task RV monitors count. Nowadays fixed in RV_PER_TASK_MONITORS. * If we find justification for more monitors, we can think about @@ -27,11 +84,9 @@ struct da_monitor { #define RV_PER_TASK_MONITORS 1 #define RV_PER_TASK_MONITOR_INIT (RV_PER_TASK_MONITORS) =20 -/* - * Futher monitor types are expected, so make this a union. - */ union rv_task_monitor { - struct da_monitor da_mon; + struct da_monitor da_mon; + struct ltl_monitor ltl_mon; }; =20 #ifdef CONFIG_RV_REACTORS diff --git a/include/rv/ltl_monitor.h b/include/rv/ltl_monitor.h new file mode 100644 index 000000000000..9a583125b566 --- /dev/null +++ b/include/rv/ltl_monitor.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/** + * This file must be combined with the $(MODEL_NAME).h file generated by + * tools/verification/rvgen. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef MONITOR_NAME +#error "Please include $(MODEL_NAME).h generated by rvgen" +#endif + +#ifdef CONFIG_RV_REACTORS +#define RV_MONITOR_NAME CONCATENATE(rv_, MONITOR_NAME) +static struct rv_monitor RV_MONITOR_NAME; + +static void rv_cond_react(struct task_struct *task) +{ + if (!rv_reacting_on() || !RV_MONITOR_NAME.react) + return; + RV_MONITOR_NAME.react("rv: "__stringify(MONITOR_NAME)": %s[%d]: violation= detected\n", + task->comm, task->pid); +} +#else +static void rv_cond_react(struct task_struct *task) +{ +} +#endif + +static int ltl_monitor_slot =3D RV_PER_TASK_MONITOR_INIT; + +static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *= mon); +static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *m= on, bool task_creation); + +static struct ltl_monitor *ltl_get_monitor(struct task_struct *task) +{ + return &task->rv[ltl_monitor_slot].ltl_mon; +} + +static void ltl_task_init(struct task_struct *task, bool task_creation) +{ + struct ltl_monitor *mon =3D ltl_get_monitor(task); + + memset(&mon->states, 0, sizeof(mon->states)); + + for (int i =3D 0; i < LTL_NUM_ATOM; ++i) + __set_bit(i, mon->unknown_atoms); + + ltl_atoms_init(task, mon, task_creation); + ltl_atoms_fetch(task, mon); +} + +static void handle_task_newtask(void *data, struct task_struct *task, unsi= gned long flags) +{ + ltl_task_init(task, true); +} + +static int ltl_monitor_init(void) +{ + struct task_struct *g, *p; + int ret, cpu; + + ret =3D rv_get_task_monitor_slot(); + if (ret < 0) + return ret; + + ltl_monitor_slot =3D ret; + + rv_attach_trace_probe(name, task_newtask, handle_task_newtask); + + read_lock(&tasklist_lock); + + for_each_process_thread(g, p) + ltl_task_init(p, false); + + for_each_present_cpu(cpu) + ltl_task_init(idle_task(cpu), false); + + read_unlock(&tasklist_lock); + + return 0; +} + +static void ltl_monitor_destroy(void) +{ + rv_detach_trace_probe(name, task_newtask, handle_task_newtask); + + rv_put_task_monitor_slot(ltl_monitor_slot); + ltl_monitor_slot =3D RV_PER_TASK_MONITOR_INIT; +} + +static void ltl_illegal_state(struct task_struct *task, struct ltl_monitor= *mon) +{ + CONCATENATE(trace_error_, MONITOR_NAME)(task); + rv_cond_react(task); +} + +static void ltl_attempt_start(struct task_struct *task, struct ltl_monitor= *mon) +{ + if (rv_ltl_all_atoms_known(mon)) + ltl_start(task, mon); +} + +static inline void ltl_atom_set(struct ltl_monitor *mon, enum ltl_atom ato= m, bool value) +{ + __clear_bit(atom, mon->unknown_atoms); + if (value) + __set_bit(atom, mon->atoms); + else + __clear_bit(atom, mon->atoms); +} + +static void +ltl_trace_event(struct task_struct *task, struct ltl_monitor *mon, unsigne= d long *next_state) +{ + const char *format_str =3D "%s"; + DECLARE_SEQ_BUF(atoms, 64); + char states[32], next[32]; + int i; + + if (!CONCATENATE(CONCATENATE(trace_event_, MONITOR_NAME), _enabled)()) + return; + + snprintf(states, sizeof(states), "%*pbl", RV_MAX_BA_STATES, mon->states); + snprintf(next, sizeof(next), "%*pbl", RV_MAX_BA_STATES, next_state); + + for (i =3D 0; i < LTL_NUM_ATOM; ++i) { + if (test_bit(i, mon->atoms)) { + seq_buf_printf(&atoms, format_str, ltl_atom_str(i)); + format_str =3D ",%s"; + } + } + + CONCATENATE(trace_event_, MONITOR_NAME)(task, states, atoms.buffer, next); +} + +static void ltl_validate(struct task_struct *task, struct ltl_monitor *mon) +{ + DECLARE_BITMAP(next_states, RV_MAX_BA_STATES) =3D {0}; + + if (!rv_ltl_valid_state(mon)) + return; + + for (unsigned int i =3D 0; i < RV_NUM_BA_STATES; ++i) { + if (test_bit(i, mon->states)) + ltl_possible_next_states(mon, i, next_states); + } + + ltl_trace_event(task, mon, next_states); + + memcpy(mon->states, next_states, sizeof(next_states)); + + if (!rv_ltl_valid_state(mon)) + ltl_illegal_state(task, mon); +} + +static void ltl_atom_update(struct task_struct *task, enum ltl_atom atom, = bool value) +{ + struct ltl_monitor *mon =3D ltl_get_monitor(task); + + ltl_atom_set(mon, atom, value); + ltl_atoms_fetch(task, mon); + + if (!rv_ltl_valid_state(mon)) + ltl_attempt_start(task, mon); + + ltl_validate(task, mon); +} + +static void __maybe_unused ltl_atom_pulse(struct task_struct *task, enum l= tl_atom atom, bool value) +{ + struct ltl_monitor *mon =3D ltl_get_monitor(task); + + ltl_atom_update(task, atom, value); + + ltl_atom_set(mon, atom, !value); + ltl_validate(task, mon); +} diff --git a/kernel/fork.c b/kernel/fork.c index 1ee8eb11f38b..1f06559d17bf 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1886,10 +1886,7 @@ static void copy_oom_score_adj(u64 clone_flags, stru= ct task_struct *tsk) #ifdef CONFIG_RV static void rv_task_fork(struct task_struct *p) { - int i; - - for (i =3D 0; i < RV_PER_TASK_MONITORS; i++) - p->rv[i].da_mon.monitoring =3D false; + memset(&p->rv, 0, sizeof(p->rv)); } #else #define rv_task_fork(p) do {} while (0) diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index 6cdffc04b73c..6e157f964991 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -11,6 +11,13 @@ config DA_MON_EVENTS_ID select RV_MON_EVENTS bool =20 +config LTL_MON_EVENTS_ID + select RV_MON_EVENTS + bool + +config RV_LTL_MONITOR + bool + menuconfig RV bool "Runtime Verification" depends on TRACING diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h index 99c3801616d4..fd3111ad1d51 100644 --- a/kernel/trace/rv/rv_trace.h +++ b/kernel/trace/rv/rv_trace.h @@ -127,6 +127,53 @@ DECLARE_EVENT_CLASS(error_da_monitor_id, // Add new monitors based on CONFIG_DA_MON_EVENTS_ID here =20 #endif /* CONFIG_DA_MON_EVENTS_ID */ +#ifdef CONFIG_LTL_MON_EVENTS_ID +DECLARE_EVENT_CLASS(event_ltl_monitor_id, + + TP_PROTO(struct task_struct *task, char *states, char *atoms, char *next), + + TP_ARGS(task, states, atoms, next), + + TP_STRUCT__entry( + __string(comm, task->comm) + __field(pid_t, pid) + __string(states, states) + __string(atoms, atoms) + __string(next, next) + ), + + TP_fast_assign( + __assign_str(comm); + __entry->pid =3D task->pid; + __assign_str(states); + __assign_str(atoms); + __assign_str(next); + ), + + TP_printk("%s[%d]: (%s) x (%s) -> (%s)", __get_str(comm), __entry->pid, + __get_str(states), __get_str(atoms), __get_str(next)) +); + +DECLARE_EVENT_CLASS(error_ltl_monitor_id, + + TP_PROTO(struct task_struct *task), + + TP_ARGS(task), + + TP_STRUCT__entry( + __string(comm, task->comm) + __field(pid_t, pid) + ), + + TP_fast_assign( + __assign_str(comm); + __entry->pid =3D task->pid; + ), + + TP_printk("%s[%d]: violation detected", __get_str(comm), __entry->pid) +); +// Add new monitors based on CONFIG_LTL_MON_EVENTS_ID here +#endif /* CONFIG_LTL_MON_EVENTS_ID */ #endif /* _TRACE_RV_H */ =20 /* This part must be outside protection */ --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 4D902302CD3; Fri, 4 Jul 2025 13:20:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635244; cv=none; b=Alqz3eOBgSpZLCVxPSngN9G3Dn6tdjYIEh4bd+8o9x/6iS+6r5xWAKzQQNa3uNZahRcsi9rRdgcNMKDsLVzFlKvcA5QdArGqMxJfmyArF10CtMP5Xr3LfL1neHyGUVOS7G7cM61DIxgrBFEYIYASwxGQl/oLydtStSWWqtr81qM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635244; c=relaxed/simple; bh=4E0Oah8Vf9+0nw81guANuSlGCnnDikjBatsfcFqNIBw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DKmhQAxQY2lQTRuKFHZc4eio4hBPAauLcOKjw+E5XX8GpPJfi6AA267n7bAVL6aoUdtV1OaT/7pGpZrz9y8S9G9fnnGXVsAiMyEqC4tqreHWlTLEs9I4oduCWf4Uvr4Ec0yves7rsYVKB5IEfo8Q2vi8EgFePlgZb2dwE0fZayo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=27F5mGsN; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=dw8OvcQf; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="27F5mGsN"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="dw8OvcQf" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635237; 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=+KAvGyQ0xP8IO/zEYr99K1J42aOtJiiaTgBhx/7FTHk=; b=27F5mGsNcOtAq81zZ91b5dpynFe9wdQaftvmab/81vlWom9r+sZSKm3eJCyv2QTpkOgePF cHdcOSXYagcrs0iSchUpGxoLMSxRFgsV6roJuQhOyzQJ3iekHUUt/mnxJBpcs/EoXQh0Cy TZgHEwNcXWtiLF4xqSq/Izo51LCTL2HZ3B21cXd14XVB6YXrdxfRwZrqAcDEFrLFUtUpod zMexLEC1a74JNCngB0+REObgSMwiYOcTRobrs3vPSFxX0LXkIeiLDBfHyzM5ANKI+KgcIO U74K/gdXPt+sOImU85YzTJTayC/ZXzfshyuf5OOfefgytM8WxUDL7kncBdES9A== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635237; 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=+KAvGyQ0xP8IO/zEYr99K1J42aOtJiiaTgBhx/7FTHk=; b=dw8OvcQf6v8TpmfaOjoRANqS2GO55LYz5u5odsXOKwN76bQqMRXSz+54oJmFilWb2hy5rV mAwx70uZSMyF9ADA== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 14/21] verification/rvgen: Add support for linear temporal logic Date: Fri, 4 Jul 2025 15:20:06 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Add support for generating RV monitors from linear temporal logic, similar to the generation of deterministic automaton monitors. Signed-off-by: Nam Cao --- v11: - Keep comments within 80 columns - Also generate a note that the monitor file is generated - Split this out from the bigger patch --- tools/verification/rvgen/.gitignore | 3 + tools/verification/rvgen/Makefile | 2 + tools/verification/rvgen/__main__.py | 3 +- tools/verification/rvgen/rvgen/ltl2ba.py | 540 ++++++++++++++++++ tools/verification/rvgen/rvgen/ltl2k.py | 252 ++++++++ .../rvgen/rvgen/templates/ltl2k/main.c | 102 ++++ .../rvgen/rvgen/templates/ltl2k/trace.h | 14 + 7 files changed, 915 insertions(+), 1 deletion(-) create mode 100644 tools/verification/rvgen/.gitignore create mode 100644 tools/verification/rvgen/rvgen/ltl2ba.py create mode 100644 tools/verification/rvgen/rvgen/ltl2k.py create mode 100644 tools/verification/rvgen/rvgen/templates/ltl2k/main.c create mode 100644 tools/verification/rvgen/rvgen/templates/ltl2k/trace.h diff --git a/tools/verification/rvgen/.gitignore b/tools/verification/rvgen= /.gitignore new file mode 100644 index 000000000000..1e288a076560 --- /dev/null +++ b/tools/verification/rvgen/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +parser.out +parsetab.py diff --git a/tools/verification/rvgen/Makefile b/tools/verification/rvgen/M= akefile index cca8c9ba82e8..cfc4056c1e87 100644 --- a/tools/verification/rvgen/Makefile +++ b/tools/verification/rvgen/Makefile @@ -21,5 +21,7 @@ install: $(INSTALL) rvgen/dot2k.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/dot2k.py $(INSTALL) rvgen/container.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/containe= r.py $(INSTALL) rvgen/generator.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/generato= r.py + $(INSTALL) rvgen/ltl2ba.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/ltl2ba.py + $(INSTALL) rvgen/ltl2k.py -D -m 644 $(DESTDIR)$(PYLIB)/rvgen/ltl2k.py $(INSTALL) __main__.py -D -m 755 $(DESTDIR)$(bindir)/rvgen cp -rp rvgen/templates $(DESTDIR)$(PYLIB)/rvgen/ diff --git a/tools/verification/rvgen/__main__.py b/tools/verification/rvge= n/__main__.py index 63ecf0c37034..fa6fc1f4de2f 100644 --- a/tools/verification/rvgen/__main__.py +++ b/tools/verification/rvgen/__main__.py @@ -12,6 +12,7 @@ if __name__ =3D=3D '__main__': from rvgen.dot2k import dot2k from rvgen.generator import Monitor from rvgen.container import Container + from rvgen.ltl2k import ltl2k import argparse import sys =20 @@ -44,7 +45,7 @@ if __name__ =3D=3D '__main__': if params.monitor_class =3D=3D "da": monitor =3D dot2k(params.spec, params.monitor_type, vars(p= arams)) elif params.monitor_class =3D=3D "ltl": - raise NotImplementedError + monitor =3D ltl2k(params.spec, params.monitor_type, vars(p= arams)) else: print("Unknown monitor class:", params.monitor_class) sys.exit(1) diff --git a/tools/verification/rvgen/rvgen/ltl2ba.py b/tools/verification/= rvgen/rvgen/ltl2ba.py new file mode 100644 index 000000000000..d11840af7f5f --- /dev/null +++ b/tools/verification/rvgen/rvgen/ltl2ba.py @@ -0,0 +1,540 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only +# +# Implementation based on +# Gerth, R., Peled, D., Vardi, M.Y., Wolper, P. (1996). +# Simple On-the-fly Automatic Verification of Linear Temporal Logic. +# https://doi.org/10.1007/978-0-387-34892-6_1 +# With extra optimizations + +from ply.lex import lex +from ply.yacc import yacc + +# Grammar: +# ltl ::=3D opd | ( ltl ) | ltl binop ltl | unop ltl +# +# Operands (opd): +# true, false, user-defined names +# +# Unary Operators (unop): +# always +# eventually +# not +# +# Binary Operators (binop): +# until +# and +# or +# imply +# equivalent + +tokens =3D ( + 'AND', + 'OR', + 'IMPLY', + 'UNTIL', + 'ALWAYS', + 'EVENTUALLY', + 'VARIABLE', + 'LITERAL', + 'NOT', + 'LPAREN', + 'RPAREN', + 'ASSIGN', +) + +t_AND =3D r'and' +t_OR =3D r'or' +t_IMPLY =3D r'imply' +t_UNTIL =3D r'until' +t_ALWAYS =3D r'always' +t_EVENTUALLY =3D r'eventually' +t_VARIABLE =3D r'[A-Z_0-9]+' +t_LITERAL =3D r'true|false' +t_NOT =3D r'not' +t_LPAREN =3D r'\(' +t_RPAREN =3D r'\)' +t_ASSIGN =3D r'=3D' +t_ignore_COMMENT =3D r'\#.*' +t_ignore =3D ' \t\n' + +def t_error(t): + raise ValueError(f"Illegal character '{t.value[0]}'") + +lexer =3D lex() + +class GraphNode: + uid =3D 0 + + def __init__(self, incoming: set['GraphNode'], new, old, _next): + self.init =3D False + self.outgoing =3D set() + self.labels =3D set() + self.incoming =3D incoming.copy() + self.new =3D new.copy() + self.old =3D old.copy() + self.next =3D _next.copy() + self.id =3D GraphNode.uid + GraphNode.uid +=3D 1 + + def expand(self, node_set): + if not self.new: + for nd in node_set: + if nd.old =3D=3D self.old and nd.next =3D=3D self.next: + nd.incoming |=3D self.incoming + return node_set + + new_current_node =3D GraphNode({self}, self.next, set(), set()) + return new_current_node.expand({self} | node_set) + n =3D self.new.pop() + return n.expand(self, node_set) + + def __lt__(self, other): + return self.id < other.id + +class ASTNode: + uid =3D 1 + + def __init__(self, op): + self.op =3D op + self.id =3D ASTNode.uid + ASTNode.uid +=3D 1 + + def __hash__(self): + return hash(self.op) + + def __eq__(self, other): + return self is other + + def __iter__(self): + yield self + yield from self.op + + def negate(self): + self.op =3D self.op.negate() + return self + + def expand(self, node, node_set): + return self.op.expand(self, node, node_set) + + def __str__(self): + if isinstance(self.op, Literal): + return str(self.op.value) + if isinstance(self.op, Variable): + return self.op.name.lower() + return "val" + str(self.id) + + def normalize(self): + # Get rid of: + # - ALWAYS + # - EVENTUALLY + # - IMPLY + # And move all the NOT to be inside + self.op =3D self.op.normalize() + return self + +class BinaryOp: + op_str =3D "not_supported" + + def __init__(self, left: ASTNode, right: ASTNode): + self.left =3D left + self.right =3D right + + def __hash__(self): + return hash((self.left, self.right)) + + def __iter__(self): + yield from self.left + yield from self.right + + def normalize(self): + raise NotImplementedError + + def negate(self): + raise NotImplementedError + + def _is_temporal(self): + raise NotImplementedError + + def is_temporal(self): + if self.left.op.is_temporal(): + return True + if self.right.op.is_temporal(): + return True + return self._is_temporal() + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + raise NotImplementedError + +class AndOp(BinaryOp): + op_str =3D '&&' + + def normalize(self): + return self + + def negate(self): + return OrOp(self.left.negate(), self.right.negate()) + + def _is_temporal(self): + return False + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + if not n.op.is_temporal(): + node.old.add(n) + return node.expand(node_set) + + tmp =3D GraphNode(node.incoming, + node.new | ({n.op.left, n.op.right} - node.old), + node.old | {n}, + node.next) + return tmp.expand(node_set) + +class OrOp(BinaryOp): + op_str =3D '||' + + def normalize(self): + return self + + def negate(self): + return AndOp(self.left.negate(), self.right.negate()) + + def _is_temporal(self): + return False + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + if not n.op.is_temporal(): + node.old |=3D {n} + return node.expand(node_set) + + node1 =3D GraphNode(node.incoming, + node.new | ({n.op.left} - node.old), + node.old | {n}, + node.next) + node2 =3D GraphNode(node.incoming, + node.new | ({n.op.right} - node.old), + node.old | {n}, + node.next) + return node2.expand(node1.expand(node_set)) + +class UntilOp(BinaryOp): + def normalize(self): + return self + + def negate(self): + return VOp(self.left.negate(), self.right.negate()) + + def _is_temporal(self): + return True + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + node1 =3D GraphNode(node.incoming, + node.new | ({n.op.left} - node.old), + node.old | {n}, + node.next | {n}) + node2 =3D GraphNode(node.incoming, + node.new | ({n.op.right} - node.old), + node.old | {n}, + node.next) + return node2.expand(node1.expand(node_set)) + +class VOp(BinaryOp): + def normalize(self): + return self + + def negate(self): + return UntilOp(self.left.negate(), self.right.negate()) + + def _is_temporal(self): + return True + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + node1 =3D GraphNode(node.incoming, + node.new | ({n.op.right} - node.old), + node.old | {n}, + node.next | {n}) + node2 =3D GraphNode(node.incoming, + node.new | ({n.op.left, n.op.right} - node.old), + node.old | {n}, + node.next) + return node2.expand(node1.expand(node_set)) + +class ImplyOp(BinaryOp): + def normalize(self): + # P -> Q =3D=3D=3D !P | Q + return OrOp(self.left.negate(), self.right) + + def _is_temporal(self): + return False + + def negate(self): + # !(P -> Q) =3D=3D=3D !(!P | Q) =3D=3D=3D P & !Q + return AndOp(self.left, self.right.negate()) + +class UnaryOp: + def __init__(self, child: ASTNode): + self.child =3D child + + def __iter__(self): + yield from self.child + + def __hash__(self): + return hash(self.child) + + def normalize(self): + raise NotImplementedError + + def _is_temporal(self): + raise NotImplementedError + + def is_temporal(self): + if self.child.op.is_temporal(): + return True + return self._is_temporal() + + def negate(self): + raise NotImplementedError + +class EventuallyOp(UnaryOp): + def __str__(self): + return "eventually " + str(self.child) + + def normalize(self): + # <>F =3D=3D true U F + return UntilOp(ASTNode(Literal(True)), self.child) + + def _is_temporal(self): + return True + + def negate(self): + # !<>F =3D=3D [](!F) + return AlwaysOp(self.child.negate()).normalize() + +class AlwaysOp(UnaryOp): + def normalize(self): + # []F =3D=3D=3D !(true U !F) =3D=3D false V F + new =3D ASTNode(Literal(False)) + return VOp(new, self.child) + + def _is_temporal(self): + return True + + def negate(self): + # ![]F =3D=3D <>(!F) + return EventuallyOp(self.child.negate()).normalize() + +class NotOp(UnaryOp): + def __str__(self): + return "!" + str(self.child) + + def normalize(self): + return self.child.op.negate() + + def negate(self): + return self.child.op + + def _is_temporal(self): + return False + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + for f in node.old: + if n.op.child is f: + return node_set + node.old |=3D {n} + return node.expand(node_set) + +class Variable: + def __init__(self, name: str): + self.name =3D name + + def __hash__(self): + return hash(self.name) + + def __iter__(self): + yield from () + + def negate(self): + new =3D ASTNode(self) + return NotOp(new) + + def normalize(self): + return self + + def is_temporal(self): + return False + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + for f in node.old: + if isinstance(f, NotOp) and f.op.child is n: + return node_set + node.old |=3D {n} + return node.expand(node_set) + +class Literal: + def __init__(self, value: bool): + self.value =3D value + + def __iter__(self): + yield from () + + def __hash__(self): + return hash(self.value) + + def __str__(self): + if self.value: + return "true" + return "false" + + def negate(self): + self.value =3D not self.value + return self + + def normalize(self): + return self + + def is_temporal(self): + return False + + @staticmethod + def expand(n: ASTNode, node: GraphNode, node_set) -> set[GraphNode]: + if not n.op.value: + return node_set + node.old |=3D {n} + return node.expand(node_set) + +def p_spec(p): + ''' + spec : assign + | assign spec + ''' + if len(p) =3D=3D 3: + p[2].append(p[1]) + p[0] =3D p[2] + else: + p[0] =3D [p[1]] + +def p_assign(p): + ''' + assign : VARIABLE ASSIGN ltl + ''' + p[0] =3D (p[1], p[3]) + +def p_ltl(p): + ''' + ltl : opd + | binop + | unop + ''' + p[0] =3D p[1] + +def p_opd(p): + ''' + opd : VARIABLE + | LITERAL + | LPAREN ltl RPAREN + ''' + if p[1] =3D=3D "true": + p[0] =3D ASTNode(Literal(True)) + elif p[1] =3D=3D "false": + p[0] =3D ASTNode(Literal(False)) + elif p[1] =3D=3D '(': + p[0] =3D p[2] + else: + p[0] =3D ASTNode(Variable(p[1])) + +def p_unop(p): + ''' + unop : ALWAYS ltl + | EVENTUALLY ltl + | NOT ltl + ''' + if p[1] =3D=3D "always": + op =3D AlwaysOp(p[2]) + elif p[1] =3D=3D "eventually": + op =3D EventuallyOp(p[2]) + elif p[1] =3D=3D "not": + op =3D NotOp(p[2]) + else: + raise ValueError(f"Invalid unary operator {p[1]}") + + p[0] =3D ASTNode(op) + +def p_binop(p): + ''' + binop : opd UNTIL ltl + | opd AND ltl + | opd OR ltl + | opd IMPLY ltl + ''' + if p[2] =3D=3D "and": + op =3D AndOp(p[1], p[3]) + elif p[2] =3D=3D "until": + op =3D UntilOp(p[1], p[3]) + elif p[2] =3D=3D "or": + op =3D OrOp(p[1], p[3]) + elif p[2] =3D=3D "imply": + op =3D ImplyOp(p[1], p[3]) + else: + raise ValueError(f"Invalid binary operator {p[2]}") + + p[0] =3D ASTNode(op) + +parser =3D yacc() + +def parse_ltl(s: str) -> ASTNode: + spec =3D parser.parse(s) + + rule =3D None + subexpr =3D {} + + for assign in spec: + if assign[0] =3D=3D "RULE": + rule =3D assign[1] + else: + subexpr[assign[0]] =3D assign[1] + + if rule is None: + raise ValueError("Please define your specification in the \"RULE = =3D \" format") + + for node in rule: + if not isinstance(node.op, Variable): + continue + replace =3D subexpr.get(node.op.name) + if replace is not None: + node.op =3D replace.op + + return rule + +def create_graph(s: str): + atoms =3D set() + + ltl =3D parse_ltl(s) + for c in ltl: + c.normalize() + if isinstance(c.op, Variable): + atoms.add(c.op.name) + + init =3D GraphNode(set(), set(), set(), set()) + head =3D GraphNode({init}, {ltl}, set(), set()) + graph =3D sorted(head.expand(set())) + + for i, node in enumerate(graph): + # The id assignment during graph generation has gaps. Reassign them + node.id =3D i + + for incoming in node.incoming: + if incoming is init: + node.init =3D True + else: + incoming.outgoing.add(node) + for o in node.old: + if not o.op.is_temporal(): + node.labels.add(str(o)) + + return sorted(atoms), graph, ltl diff --git a/tools/verification/rvgen/rvgen/ltl2k.py b/tools/verification/r= vgen/rvgen/ltl2k.py new file mode 100644 index 000000000000..92e713861d86 --- /dev/null +++ b/tools/verification/rvgen/rvgen/ltl2k.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only + +from pathlib import Path +from . import generator +from . import ltl2ba + +COLUMN_LIMIT =3D 100 + +def line_len(line: str) -> int: + tabs =3D line.count('\t') + return tabs * 7 + len(line) + +def break_long_line(line: str, indent=3D'') -> list[str]: + result =3D [] + while line_len(line) > COLUMN_LIMIT: + i =3D line[:COLUMN_LIMIT - line_len(line)].rfind(' ') + result.append(line[:i]) + line =3D indent + line[i + 1:] + if line: + result.append(line) + return result + +def build_condition_string(node: ltl2ba.GraphNode): + if not node.labels: + return "(true)" + + result =3D "(" + + first =3D True + for label in sorted(node.labels): + if not first: + result +=3D " && " + result +=3D label + first =3D False + + result +=3D ")" + + return result + +def abbreviate_atoms(atoms: list[str]) -> list[str]: + def shorten(s: str) -> str: + skip =3D ["is", "by", "or", "and"] + return '_'.join([x[:2] for x in s.lower().split('_') if x not in s= kip]) + + abbrs =3D [] + for atom in atoms: + for i in range(len(atom), -1, -1): + if sum(a.startswith(atom[:i]) for a in atoms) > 1: + break + share =3D atom[:i] + unique =3D atom[i:] + abbrs.append((shorten(share) + shorten(unique))) + return abbrs + +class ltl2k(generator.Monitor): + template_dir =3D "ltl2k" + + def __init__(self, file_path, MonitorType, extra_params=3D{}): + if MonitorType !=3D "per_task": + raise NotImplementedError("Only per_task monitor is supported = for LTL") + super().__init__(extra_params) + with open(file_path) as f: + self.atoms, self.ba, self.ltl =3D ltl2ba.create_graph(f.read()) + self.atoms_abbr =3D abbreviate_atoms(self.atoms) + self.name =3D extra_params.get("model_name") + if not self.name: + self.name =3D Path(file_path).stem + + def _fill_states(self) -> str: + buf =3D [ + "enum ltl_buchi_state {", + ] + + for node in self.ba: + buf.append("\tS%i," % node.id) + buf.append("\tRV_NUM_BA_STATES") + buf.append("};") + buf.append("static_assert(RV_NUM_BA_STATES <=3D RV_MAX_BA_STATES);= ") + return buf + + def _fill_atoms(self): + buf =3D ["enum ltl_atom {"] + for a in sorted(self.atoms): + buf.append("\tLTL_%s," % a) + buf.append("\tLTL_NUM_ATOM") + buf.append("};") + buf.append("static_assert(LTL_NUM_ATOM <=3D RV_MAX_LTL_ATOM);") + return buf + + def _fill_atoms_to_string(self): + buf =3D [ + "static const char *ltl_atom_str(enum ltl_atom atom)", + "{", + "\tstatic const char *const names[] =3D {" + ] + + for name in self.atoms_abbr: + buf.append("\t\t\"%s\"," % name) + + buf.extend([ + "\t};", + "", + "\treturn names[atom];", + "}" + ]) + return buf + + def _fill_atom_values(self): + buf =3D [] + for node in self.ltl: + if node.op.is_temporal(): + continue + + if isinstance(node.op, ltl2ba.Variable): + buf.append("\tbool %s =3D test_bit(LTL_%s, mon->atoms);" %= (node, node.op.name)) + elif isinstance(node.op, ltl2ba.AndOp): + buf.append("\tbool %s =3D %s && %s;" % (node, node.op.left= , node.op.right)) + elif isinstance(node.op, ltl2ba.OrOp): + buf.append("\tbool %s =3D %s || %s;" % (node, node.op.left= , node.op.right)) + elif isinstance(node.op, ltl2ba.NotOp): + buf.append("\tbool %s =3D !%s;" % (node, node.op.child)) + buf.reverse() + + buf2 =3D [] + for line in buf: + buf2.extend(break_long_line(line, "\t ")) + return buf2 + + def _fill_transitions(self): + buf =3D [ + "static void", + "ltl_possible_next_states(struct ltl_monitor *mon, unsigned in= t state, unsigned long *next)", + "{" + ] + buf.extend(self._fill_atom_values()) + buf.extend([ + "", + "\tswitch (state) {" + ]) + + for node in self.ba: + buf.append("\tcase S%i:" % node.id) + + for o in sorted(node.outgoing): + line =3D "\t\tif " + indent =3D "\t\t " + + line +=3D build_condition_string(o) + lines =3D break_long_line(line, indent) + buf.extend(lines) + + buf.append("\t\t\t__set_bit(S%i, next);" % o.id) + buf.append("\t\tbreak;") + buf.extend([ + "\t}", + "}" + ]) + + return buf + + def _fill_start(self): + buf =3D [ + "static void ltl_start(struct task_struct *task, struct ltl_mo= nitor *mon)", + "{" + ] + buf.extend(self._fill_atom_values()) + buf.append("") + + for node in self.ba: + if not node.init: + continue + + line =3D "\tif " + indent =3D "\t " + + line +=3D build_condition_string(node) + lines =3D break_long_line(line, indent) + buf.extend(lines) + + buf.append("\t\t__set_bit(S%i, mon->states);" % node.id) + buf.append("}") + return buf + + def fill_tracepoint_handlers_skel(self): + buff =3D [] + buff.append("static void handle_example_event(void *data, /* XXX: = fill header */)") + buff.append("{") + buff.append("\tltl_atom_update(task, LTL_%s, true/false);" % self.= atoms[0]) + buff.append("}") + buff.append("") + return '\n'.join(buff) + + def fill_tracepoint_attach_probe(self): + return "\trv_attach_trace_probe(\"%s\", /* XXX: tracepoint */, han= dle_example_event);" \ + % self.name + + def fill_tracepoint_detach_helper(self): + return "\trv_detach_trace_probe(\"%s\", /* XXX: tracepoint */, han= dle_sample_event);" \ + % self.name + + def fill_atoms_init(self): + buff =3D [] + for a in self.atoms: + buff.append("\tltl_atom_set(mon, LTL_%s, true/false);" % a) + return '\n'.join(buff) + + def fill_model_h(self): + buf =3D [ + "/* SPDX-License-Identifier: GPL-2.0 */", + "", + "/*", + " * C implementation of Buchi automaton, automatically generat= ed by", + " * tools/verification/rvgen from the linear temporal logic sp= ecification.", + " * For further information, see kernel documentation:", + " * Documentation/trace/rv/linear_temporal_logic.rst", + " */", + "", + "#include ", + "", + "#define MONITOR_NAME " + self.name, + "" + ] + + buf.extend(self._fill_atoms()) + buf.append('') + + buf.extend(self._fill_atoms_to_string()) + buf.append('') + + buf.extend(self._fill_states()) + buf.append('') + + buf.extend(self._fill_start()) + buf.append('') + + buf.extend(self._fill_transitions()) + buf.append('') + + return '\n'.join(buf) + + def fill_monitor_class_type(self): + return "LTL_MON_EVENTS_ID" + + def fill_monitor_class(self): + return "ltl_monitor_id" + + def fill_main_c(self): + main_c =3D super().fill_main_c() + main_c =3D main_c.replace("%%ATOMS_INIT%%", self.fill_atoms_init()) + + return main_c diff --git a/tools/verification/rvgen/rvgen/templates/ltl2k/main.c b/tools/= verification/rvgen/rvgen/templates/ltl2k/main.c new file mode 100644 index 000000000000..f85d076fbf78 --- /dev/null +++ b/tools/verification/rvgen/rvgen/templates/ltl2k/main.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "%%MODEL_NAME%%" + +/* + * XXX: include required tracepoint headers, e.g., + * #include + */ +#include +%%INCLUDE_PARENT%% + +/* + * This is the self-generated part of the monitor. Generally, there is no = need + * to touch this section. + */ +#include "%%MODEL_NAME%%.h" +#include + +static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *= mon) +{ + /* + * This is called everytime the Buchi automaton is triggered. + * + * This function could be used to fetch the atomic propositions which + * are expensive to trace. It is possible only if the atomic proposition + * does not need to be updated at precise time. + * + * It is recommended to use tracepoints and ltl_atom_update() instead. + */ +} + +static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *m= on, bool task_creation) +{ + /* + * This should initialize as many atomic propositions as possible. + * + * @task_creation indicates whether the task is being created. This is + * false if the task is already running before the monitor is enabled. + */ +%%ATOMS_INIT%% +} + +/* + * 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%% +static int enable_%%MODEL_NAME%%(void) +{ + int retval; + + retval =3D ltl_monitor_init(); + if (retval) + return retval; + +%%TRACEPOINT_ATTACH%% + + return 0; +} + +static void disable_%%MODEL_NAME%%(void) +{ +%%TRACEPOINT_DETACH%% + + ltl_monitor_destroy(); +} + +/* + * This is the monitor register section. + */ +static struct rv_monitor rv_%%MODEL_NAME%% =3D { + .name =3D "%%MODEL_NAME%%", + .description =3D "%%DESCRIPTION%%", + .enable =3D enable_%%MODEL_NAME%%, + .disable =3D disable_%%MODEL_NAME%%, +}; + +static int __init register_%%MODEL_NAME%%(void) +{ + return rv_register_monitor(&rv_%%MODEL_NAME%%, %%PARENT%%); +} + +static void __exit unregister_%%MODEL_NAME%%(void) +{ + rv_unregister_monitor(&rv_%%MODEL_NAME%%); +} + +module_init(register_%%MODEL_NAME%%); +module_exit(unregister_%%MODEL_NAME%%); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(/* TODO */); +MODULE_DESCRIPTION("%%MODEL_NAME%%: %%DESCRIPTION%%"); diff --git a/tools/verification/rvgen/rvgen/templates/ltl2k/trace.h b/tools= /verification/rvgen/rvgen/templates/ltl2k/trace.h new file mode 100644 index 000000000000..49394c4b0f1c --- /dev/null +++ b/tools/verification/rvgen/rvgen/templates/ltl2k/trace.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Snippet to be included in rv_trace.h + */ + +#ifdef CONFIG_RV_MON_%%MODEL_NAME_UP%% +DEFINE_EVENT(event_%%MONITOR_CLASS%%, event_%%MODEL_NAME%%, + TP_PROTO(struct task_struct *task, char *states, char *atoms, char *= next), + TP_ARGS(task, states, atoms, next)); +DEFINE_EVENT(error_%%MONITOR_CLASS%%, error_%%MODEL_NAME%%, + TP_PROTO(struct task_struct *task), + TP_ARGS(task)); +#endif /* CONFIG_RV_MON_%%MODEL_NAME_UP%% */ --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 AA743303DCB; Fri, 4 Jul 2025 13:20:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635243; cv=none; b=H4vD2tVxAERoJDE64+woQ2yhcWNuM+1XW45a+bIqo2KDnqVfYTW9xvI+jH9ENXog6+YHZBTwLUtGzfndYXIFvmHn69iqa4MmjeM08UKDLlwVB6SZWUKB9uybkpvn1mU9QuWYBws1G1qN5VWU3i9RHkylytuQs2b+TczjJD5e//I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635243; c=relaxed/simple; bh=TBOO2AQSEASuyWnG4DlvlSfUwCeZ9UIJdlj7NIr/YgU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=jCide+SCqrO7cpf0HCpd8EyBSrfhsqglWjoLW6C62+wD7dE9Fp4SWCJPrfemQvuVG6Op4NRKVKcucHva8pnGxvSN1DF/eBKXbkCKLK8EEVL3kImX4symXCYVKL1xZ0aACOz8HpjYUa1a7zsSxI8DF26FuwgTpW7azndbNXXbpNU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=mgdLzJak; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=7u+9oYe4; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="mgdLzJak"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="7u+9oYe4" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635238; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1sIiqASdnVahoU69Z+YarnWuWRAvV/Tk9WWJfBmMBXk=; b=mgdLzJakv5jot1BD/tTKNWGPWHb3mYXJWNKmfXyd4qvdmCRjHILrt4+M3Wa0bG5OcqupYo XWZT+pCC+HEoWbwX0OIBlCfUYyQB1jBWxODyywNGqnio8M7s5esgprfUTtZcZboKXR98Ml SrD3yWMMsaDXnniPLeXv+2aQrP7Yd8plu1K9wGAwYwVqJj5tXpchkjK9YLBO62/ihg4P3z rwgpwNlBOTW7c1oEDPp9vaQCUvjSqmUbOvgDh9IqkFHWz1xbDXfZJh2CE/nqc1aAy7sfbb pWAP9UnNHEAPdKkXJJ8+Dz6Aw1EePZxRnON3P8z5saJDhvn4PmKuOl3eZxMdYQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635238; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1sIiqASdnVahoU69Z+YarnWuWRAvV/Tk9WWJfBmMBXk=; b=7u+9oYe4V7jh5JbBNHG8Mzevoz9WHgDM6ZcIvRxy86lLgIr5wx6+rAABx+PvozeXyHZz7W ADcfVabh0gQKn/Bw== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 15/21] Documentation/rv: Add documentation for linear temporal logic monitors Date: Fri, 4 Jul 2025 15:20:07 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Add documents describing linear temporal logic runtime verification monitors and how to generate them using rvgen. Signed-off-by: Nam Cao --- v11: - Keep the doc within 80 columns - Split this out from the bigger patch --- Documentation/trace/rv/index.rst | 1 + .../trace/rv/linear_temporal_logic.rst | 133 +++++++++++++++ Documentation/trace/rv/monitor_synthesis.rst | 156 ++++++++++++++++-- 3 files changed, 274 insertions(+), 16 deletions(-) create mode 100644 Documentation/trace/rv/linear_temporal_logic.rst diff --git a/Documentation/trace/rv/index.rst b/Documentation/trace/rv/inde= x.rst index 8e411b76ec82..2a27f6bc9429 100644 --- a/Documentation/trace/rv/index.rst +++ b/Documentation/trace/rv/index.rst @@ -8,6 +8,7 @@ Runtime Verification =20 runtime-verification.rst deterministic_automata.rst + linear_temporal_logic.rst monitor_synthesis.rst da_monitor_instrumentation.rst monitor_wip.rst diff --git a/Documentation/trace/rv/linear_temporal_logic.rst b/Documentati= on/trace/rv/linear_temporal_logic.rst new file mode 100644 index 000000000000..57f107fcf6dd --- /dev/null +++ b/Documentation/trace/rv/linear_temporal_logic.rst @@ -0,0 +1,133 @@ +Linear temporal logic +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Introduction +------------ + +Runtime verification monitor is a verification technique which checks that= the +kernel follows a specification. It does so by using tracepoints to monitor= the +kernel's execution trace, and verifying that the execution trace sastifies= the +specification. + +Initially, the specification can only be written in the form of determinis= tic +automaton (DA). However, while attempting to implement DA monitors for so= me +complex specifications, deterministic automaton is found to be inappropria= te as +the specification language. The automaton is complicated, hard to understa= nd, +and error-prone. + +Thus, RV monitors based on linear temporal logic (LTL) are introduced. Thi= s type +of monitor uses LTL as specification instead of DA. For some cases, writin= g the +specification as LTL is more concise and intuitive. + +Many materials explain LTL in details. One book is:: + + Christel Baier and Joost-Pieter Katoen: Principles of Model Checking, Th= e MIT + Press, 2008. + +Grammar +------- + +Unlike some existing syntax, kernel's implementation of LTL is more verbos= e. +This is motivated by considering that the people who read the LTL specific= ations +may not be well-versed in LTL. + +Grammar: + ltl ::=3D opd | ( ltl ) | ltl binop ltl | unop ltl + +Operands (opd): + true, false, user-defined names consisting of upper-case characters, d= igits, + and underscore. + +Unary Operators (unop): + always + eventually + not + +Binary Operators (binop): + until + and + or + imply + equivalent + +This grammar is ambiguous: operator precedence is not defined. Parentheses= must +be used. + +Example linear temporal logic +----------------------------- +.. code-block:: + + RAIN imply (GO_OUTSIDE imply HAVE_UMBRELLA) + +means: if it is raining, going outside means having an umbrella. + +.. code-block:: + + RAIN imply (WET until not RAIN) + +means: if it is raining, it is going to be wet until the rain stops. + +.. code-block:: + + RAIN imply eventually not RAIN + +means: if it is raining, rain will eventually stop. + +The above examples are referring to the current time instance only. For ke= rnel +verification, the `always` operator is usually desirable, to specify that +something is always true at the present and for all future. For example:: + + always (RAIN imply eventually not RAIN) + +means: *all* rain eventually stops. + +In the above examples, `RAIN`, `GO_OUTSIDE`, `HAVE_UMBRELLA` and `WET` are= the +"atomic propositions". + +Monitor synthesis +----------------- + +To synthesize an LTL into a kernel monitor, the `rvgen` tool can be used: +`tools/verification/rvgen`. The specification needs to be provided as a fi= le, +and it must have a "RULE =3D LTL" assignment. For example:: + + RULE =3D always (ACQUIRE imply ((not KILLED and not CRASHED) until REL= EASE)) + +which says: if `ACQUIRE`, then `RELEASE` must happen before `KILLED` or +`CRASHED`. + +The LTL can be broken down using sub-expressions. The above is equivalent = to: + + .. code-block:: + + RULE =3D always (ACQUIRE imply (ALIVE until RELEASE)) + ALIVE =3D not KILLED and not CRASHED + +From this specification, `rvgen` generates the C implementation of a Buchi +automaton - a non-deterministic state machine which checks the satisfiabil= ity of +the LTL. See Documentation/trace/rv/monitor_synthesis.rst for details on u= sing +`rvgen`. + +References +---------- + +One book covering model checking and linear temporal logic is:: + + Christel Baier and Joost-Pieter Katoen: Principles of Model Checking, Th= e MIT + Press, 2008. + +For an example of using linear temporal logic in software testing, see:: + + Ruijie Meng, Zhen Dong, Jialin Li, Ivan Beschastnikh, and Abhik Roychoud= hury. + 2022. Linear-time temporal logic guided greybox fuzzing. In Proceedings = of the + 44th International Conference on Software Engineering (ICSE '22). Assoc= iation + for Computing Machinery, New York, NY, USA, 1343=E2=80=931355. + https://doi.org/10.1145/3510003.3510082 + +The kernel's LTL monitor implementation is based on:: + + Gerth, R., Peled, D., Vardi, M.Y., Wolper, P. (1996). Simple On-the-fly + Automatic Verification of Linear Temporal Logic. In: Dembi=C5=84ski, P.,= =C5=9Aredniawa, + M. (eds) Protocol Specification, Testing and Verification XV. PSTV 1995.= IFIP + Advances in Information and Communication Technology. Springer, Boston, = MA. + https://doi.org/10.1007/978-0-387-34892-6_1 diff --git a/Documentation/trace/rv/monitor_synthesis.rst b/Documentation/t= race/rv/monitor_synthesis.rst index 85624062073b..ac808a7554f5 100644 --- a/Documentation/trace/rv/monitor_synthesis.rst +++ b/Documentation/trace/rv/monitor_synthesis.rst @@ -39,16 +39,18 @@ below:: RV monitor synthesis -------------------- =20 -The synthesis of automata-based models into the Linux *RV monitor* abstrac= tion -is automated by the rvgen tool and the rv/da_monitor.h header file that -contains a set of macros that automatically generate the monitor's code. +The synthesis of a specification into the Linux *RV monitor* abstraction is +automated by the rvgen tool and the header file containing common code for +creating monitors. The header files are: + + * rv/da_monitor.h for deterministic automaton monitor. + * rv/ltl_monitor.h for linear temporal logic monitor. =20 rvgen ----- =20 -The rvgen utility leverages dot2c by converting an automaton model in -the DOT format into the C representation [1] and creating the skeleton of -a kernel monitor in C. +The rvgen utility converts a specification into the C presentation and cre= ating +the skeleton of a kernel monitor in C. =20 For example, it is possible to transform the wip.dot model present in [1] into a per-cpu monitor with the following command:: @@ -63,18 +65,38 @@ This will create a directory named wip/ with the follow= ing files: The wip.c file contains the monitor declaration and the starting point for the system instrumentation. =20 -Monitor macros --------------- +Similarly, a linear temporal logic monitor can be generated with the follo= wing +command:: + + $ rvgen monitor -c ltl -s pagefault.ltl -t per_task + +This generates pagefault/ directory with: + +- pagefault.h: The Buchi automaton (the non-deterministic state machine to + verify the specification) +- pagefault.c: The skeleton for the RV monitor + +Monitor header files +-------------------- + +The header files: + +- `rv/da_monitor.h` for deterministic automaton monitor +- `rv/ltl_monitor` for linear temporal logic monitor + +include common macros and static functions for implementing *Monitor +Instance(s)*. =20 -The rv/da_monitor.h enables automatic code generation for the *Monitor -Instance(s)* using C macros. +The benefits of having all common functionalities in a single header file = are +3-fold: =20 -The benefits of the usage of macro for monitor synthesis are 3-fold as it: + - Reduce the code duplication; + - Facilitate the bug fix/improvement; + - Avoid the case of developers changing the core of the monitor code to + manipulate the model in a (let's say) non-standard way. =20 -- Reduces the code duplication; -- Facilitates the bug fix/improvement; -- Avoids the case of developers changing the core of the monitor code - to manipulate the model in a (let's say) non-standard way. +rv/da_monitor.h ++++++++++++++++ =20 This initial implementation presents three different types of monitor inst= ances: =20 @@ -130,10 +152,112 @@ While the event "preempt_enabled" will use:: To notify the monitor that the system will be returning to the initial sta= te, so the system and the monitor should be in sync. =20 +rv/ltl_monitor.h +++++++++++++++++ +This file must be combined with the $(MODEL_NAME).h file (generated by `rv= gen`) +to be complete. For example, for the `pagefault` monitor, the `pagefault.c` +source file must include:: + + #include "pagefault.h" + #include + +(the skeleton monitor file generated by `rvgen` already does this). + +`$(MODEL_NAME).h` (`pagefault.h` in the above example) includes the +implementation of the Buchi automaton - a non-deterministic state machine = that +verifies the LTL specification. While `rv/ltl_monitor.h` includes the comm= on +helper functions to interact with the Buchi automaton and to implement an = RV +monitor. An important definition in `$(MODEL_NAME).h` is:: + + enum ltl_atom { + LTL_$(FIRST_ATOMIC_PROPOSITION), + LTL_$(SECOND_ATOMIC_PROPOSITION), + ... + LTL_NUM_ATOM + }; + +which is the list of atomic propositions present in the LTL specification +(prefixed with "LTL\_" to avoid name collision). This `enum` is passed to = the +functions interacting with the Buchi automaton. + +While generating code, `rvgen` cannot understand the meaning of the atomic +propositions. Thus, that task is left for manual work. The recommended pra= tice +is adding tracepoints to places where the atomic propositions change; and = in the +tracepoints' handlers: the Buchi automaton is executed using:: + + void ltl_atom_update(struct task_struct *task, enum ltl_atom atom, bool = value) + +which tells the Buchi automaton that the atomic proposition `atom` is now +`value`. The Buchi automaton checks whether the LTL specification is still +satisfied, and invokes the monitor's error tracepoint and the reactor if +violation is detected. + +Tracepoints and `ltl_atom_update()` should be used whenever possible. Howe= ver, +it is sometimes not the most convenient. For some atomic propositions whic= h are +changed in multiple places in the kernel, it is cumbersome to trace all th= ose +places. Furthermore, it may not be important that the atomic propositions = are +updated at precise times. For example, considering the following linear te= mporal +logic:: + + RULE =3D always (RT imply not PAGEFAULT) + +This LTL states that a real-time task does not raise page faults. For this +specification, it is not important when `RT` changes, as long as it has the +correct value when `PAGEFAULT` is true. Motivated by this case, another +function is introduced:: + + void ltl_atom_fetch(struct task_struct *task, struct ltl_monitor *mon) + +This function is called whenever the Buchi automaton is triggered. Therefo= re, it +can be manually implemented to "fetch" `RT`:: + + void ltl_atom_fetch(struct task_struct *task, struct ltl_monitor *mon) + { + ltl_atom_set(mon, LTL_RT, rt_task(task)); + } + +Effectively, whenever `PAGEFAULT` is updated with a call to `ltl_atom_upda= te()`, +`RT` is also fetched. Thus, the LTL specification can be verified without +tracing `RT` everywhere. + +For atomic propositions which act like events, they usually need to be set= (or +cleared) and then immediately cleared (or set). A convenient function is +provided:: + + void ltl_atom_pulse(struct task_struct *task, enum ltl_atom atom, bool v= alue) + +which is equivalent to:: + + ltl_atom_update(task, atom, value); + ltl_atom_update(task, atom, !value); + +To initialize the atomic propositions, the following function must be +implemented:: + + ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool t= ask_creation) + +This function is called for all running tasks when the monitor is enabled.= It is +also called for new tasks created after the enabling the monitor. It should +initialize as many atomic propositions as possible, for example:: + + void ltl_atom_init(struct task_struct *task, struct ltl_monitor *mon, bo= ol task_creation) + { + ltl_atom_set(mon, LTL_RT, rt_task(task)); + if (task_creation) + ltl_atom_set(mon, LTL_PAGEFAULT, false); + } + +Atomic propositions not initialized by `ltl_atom_init()` will stay in the +unknown state until relevant tracepoints are hit, which can take some time= . As +monitoring for a task cannot be done until all atomic propositions is know= n for +the task, the monitor may need some time to start validating tasks which h= ave +been running before the monitor is enabled. Therefore, it is recommended to +start the tasks of interest after enabling the monitor. + Final remarks ------------- =20 -With the monitor synthesis in place using the rv/da_monitor.h and +With the monitor synthesis in place using the header files and rvgen, the developer's work should be limited to the instrumentation of the system, increasing the confidence in the overall approach. =20 --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 6E74F2FD588; Fri, 4 Jul 2025 13:20:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635244; cv=none; b=b7CdS5AQyuw/91um/ZNY3y/qOZRTAohozIQfFgcEcAVcwzAGUcrrYYKsltdvVV1dvl2aileAqLBAmzfo3yMid9BZAlgdARBHsXXC8Nf6zXbMWDiHN0+kGnhhNXvFRorD8XvGRkrFmCD86WqJlD+17G9XQf30lfoljPU/me1oWJ0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635244; c=relaxed/simple; bh=DcRi22O4d3UBw9x9KLG2WX/b+wJDIh4hVT93QK7WiGQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DVnDHaUGnjACQLBbcC0E51qRDrMjtIqHOQT2OsOxMJTm9AIQnukuFPWQpAYCxfSs/Uv7k3LczVF/dHiygH114UH4fU0IvkpNhPdw1EGzzOEyKbn6gkXQUOCjZPZX9qnxIbvIm8x/fD1UxBDjNYTBWCmzfs7qoly9GjoZxXrOhIM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=tlr7Q1Lz; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=5gJAsm1q; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="tlr7Q1Lz"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="5gJAsm1q" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635239; 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=DH23WTRlvZDwouVOr7H+Q/MXu18JPTVYiKREYg9L8wY=; b=tlr7Q1Lzfpo07vOFcwWFU1JXM6o9RFMsItY1e1tBlq+dKbbXHK4hx+P6qr/iodwqB/KPQj XgTg+Sen1/Sq1oHfyBWNeU0+hPsJEvRSnncJEoB/SFwOVoJkP72dA48a9sL/FuxOXQKo1e 60ciwsvF3h5TyjoHcq1xBr6VXRNlt0cyVVPzWUW9tZnoaH9frSU+bIiSFhbtdE6quCDA2V qRjC0xfoEevNq4ixA/E2DUQ4tbvxT+405EkQ2bS0ClG3KV/mOgD0MwK05RDaXcCB5ZSsQg 2NKg4UGGT0n6fS71qMMdAg/e77Cudrk7qoHzukr03XEXQWYS/ZD+YAEyfuDelw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635239; 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=DH23WTRlvZDwouVOr7H+Q/MXu18JPTVYiKREYg9L8wY=; b=5gJAsm1qs5ExWfSrt6brx5S4+FQyE98oHhbE0dp7eRvBkyAoNW/FWH3Ydf7C7m6GKB8OTa 3GnfcveYX/9MxGCQ== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 16/21] rv: Add rtapp container monitor Date: Fri, 4 Jul 2025 15:20:08 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Add the container "rtapp" which is the monitor collection for detecting problems with real-time applications. The monitors will be added in the follow-up commits. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- v11: Remove the incorrect note that this patch has performance impact (that comes later) --- kernel/trace/rv/Kconfig | 1 + kernel/trace/rv/Makefile | 1 + kernel/trace/rv/monitors/rtapp/Kconfig | 10 ++++++++ kernel/trace/rv/monitors/rtapp/rtapp.c | 33 ++++++++++++++++++++++++++ kernel/trace/rv/monitors/rtapp/rtapp.h | 3 +++ 5 files changed, 48 insertions(+) create mode 100644 kernel/trace/rv/monitors/rtapp/Kconfig create mode 100644 kernel/trace/rv/monitors/rtapp/rtapp.c create mode 100644 kernel/trace/rv/monitors/rtapp/rtapp.h diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index 6e157f964991..5c407d291661 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -41,6 +41,7 @@ source "kernel/trace/rv/monitors/snroc/Kconfig" source "kernel/trace/rv/monitors/scpd/Kconfig" source "kernel/trace/rv/monitors/snep/Kconfig" source "kernel/trace/rv/monitors/sncid/Kconfig" +source "kernel/trace/rv/monitors/rtapp/Kconfig" # Add new monitors here =20 config RV_REACTORS diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile index f9b2cd0483c3..9b28c2419995 100644 --- a/kernel/trace/rv/Makefile +++ b/kernel/trace/rv/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_RV_MON_SNROC) +=3D monitors/snroc/snroc.o obj-$(CONFIG_RV_MON_SCPD) +=3D monitors/scpd/scpd.o obj-$(CONFIG_RV_MON_SNEP) +=3D monitors/snep/snep.o obj-$(CONFIG_RV_MON_SNCID) +=3D monitors/sncid/sncid.o +obj-$(CONFIG_RV_MON_RTAPP) +=3D monitors/rtapp/rtapp.o # Add new monitors here obj-$(CONFIG_RV_REACTORS) +=3D rv_reactors.o obj-$(CONFIG_RV_REACT_PRINTK) +=3D reactor_printk.o diff --git a/kernel/trace/rv/monitors/rtapp/Kconfig b/kernel/trace/rv/monit= ors/rtapp/Kconfig new file mode 100644 index 000000000000..b7415c3570bb --- /dev/null +++ b/kernel/trace/rv/monitors/rtapp/Kconfig @@ -0,0 +1,10 @@ +config RV_MON_RTAPP + depends on RV + bool "rtapp monitor" + help + Collection of monitors to check for common problems with real-time + application that may cause unexpected latency. + + If you are developing a real-time system and not entirely sure whether + the applications are designed correctly for real-time, you want to say + Y here. diff --git a/kernel/trace/rv/monitors/rtapp/rtapp.c b/kernel/trace/rv/monit= ors/rtapp/rtapp.c new file mode 100644 index 000000000000..fd75fc927d65 --- /dev/null +++ b/kernel/trace/rv/monitors/rtapp/rtapp.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include + +#define MODULE_NAME "rtapp" + +#include "rtapp.h" + +struct rv_monitor rv_rtapp; + +struct rv_monitor rv_rtapp =3D { + .name =3D "rtapp", + .description =3D "Collection of monitors for detecting problems with real= -time applications", +}; + +static int __init register_rtapp(void) +{ + return rv_register_monitor(&rv_rtapp, NULL); +} + +static void __exit unregister_rtapp(void) +{ + rv_unregister_monitor(&rv_rtapp); +} + +module_init(register_rtapp); +module_exit(unregister_rtapp); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nam Cao "); +MODULE_DESCRIPTION("Collection of monitors for detecting problems with rea= l-time applications"); diff --git a/kernel/trace/rv/monitors/rtapp/rtapp.h b/kernel/trace/rv/monit= ors/rtapp/rtapp.h new file mode 100644 index 000000000000..4c200d67c7f6 --- /dev/null +++ b/kernel/trace/rv/monitors/rtapp/rtapp.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +extern struct rv_monitor rv_rtapp; --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 4739A30749D; Fri, 4 Jul 2025 13:20:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635245; cv=none; b=oTZthLbv33Sjcq1woGcgKGSdHXEICFXsH4ey74SlO9sNR3UoM9jioyZLqZse+xCr7rqOP6HD3VF5Iwa8hTODjgDRuvBGqj4y+9sqEu4Q8fk2Fkkt6Migxl5pxnvgkO8yinRtzDLaPd0e+Lb7PHuyQkJZ41SddZ+UTxC0bKgciOQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635245; c=relaxed/simple; bh=FWBQX1/asfPTUJ186TDblgFmvHyPG/sEa71kKq0O6D4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=dOhOvS5AwVdd8BDsEIPt4YdDOHwUot6kPvt4GusWLjfpiYURSO3OGRA+ans0ebybAPVRmDB5uj3ByiFHR+TLvIf0SXDKWtQ4eXaCqt54Nju5rkEMZvUaRDK2bmSwp4Tt1ZBwJBhxgA5VY5Xr5W41erd+TVfJPmlfIcFkgBe42wc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=BdZMuLx8; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=FgxC8+w9; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="BdZMuLx8"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="FgxC8+w9" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635240; 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=EE8nze+dHV488yKI++rzQSjed2WDi861RqnjmSmBFVc=; b=BdZMuLx8cSXRL5EOMJAQ26EuaXJpzQsttckmE06bw/HAGjLRF9iAwRN9fxNaPyQv838kvm 5Vlrh8g9JUuXPAsH/U7dKI6XTkpskUBziil2Rvn+FBPZWw5sBD8mzUh9ZDdiJDYl6bGjyQ eXzCzt7uOIObnj9t2YGxaN1tMNMdXPoSlzL7+4MTWxe6BDWgUTctzrk1y/HVPCaEgoaJJN s4XfOnZDLldBcLE1MM3NvzPTvDdFlDAgPpr9gcDJJ+gR88uv96UgcmJv7CTJAw9sUx+k2R iAYqNh6/10UXPCWDHYjJzAZlZc76QSKYyIBSgGAW9zrU+Gacp/Jz4mksLIBWLg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635240; 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=EE8nze+dHV488yKI++rzQSjed2WDi861RqnjmSmBFVc=; b=FgxC8+w9z4RUHzTPkrnkogGgx03o6FFPgAURnK5rWK+Y/OBBxXCKWrHbsqZ6ruZvye7UDX N5/YM3gzDoHZZWBA== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao , Alexandre Ghiti , Palmer Dabbelt , Paul Walmsley , Albert Ou , linux-riscv@lists.infradead.org Subject: [PATCH v11 17/21] riscv: mm: Add page fault trace points Date: Fri, 4 Jul 2025 15:20:09 +0200 Message-Id: <97604a88be30e672e40a0ddf02a1d5a623ed8c97.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Add page fault trace points, which are useful to implement RV monitor that watches page faults. Signed-off-by: Nam Cao Acked-by: Alexandre Ghiti Acked-by: Palmer Dabbelt --- Cc: Paul Walmsley Cc: Albert Ou Cc: linux-riscv@lists.infradead.org --- arch/riscv/mm/fault.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index 0194324a0c50..04ed6f8acae4 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c @@ -20,6 +20,9 @@ #include #include =20 +#define CREATE_TRACE_POINTS +#include + #include "../kernel/head.h" =20 static void show_pte(unsigned long addr) @@ -291,6 +294,11 @@ void handle_page_fault(struct pt_regs *regs) if (kprobe_page_fault(regs, cause)) return; =20 + if (user_mode(regs)) + trace_page_fault_user(addr, regs, cause); + else + trace_page_fault_kernel(addr, regs, cause); + /* * Fault-in kernel-space virtual memory on-demand. * The 'reference' page table is init_mm.pgd. --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 3B1F72F94BD; Fri, 4 Jul 2025 13:20:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; cv=none; b=mCGFdzUqTGQkNRWlMLaAU5ZVzszTan9jm10YXelgIkKRuhhFX8vUq2QFfy3AXG74hdWhmYUeIrV39Whxe/otKNNBtw5WBN28jyGsCfKNx4sQ7vHpoNmAUmBod2Z/Y9pgpucMN7lGmcwR8IiEPz7WgXc/bbtTvcJtceZLG2Uo/cc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; c=relaxed/simple; bh=3utwXlReO4IhjgaBs47VW0q+zsLGVjxsT/h85xZExd8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JptXnMfuwHDpgpql7prAeD2Psl4Waf0i47lzHn/J8bj5xA1jlbjG6IufsebAqBnvArekpJpGMS+FOg1i+sUU8ROMIn/HmCYdoRHf637SlvWoW3ksPbWPO07QnestMnybBw5QhRyqAB6pPdMRPlWk+w55pYCF0A+IZQd8EbsqXos= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=jJ+27AD3; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=CeyofVwL; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="jJ+27AD3"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="CeyofVwL" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635241; 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=vlMc1dpjv540CoO8OHsvRwbAPWQtH/2uFDXFrb+aZhU=; b=jJ+27AD3nY0fqRJb9pmfiPoJN3awOUSo0qh32ST2i1UEuXOmObGo9MKo0kxABoKunzQepb 9xQDQaDn1d5SbnWJx8RUjfKEtU8akWa2tP+7/E4UT/Cyigd2DwAE7+R8lrl7/nL+efZipM Q9OggT8kChy/JjskHlBaWSqIBJ1ssq6vZACPyf019UPZBNgPf9+tr33HG7ixFx5Q6hniFp xsrv5lglzaA9u7JKkBuPfr4BIxOWam0LWds8qdnwOey0DhKADS7fYnKN5mAYKqratPDHEc ldWFVsIQw7HR+Og6PvMKECQmYHyWHTKeBfSP4zfmKfCBs/ozwUhcjRIDErh/og== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635241; 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=vlMc1dpjv540CoO8OHsvRwbAPWQtH/2uFDXFrb+aZhU=; b=CeyofVwL9a313GprfTYKCjV8eGH1TpkDVakZ3/igJGcmT/z8Pfn/+JwD0HTTPP9gp5gFvi PCaeFWjAFuTJd3Cg== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 18/21] rv: Add rtapp_pagefault monitor Date: Fri, 4 Jul 2025 15:20:10 +0200 Message-Id: In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Userspace real-time applications may have design flaws that they raise page faults in real-time threads, and thus have unexpected latencies. Add an linear temporal logic monitor to detect this scenario. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- v11: - Add note that the header file is completely generated - Keep the comments wihtin 80 columns --- kernel/trace/rv/Kconfig | 1 + kernel/trace/rv/Makefile | 1 + kernel/trace/rv/monitors/pagefault/Kconfig | 20 +++++ .../trace/rv/monitors/pagefault/pagefault.c | 88 +++++++++++++++++++ .../trace/rv/monitors/pagefault/pagefault.h | 64 ++++++++++++++ .../rv/monitors/pagefault/pagefault_trace.h | 14 +++ kernel/trace/rv/rv_trace.h | 1 + tools/verification/models/rtapp/pagefault.ltl | 1 + 8 files changed, 190 insertions(+) create mode 100644 kernel/trace/rv/monitors/pagefault/Kconfig create mode 100644 kernel/trace/rv/monitors/pagefault/pagefault.c create mode 100644 kernel/trace/rv/monitors/pagefault/pagefault.h create mode 100644 kernel/trace/rv/monitors/pagefault/pagefault_trace.h create mode 100644 tools/verification/models/rtapp/pagefault.ltl diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index 5c407d291661..6f86d8501e87 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -42,6 +42,7 @@ source "kernel/trace/rv/monitors/scpd/Kconfig" source "kernel/trace/rv/monitors/snep/Kconfig" source "kernel/trace/rv/monitors/sncid/Kconfig" source "kernel/trace/rv/monitors/rtapp/Kconfig" +source "kernel/trace/rv/monitors/pagefault/Kconfig" # Add new monitors here =20 config RV_REACTORS diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile index 9b28c2419995..353ecf939d0e 100644 --- a/kernel/trace/rv/Makefile +++ b/kernel/trace/rv/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_RV_MON_SCPD) +=3D monitors/scpd/scpd.o obj-$(CONFIG_RV_MON_SNEP) +=3D monitors/snep/snep.o obj-$(CONFIG_RV_MON_SNCID) +=3D monitors/sncid/sncid.o obj-$(CONFIG_RV_MON_RTAPP) +=3D monitors/rtapp/rtapp.o +obj-$(CONFIG_RV_MON_PAGEFAULT) +=3D monitors/pagefault/pagefault.o # Add new monitors here obj-$(CONFIG_RV_REACTORS) +=3D rv_reactors.o obj-$(CONFIG_RV_REACT_PRINTK) +=3D reactor_printk.o diff --git a/kernel/trace/rv/monitors/pagefault/Kconfig b/kernel/trace/rv/m= onitors/pagefault/Kconfig new file mode 100644 index 000000000000..5e16625f1653 --- /dev/null +++ b/kernel/trace/rv/monitors/pagefault/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +config RV_MON_PAGEFAULT + depends on RV + select RV_LTL_MONITOR + depends on RV_MON_RTAPP + depends on X86 || RISCV + default y + select LTL_MON_EVENTS_ID + bool "pagefault monitor" + help + Monitor that real-time tasks do not raise page faults, causing + undesirable latency. + + If you are developing a real-time system and not entirely sure whether + the applications are designed correctly for real-time, you want to say + Y here. + + This monitor does not affect execution speed while it is not running, + therefore it is safe to enable this in production kernel. diff --git a/kernel/trace/rv/monitors/pagefault/pagefault.c b/kernel/trace/= rv/monitors/pagefault/pagefault.c new file mode 100644 index 000000000000..9fe6123b2200 --- /dev/null +++ b/kernel/trace/rv/monitors/pagefault/pagefault.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "pagefault" + +#include +#include +#include + +#include "pagefault.h" +#include + +static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *= mon) +{ + /* + * This includes "actual" real-time tasks and also PI-boosted + * tasks. A task being PI-boosted means it is blocking an "actual" + * real-task, therefore it should also obey the monitor's rule, + * otherwise the "actual" real-task may be delayed. + */ + ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task)); +} + +static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *m= on, bool task_creation) +{ + if (task_creation) + ltl_atom_set(mon, LTL_PAGEFAULT, false); +} + +static void handle_page_fault(void *data, unsigned long address, struct pt= _regs *regs, + unsigned long error_code) +{ + ltl_atom_pulse(current, LTL_PAGEFAULT, true); +} + +static int enable_pagefault(void) +{ + int retval; + + retval =3D ltl_monitor_init(); + if (retval) + return retval; + + rv_attach_trace_probe("rtapp_pagefault", page_fault_kernel, handle_page_f= ault); + rv_attach_trace_probe("rtapp_pagefault", page_fault_user, handle_page_fau= lt); + + return 0; +} + +static void disable_pagefault(void) +{ + rv_detach_trace_probe("rtapp_pagefault", page_fault_kernel, handle_page_f= ault); + rv_detach_trace_probe("rtapp_pagefault", page_fault_user, handle_page_fau= lt); + + ltl_monitor_destroy(); +} + +static struct rv_monitor rv_pagefault =3D { + .name =3D "pagefault", + .description =3D "Monitor that RT tasks do not raise page faults", + .enable =3D enable_pagefault, + .disable =3D disable_pagefault, +}; + +static int __init register_pagefault(void) +{ + return rv_register_monitor(&rv_pagefault, &rv_rtapp); +} + +static void __exit unregister_pagefault(void) +{ + rv_unregister_monitor(&rv_pagefault); +} + +module_init(register_pagefault); +module_exit(unregister_pagefault); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nam Cao "); +MODULE_DESCRIPTION("pagefault: Monitor that RT tasks do not raise page fau= lts"); diff --git a/kernel/trace/rv/monitors/pagefault/pagefault.h b/kernel/trace/= rv/monitors/pagefault/pagefault.h new file mode 100644 index 000000000000..c580ec194009 --- /dev/null +++ b/kernel/trace/rv/monitors/pagefault/pagefault.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * C implementation of Buchi automaton, automatically generated by + * tools/verification/rvgen from the linear temporal logic specification. + * For further information, see kernel documentation: + * Documentation/trace/rv/linear_temporal_logic.rst + */ + +#include + +#define MONITOR_NAME pagefault + +enum ltl_atom { + LTL_PAGEFAULT, + LTL_RT, + LTL_NUM_ATOM +}; +static_assert(LTL_NUM_ATOM <=3D RV_MAX_LTL_ATOM); + +static const char *ltl_atom_str(enum ltl_atom atom) +{ + static const char *const names[] =3D { + "pa", + "rt", + }; + + return names[atom]; +} + +enum ltl_buchi_state { + S0, + RV_NUM_BA_STATES +}; +static_assert(RV_NUM_BA_STATES <=3D RV_MAX_BA_STATES); + +static void ltl_start(struct task_struct *task, struct ltl_monitor *mon) +{ + bool pagefault =3D test_bit(LTL_PAGEFAULT, mon->atoms); + bool val3 =3D !pagefault; + bool rt =3D test_bit(LTL_RT, mon->atoms); + bool val1 =3D !rt; + bool val4 =3D val1 || val3; + + if (val4) + __set_bit(S0, mon->states); +} + +static void +ltl_possible_next_states(struct ltl_monitor *mon, unsigned int state, unsi= gned long *next) +{ + bool pagefault =3D test_bit(LTL_PAGEFAULT, mon->atoms); + bool val3 =3D !pagefault; + bool rt =3D test_bit(LTL_RT, mon->atoms); + bool val1 =3D !rt; + bool val4 =3D val1 || val3; + + switch (state) { + case S0: + if (val4) + __set_bit(S0, next); + break; + } +} diff --git a/kernel/trace/rv/monitors/pagefault/pagefault_trace.h b/kernel/= trace/rv/monitors/pagefault/pagefault_trace.h new file mode 100644 index 000000000000..fe1f82597b1a --- /dev/null +++ b/kernel/trace/rv/monitors/pagefault/pagefault_trace.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Snippet to be included in rv_trace.h + */ + +#ifdef CONFIG_RV_MON_PAGEFAULT +DEFINE_EVENT(event_ltl_monitor_id, event_pagefault, + TP_PROTO(struct task_struct *task, char *states, char *atoms, char *= next), + TP_ARGS(task, states, atoms, next)); +DEFINE_EVENT(error_ltl_monitor_id, error_pagefault, + TP_PROTO(struct task_struct *task), + TP_ARGS(task)); +#endif /* CONFIG_RV_MON_PAGEFAULT */ diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h index fd3111ad1d51..98eee8ec96e4 100644 --- a/kernel/trace/rv/rv_trace.h +++ b/kernel/trace/rv/rv_trace.h @@ -172,6 +172,7 @@ DECLARE_EVENT_CLASS(error_ltl_monitor_id, =20 TP_printk("%s[%d]: violation detected", __get_str(comm), __entry->pid) ); +#include // Add new monitors based on CONFIG_LTL_MON_EVENTS_ID here #endif /* CONFIG_LTL_MON_EVENTS_ID */ #endif /* _TRACE_RV_H */ diff --git a/tools/verification/models/rtapp/pagefault.ltl b/tools/verifica= tion/models/rtapp/pagefault.ltl new file mode 100644 index 000000000000..d7ce62102733 --- /dev/null +++ b/tools/verification/models/rtapp/pagefault.ltl @@ -0,0 +1 @@ +RULE =3D always (RT imply not PAGEFAULT) --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 3D8C33074B0; Fri, 4 Jul 2025 13:20:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; cv=none; b=T0JPWFn9+1xxhEQOX8uqSOm1SC1tzgkVoBeej+MKtQry1feTPAhse/e2ZdG7qk7lnX8rcLI1DyQ8850URlYLDZrcMsv1YtbzNiW/FYINGzse4H8TpR615QUohRaQQXJ33vN6iBMW5bl/XbteGmrWR6Ww9mZj0w2dPEBqDYyPDpc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; c=relaxed/simple; bh=n17XeoJLddGc63Jkv8Ii6jI4GrKCoAOp2/WjGDaI3Kc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ddAaPGLj1j+sTOAiAFF+zv+3B+/micgOX5k4DpeJ7Mq5omUSgV6EETtahltcuEDKqLYLYILsEHoMz9wEqklHlHae7W1p+S8V6r65zGi62N5KhOnTRrAsYlWgEPBXtuPDZoWGJmC7oyMTJdhX1EJpo26vBulbBJjvXkRKm1a8Ks8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=ruOHABVs; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=hKmhpaoo; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="ruOHABVs"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="hKmhpaoo" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635241; 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=JnVUGY7q5AhzaITroHjdEOkJp+4ErA8qVqqild0/09k=; b=ruOHABVsu/bb8ZnHuTOlz1qYSB1pVGbfG7Ahx8yzXK1xTdPthTl/fEb+NtVRCNiBjmwAE/ 3S2krkVA9Q4j3ddWlKbQ+OL0xagVbBwXg7xbfHlO9aeiFJgpvSkVrQvXPwqrXhpAJf+ULR kuQrru9vdMRzKwO3fBsJFgzAKP+zbq6jmds8x7jR+RoPuPIfsD8dbI+Pa0LxEmDdLOq9xv CaAIzoq3LpUhwo7viGRJ2JckFRobwTC1QycngDZDMEM5hduOz7zyKpDSoeQa5TVCXhnCEA WOFtsqgL5ka1cX3ubWivULY+kZ5E0UqUHi/o5hsq3UWwwKfKRLQgQWdaqJaJrg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635241; 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=JnVUGY7q5AhzaITroHjdEOkJp+4ErA8qVqqild0/09k=; b=hKmhpaooNHtIgerd57LM1lTUi2iOYhXxtjp/GXpPTUYWU/bvd78CwfZ8ynypfDIQu+AZGD r/XcxwPlfaJpdtDw== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 19/21] rv: Add rtapp_sleep monitor Date: Fri, 4 Jul 2025 15:20:11 +0200 Message-Id: <06f4152fdc07f7dd0f28939f77a07ce03be8849f.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Add a monitor for checking that real-time tasks do not go to sleep in a manner that may cause undesirable latency. Also change RV depends on TRACING to RV select TRACING to avoid the following recursive dependency: error: recursive dependency detected! symbol TRACING is selected by PREEMPTIRQ_TRACEPOINTS symbol PREEMPTIRQ_TRACEPOINTS depends on TRACE_IRQFLAGS symbol TRACE_IRQFLAGS is selected by RV_MON_SLEEP symbol RV_MON_SLEEP depends on RV symbol RV depends on TRACING Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- v11: - Add note that the header file is completely generated - Keep the comments wihtin 80 columns --- kernel/trace/rv/Kconfig | 3 +- kernel/trace/rv/Makefile | 1 + kernel/trace/rv/monitors/sleep/Kconfig | 22 ++ kernel/trace/rv/monitors/sleep/sleep.c | 237 +++++++++++++++++ kernel/trace/rv/monitors/sleep/sleep.h | 257 +++++++++++++++++++ kernel/trace/rv/monitors/sleep/sleep_trace.h | 14 + kernel/trace/rv/rv_trace.h | 1 + tools/verification/models/rtapp/sleep.ltl | 22 ++ 8 files changed, 556 insertions(+), 1 deletion(-) create mode 100644 kernel/trace/rv/monitors/sleep/Kconfig create mode 100644 kernel/trace/rv/monitors/sleep/sleep.c create mode 100644 kernel/trace/rv/monitors/sleep/sleep.h create mode 100644 kernel/trace/rv/monitors/sleep/sleep_trace.h create mode 100644 tools/verification/models/rtapp/sleep.ltl diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index 6f86d8501e87..942d57575e67 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -20,7 +20,7 @@ config RV_LTL_MONITOR =20 menuconfig RV bool "Runtime Verification" - depends on TRACING + select TRACING help Enable the kernel runtime verification infrastructure. RV is a lightweight (yet rigorous) method that complements classical @@ -43,6 +43,7 @@ source "kernel/trace/rv/monitors/snep/Kconfig" source "kernel/trace/rv/monitors/sncid/Kconfig" source "kernel/trace/rv/monitors/rtapp/Kconfig" source "kernel/trace/rv/monitors/pagefault/Kconfig" +source "kernel/trace/rv/monitors/sleep/Kconfig" # Add new monitors here =20 config RV_REACTORS diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile index 353ecf939d0e..13ec2944c665 100644 --- a/kernel/trace/rv/Makefile +++ b/kernel/trace/rv/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_RV_MON_SNEP) +=3D monitors/snep/snep.o obj-$(CONFIG_RV_MON_SNCID) +=3D monitors/sncid/sncid.o obj-$(CONFIG_RV_MON_RTAPP) +=3D monitors/rtapp/rtapp.o obj-$(CONFIG_RV_MON_PAGEFAULT) +=3D monitors/pagefault/pagefault.o +obj-$(CONFIG_RV_MON_SLEEP) +=3D monitors/sleep/sleep.o # Add new monitors here obj-$(CONFIG_RV_REACTORS) +=3D rv_reactors.o obj-$(CONFIG_RV_REACT_PRINTK) +=3D reactor_printk.o diff --git a/kernel/trace/rv/monitors/sleep/Kconfig b/kernel/trace/rv/monit= ors/sleep/Kconfig new file mode 100644 index 000000000000..6b7a122e7b47 --- /dev/null +++ b/kernel/trace/rv/monitors/sleep/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +config RV_MON_SLEEP + depends on RV + select RV_LTL_MONITOR + depends on HAVE_SYSCALL_TRACEPOINTS + depends on RV_MON_RTAPP + select TRACE_IRQFLAGS + default y + select LTL_MON_EVENTS_ID + bool "sleep monitor" + help + Monitor that real-time tasks do not sleep in a manner that may + cause undesirable latency. + + If you are developing a real-time system and not entirely sure whether + the applications are designed correctly for real-time, you want to say + Y here. + + Enabling this monitor may have performance impact (due to select + TRACE_IRQFLAGS). Therefore, you probably should say N for + production kernel. diff --git a/kernel/trace/rv/monitors/sleep/sleep.c b/kernel/trace/rv/monit= ors/sleep/sleep.c new file mode 100644 index 000000000000..eea447b06907 --- /dev/null +++ b/kernel/trace/rv/monitors/sleep/sleep.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "sleep" + +#include +#include +#include +#include +#include +#include + +#include "sleep.h" +#include + +static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *= mon) +{ + /* + * This includes "actual" real-time tasks and also PI-boosted + * tasks. A task being PI-boosted means it is blocking an "actual" + * real-task, therefore it should also obey the monitor's rule, + * otherwise the "actual" real-task may be delayed. + */ + ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task)); +} + +static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *m= on, bool task_creation) +{ + ltl_atom_set(mon, LTL_SLEEP, false); + ltl_atom_set(mon, LTL_WAKE, false); + ltl_atom_set(mon, LTL_ABORT_SLEEP, false); + ltl_atom_set(mon, LTL_WOKEN_BY_HARDIRQ, false); + ltl_atom_set(mon, LTL_WOKEN_BY_NMI, false); + ltl_atom_set(mon, LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, false); + + if (task_creation) { + ltl_atom_set(mon, LTL_KTHREAD_SHOULD_STOP, false); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); + ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); + ltl_atom_set(mon, LTL_CLOCK_NANOSLEEP, false); + ltl_atom_set(mon, LTL_FUTEX_WAIT, false); + ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); + ltl_atom_set(mon, LTL_BLOCK_ON_RT_MUTEX, false); + } + + if (task->flags & PF_KTHREAD) { + ltl_atom_set(mon, LTL_KERNEL_THREAD, true); + + /* kernel tasks do not do syscall */ + ltl_atom_set(mon, LTL_FUTEX_WAIT, false); + ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); + ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); + ltl_atom_set(mon, LTL_CLOCK_NANOSLEEP, false); + + if (strstarts(task->comm, "migration/")) + ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, true); + else + ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, false); + + if (strstarts(task->comm, "rcu")) + ltl_atom_set(mon, LTL_TASK_IS_RCU, true); + else + ltl_atom_set(mon, LTL_TASK_IS_RCU, false); + } else { + ltl_atom_set(mon, LTL_KTHREAD_SHOULD_STOP, false); + ltl_atom_set(mon, LTL_KERNEL_THREAD, false); + ltl_atom_set(mon, LTL_TASK_IS_RCU, false); + ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, false); + } + +} + +static void handle_sched_set_state(void *data, struct task_struct *task, i= nt state) +{ + if (state & TASK_INTERRUPTIBLE) + ltl_atom_pulse(task, LTL_SLEEP, true); + else if (state =3D=3D TASK_RUNNING) + ltl_atom_pulse(task, LTL_ABORT_SLEEP, true); +} + +static void handle_sched_wakeup(void *data, struct task_struct *task) +{ + ltl_atom_pulse(task, LTL_WAKE, true); +} + +static void handle_sched_waking(void *data, struct task_struct *task) +{ + if (this_cpu_read(hardirq_context)) { + ltl_atom_pulse(task, LTL_WOKEN_BY_HARDIRQ, true); + } else if (in_task()) { + if (current->prio <=3D task->prio) + ltl_atom_pulse(task, LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, true); + } else if (in_nmi()) { + ltl_atom_pulse(task, LTL_WOKEN_BY_NMI, true); + } +} + +static void handle_contention_begin(void *data, void *lock, unsigned int f= lags) +{ + if (flags & LCB_F_RT) + ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, true); +} + +static void handle_contention_end(void *data, void *lock, int ret) +{ + ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, false); +} + +static void handle_sys_enter(void *data, struct pt_regs *regs, long id) +{ + struct ltl_monitor *mon; + unsigned long args[6]; + int op, cmd; + + mon =3D ltl_get_monitor(current); + + switch (id) { + case __NR_clock_nanosleep: +#ifdef __NR_clock_nanosleep_time64 + case __NR_clock_nanosleep_time64: +#endif + syscall_get_arguments(current, regs, args); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, args[0] =3D=3D CLOCK_MO= NOTONIC); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, args[0] =3D=3D CLOCK_TAI); + ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, args[1] =3D=3D TIMER_ABST= IME); + ltl_atom_update(current, LTL_CLOCK_NANOSLEEP, true); + break; + + case __NR_futex: +#ifdef __NR_futex_time64 + case __NR_futex_time64: +#endif + syscall_get_arguments(current, regs, args); + op =3D args[1]; + cmd =3D op & FUTEX_CMD_MASK; + + switch (cmd) { + case FUTEX_LOCK_PI: + case FUTEX_LOCK_PI2: + ltl_atom_update(current, LTL_FUTEX_LOCK_PI, true); + break; + case FUTEX_WAIT: + case FUTEX_WAIT_BITSET: + case FUTEX_WAIT_REQUEUE_PI: + ltl_atom_update(current, LTL_FUTEX_WAIT, true); + break; + } + break; + } +} + +static void handle_sys_exit(void *data, struct pt_regs *regs, long ret) +{ + struct ltl_monitor *mon =3D ltl_get_monitor(current); + + ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); + ltl_atom_set(mon, LTL_FUTEX_WAIT, false); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); + ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); + ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); + ltl_atom_update(current, LTL_CLOCK_NANOSLEEP, false); +} + +static void handle_kthread_stop(void *data, struct task_struct *task) +{ + /* FIXME: this could race with other tracepoint handlers */ + ltl_atom_update(task, LTL_KTHREAD_SHOULD_STOP, true); +} + +static int enable_sleep(void) +{ + int retval; + + retval =3D ltl_monitor_init(); + if (retval) + return retval; + + rv_attach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); + rv_attach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); + rv_attach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set= _state); + rv_attach_trace_probe("rtapp_sleep", contention_begin, handle_contention_= begin); + rv_attach_trace_probe("rtapp_sleep", contention_end, handle_contention_en= d); + rv_attach_trace_probe("rtapp_sleep", sched_kthread_stop, handle_kthread_s= top); + rv_attach_trace_probe("rtapp_sleep", sys_enter, handle_sys_enter); + rv_attach_trace_probe("rtapp_sleep", sys_exit, handle_sys_exit); + return 0; +} + +static void disable_sleep(void) +{ + rv_detach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); + rv_detach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); + rv_detach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set= _state); + rv_detach_trace_probe("rtapp_sleep", contention_begin, handle_contention_= begin); + rv_detach_trace_probe("rtapp_sleep", contention_end, handle_contention_en= d); + rv_detach_trace_probe("rtapp_sleep", sched_kthread_stop, handle_kthread_s= top); + rv_detach_trace_probe("rtapp_sleep", sys_enter, handle_sys_enter); + rv_detach_trace_probe("rtapp_sleep", sys_exit, handle_sys_exit); + + ltl_monitor_destroy(); +} + +static struct rv_monitor rv_sleep =3D { + .name =3D "sleep", + .description =3D "Monitor that RT tasks do not undesirably sleep", + .enable =3D enable_sleep, + .disable =3D disable_sleep, +}; + +static int __init register_sleep(void) +{ + return rv_register_monitor(&rv_sleep, &rv_rtapp); +} + +static void __exit unregister_sleep(void) +{ + rv_unregister_monitor(&rv_sleep); +} + +module_init(register_sleep); +module_exit(unregister_sleep); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nam Cao "); +MODULE_DESCRIPTION("sleep: Monitor that RT tasks do not undesirably sleep"= ); diff --git a/kernel/trace/rv/monitors/sleep/sleep.h b/kernel/trace/rv/monit= ors/sleep/sleep.h new file mode 100644 index 000000000000..2ab46fd218d2 --- /dev/null +++ b/kernel/trace/rv/monitors/sleep/sleep.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * C implementation of Buchi automaton, automatically generated by + * tools/verification/rvgen from the linear temporal logic specification. + * For further information, see kernel documentation: + * Documentation/trace/rv/linear_temporal_logic.rst + */ + +#include + +#define MONITOR_NAME sleep + +enum ltl_atom { + LTL_ABORT_SLEEP, + LTL_BLOCK_ON_RT_MUTEX, + LTL_CLOCK_NANOSLEEP, + LTL_FUTEX_LOCK_PI, + LTL_FUTEX_WAIT, + LTL_KERNEL_THREAD, + LTL_KTHREAD_SHOULD_STOP, + LTL_NANOSLEEP_CLOCK_MONOTONIC, + LTL_NANOSLEEP_CLOCK_TAI, + LTL_NANOSLEEP_TIMER_ABSTIME, + LTL_RT, + LTL_SLEEP, + LTL_TASK_IS_MIGRATION, + LTL_TASK_IS_RCU, + LTL_WAKE, + LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, + LTL_WOKEN_BY_HARDIRQ, + LTL_WOKEN_BY_NMI, + LTL_NUM_ATOM +}; +static_assert(LTL_NUM_ATOM <=3D RV_MAX_LTL_ATOM); + +static const char *ltl_atom_str(enum ltl_atom atom) +{ + static const char *const names[] =3D { + "ab_sl", + "bl_on_rt_mu", + "cl_na", + "fu_lo_pi", + "fu_wa", + "ker_th", + "kth_sh_st", + "na_cl_mo", + "na_cl_ta", + "na_ti_ab", + "rt", + "sl", + "ta_mi", + "ta_rc", + "wak", + "wo_eq_hi_pr", + "wo_ha", + "wo_nm", + }; + + return names[atom]; +} + +enum ltl_buchi_state { + S0, + S1, + S2, + S3, + S4, + S5, + S6, + S7, + RV_NUM_BA_STATES +}; +static_assert(RV_NUM_BA_STATES <=3D RV_MAX_BA_STATES); + +static void ltl_start(struct task_struct *task, struct ltl_monitor *mon) +{ + bool task_is_migration =3D test_bit(LTL_TASK_IS_MIGRATION, mon->atoms); + bool task_is_rcu =3D test_bit(LTL_TASK_IS_RCU, mon->atoms); + bool val40 =3D task_is_rcu || task_is_migration; + bool futex_lock_pi =3D test_bit(LTL_FUTEX_LOCK_PI, mon->atoms); + bool val41 =3D futex_lock_pi || val40; + bool block_on_rt_mutex =3D test_bit(LTL_BLOCK_ON_RT_MUTEX, mon->atoms); + bool val5 =3D block_on_rt_mutex || val41; + bool kthread_should_stop =3D test_bit(LTL_KTHREAD_SHOULD_STOP, mon->atoms= ); + bool abort_sleep =3D test_bit(LTL_ABORT_SLEEP, mon->atoms); + bool val32 =3D abort_sleep || kthread_should_stop; + bool woken_by_nmi =3D test_bit(LTL_WOKEN_BY_NMI, mon->atoms); + bool val33 =3D woken_by_nmi || val32; + bool woken_by_hardirq =3D test_bit(LTL_WOKEN_BY_HARDIRQ, mon->atoms); + bool val34 =3D woken_by_hardirq || val33; + bool woken_by_equal_or_higher_prio =3D test_bit(LTL_WOKEN_BY_EQUAL_OR_HIG= HER_PRIO, + mon->atoms); + bool val14 =3D woken_by_equal_or_higher_prio || val34; + bool wake =3D test_bit(LTL_WAKE, mon->atoms); + bool val13 =3D !wake; + bool kernel_thread =3D test_bit(LTL_KERNEL_THREAD, mon->atoms); + bool nanosleep_clock_tai =3D test_bit(LTL_NANOSLEEP_CLOCK_TAI, mon->atoms= ); + bool nanosleep_clock_monotonic =3D test_bit(LTL_NANOSLEEP_CLOCK_MONOTONIC= , mon->atoms); + bool val24 =3D nanosleep_clock_monotonic || nanosleep_clock_tai; + bool nanosleep_timer_abstime =3D test_bit(LTL_NANOSLEEP_TIMER_ABSTIME, mo= n->atoms); + bool val25 =3D nanosleep_timer_abstime && val24; + bool clock_nanosleep =3D test_bit(LTL_CLOCK_NANOSLEEP, mon->atoms); + bool val18 =3D clock_nanosleep && val25; + bool futex_wait =3D test_bit(LTL_FUTEX_WAIT, mon->atoms); + bool val9 =3D futex_wait || val18; + bool val11 =3D val9 || kernel_thread; + bool sleep =3D test_bit(LTL_SLEEP, mon->atoms); + bool val2 =3D !sleep; + bool rt =3D test_bit(LTL_RT, mon->atoms); + bool val1 =3D !rt; + bool val3 =3D val1 || val2; + + if (val3) + __set_bit(S0, mon->states); + if (val11 && val13) + __set_bit(S1, mon->states); + if (val11 && val14) + __set_bit(S4, mon->states); + if (val5) + __set_bit(S5, mon->states); +} + +static void +ltl_possible_next_states(struct ltl_monitor *mon, unsigned int state, unsi= gned long *next) +{ + bool task_is_migration =3D test_bit(LTL_TASK_IS_MIGRATION, mon->atoms); + bool task_is_rcu =3D test_bit(LTL_TASK_IS_RCU, mon->atoms); + bool val40 =3D task_is_rcu || task_is_migration; + bool futex_lock_pi =3D test_bit(LTL_FUTEX_LOCK_PI, mon->atoms); + bool val41 =3D futex_lock_pi || val40; + bool block_on_rt_mutex =3D test_bit(LTL_BLOCK_ON_RT_MUTEX, mon->atoms); + bool val5 =3D block_on_rt_mutex || val41; + bool kthread_should_stop =3D test_bit(LTL_KTHREAD_SHOULD_STOP, mon->atoms= ); + bool abort_sleep =3D test_bit(LTL_ABORT_SLEEP, mon->atoms); + bool val32 =3D abort_sleep || kthread_should_stop; + bool woken_by_nmi =3D test_bit(LTL_WOKEN_BY_NMI, mon->atoms); + bool val33 =3D woken_by_nmi || val32; + bool woken_by_hardirq =3D test_bit(LTL_WOKEN_BY_HARDIRQ, mon->atoms); + bool val34 =3D woken_by_hardirq || val33; + bool woken_by_equal_or_higher_prio =3D test_bit(LTL_WOKEN_BY_EQUAL_OR_HIG= HER_PRIO, + mon->atoms); + bool val14 =3D woken_by_equal_or_higher_prio || val34; + bool wake =3D test_bit(LTL_WAKE, mon->atoms); + bool val13 =3D !wake; + bool kernel_thread =3D test_bit(LTL_KERNEL_THREAD, mon->atoms); + bool nanosleep_clock_tai =3D test_bit(LTL_NANOSLEEP_CLOCK_TAI, mon->atoms= ); + bool nanosleep_clock_monotonic =3D test_bit(LTL_NANOSLEEP_CLOCK_MONOTONIC= , mon->atoms); + bool val24 =3D nanosleep_clock_monotonic || nanosleep_clock_tai; + bool nanosleep_timer_abstime =3D test_bit(LTL_NANOSLEEP_TIMER_ABSTIME, mo= n->atoms); + bool val25 =3D nanosleep_timer_abstime && val24; + bool clock_nanosleep =3D test_bit(LTL_CLOCK_NANOSLEEP, mon->atoms); + bool val18 =3D clock_nanosleep && val25; + bool futex_wait =3D test_bit(LTL_FUTEX_WAIT, mon->atoms); + bool val9 =3D futex_wait || val18; + bool val11 =3D val9 || kernel_thread; + bool sleep =3D test_bit(LTL_SLEEP, mon->atoms); + bool val2 =3D !sleep; + bool rt =3D test_bit(LTL_RT, mon->atoms); + bool val1 =3D !rt; + bool val3 =3D val1 || val2; + + switch (state) { + case S0: + if (val3) + __set_bit(S0, next); + if (val11 && val13) + __set_bit(S1, next); + if (val11 && val14) + __set_bit(S4, next); + if (val5) + __set_bit(S5, next); + break; + case S1: + if (val11 && val13) + __set_bit(S1, next); + if (val13 && val3) + __set_bit(S2, next); + if (val14 && val3) + __set_bit(S3, next); + if (val11 && val14) + __set_bit(S4, next); + if (val13 && val5) + __set_bit(S6, next); + if (val14 && val5) + __set_bit(S7, next); + break; + case S2: + if (val11 && val13) + __set_bit(S1, next); + if (val13 && val3) + __set_bit(S2, next); + if (val14 && val3) + __set_bit(S3, next); + if (val11 && val14) + __set_bit(S4, next); + if (val13 && val5) + __set_bit(S6, next); + if (val14 && val5) + __set_bit(S7, next); + break; + case S3: + if (val3) + __set_bit(S0, next); + if (val11 && val13) + __set_bit(S1, next); + if (val11 && val14) + __set_bit(S4, next); + if (val5) + __set_bit(S5, next); + break; + case S4: + if (val3) + __set_bit(S0, next); + if (val11 && val13) + __set_bit(S1, next); + if (val11 && val14) + __set_bit(S4, next); + if (val5) + __set_bit(S5, next); + break; + case S5: + if (val3) + __set_bit(S0, next); + if (val11 && val13) + __set_bit(S1, next); + if (val11 && val14) + __set_bit(S4, next); + if (val5) + __set_bit(S5, next); + break; + case S6: + if (val11 && val13) + __set_bit(S1, next); + if (val13 && val3) + __set_bit(S2, next); + if (val14 && val3) + __set_bit(S3, next); + if (val11 && val14) + __set_bit(S4, next); + if (val13 && val5) + __set_bit(S6, next); + if (val14 && val5) + __set_bit(S7, next); + break; + case S7: + if (val3) + __set_bit(S0, next); + if (val11 && val13) + __set_bit(S1, next); + if (val11 && val14) + __set_bit(S4, next); + if (val5) + __set_bit(S5, next); + break; + } +} diff --git a/kernel/trace/rv/monitors/sleep/sleep_trace.h b/kernel/trace/rv= /monitors/sleep/sleep_trace.h new file mode 100644 index 000000000000..22eaf31da987 --- /dev/null +++ b/kernel/trace/rv/monitors/sleep/sleep_trace.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Snippet to be included in rv_trace.h + */ + +#ifdef CONFIG_RV_MON_SLEEP +DEFINE_EVENT(event_ltl_monitor_id, event_sleep, + TP_PROTO(struct task_struct *task, char *states, char *atoms, char *= next), + TP_ARGS(task, states, atoms, next)); +DEFINE_EVENT(error_ltl_monitor_id, error_sleep, + TP_PROTO(struct task_struct *task), + TP_ARGS(task)); +#endif /* CONFIG_RV_MON_SLEEP */ diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h index 98eee8ec96e4..b6f310498466 100644 --- a/kernel/trace/rv/rv_trace.h +++ b/kernel/trace/rv/rv_trace.h @@ -173,6 +173,7 @@ DECLARE_EVENT_CLASS(error_ltl_monitor_id, TP_printk("%s[%d]: violation detected", __get_str(comm), __entry->pid) ); #include +#include // Add new monitors based on CONFIG_LTL_MON_EVENTS_ID here #endif /* CONFIG_LTL_MON_EVENTS_ID */ #endif /* _TRACE_RV_H */ diff --git a/tools/verification/models/rtapp/sleep.ltl b/tools/verification= /models/rtapp/sleep.ltl new file mode 100644 index 000000000000..6379bbeb6212 --- /dev/null +++ b/tools/verification/models/rtapp/sleep.ltl @@ -0,0 +1,22 @@ +RULE =3D always ((RT and SLEEP) imply (RT_FRIENDLY_SLEEP or ALLOWLIST)) + +RT_FRIENDLY_SLEEP =3D (RT_VALID_SLEEP_REASON or KERNEL_THREAD) + and ((not WAKE) until RT_FRIENDLY_WAKE) + +RT_VALID_SLEEP_REASON =3D FUTEX_WAIT + or RT_FRIENDLY_NANOSLEEP + +RT_FRIENDLY_NANOSLEEP =3D CLOCK_NANOSLEEP + and NANOSLEEP_TIMER_ABSTIME + and (NANOSLEEP_CLOCK_MONOTONIC or NANOSLEEP_CLOCK_TAI) + +RT_FRIENDLY_WAKE =3D WOKEN_BY_EQUAL_OR_HIGHER_PRIO + or WOKEN_BY_HARDIRQ + or WOKEN_BY_NMI + or ABORT_SLEEP + or KTHREAD_SHOULD_STOP + +ALLOWLIST =3D BLOCK_ON_RT_MUTEX + or FUTEX_LOCK_PI + or TASK_IS_RCU + or TASK_IS_MIGRATION --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 21238307AC8; Fri, 4 Jul 2025 13:20:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; cv=none; b=fOGZcXowsaFj4Itp6Wy2HnuVJPr+vfdizXXX6WuO8Mh6lS+8AkpmZ602XT3MKyuu7UR3Y7lK5XGsYdipcLfWahCYrvanl81j2gitRSJ93oI6u/2wlcXVJ9gM6Mo575acoDIeVIv51Xu6eEjlOoilaEPTnI8Z0aAAtHIEp7rJ1I0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; c=relaxed/simple; bh=7IJgnS3iHCpUZ23jR5nVARpuubCz0owhOmr7hUeLNdw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nlkJlaFcb8rW3jxzdJbIEPjwA187Z7VIKsYKgn6tQmfqaw11znEVGWNXnx6AuY1U4Fn0FHwxPgQ/nmBHFOzhLBnbs1mTngMZQW4bSn+8aogxSTG0QuUK+OYj4hv5VDWYrX4BOYVk9ZAbguv+ZUWqsFTfE6+oaODUArfTk8uClK8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=cjWINE5F; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=PLlfpCcX; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="cjWINE5F"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="PLlfpCcX" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635242; 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=3fH86CFLSZzi92RHkeYob7PW0CNtuplpwRq83WhS9hM=; b=cjWINE5FoXncLXJ8uUgSSchy5Rz9UUX70f5AL847cPSO1mJZejNke1kyL+HjwLaBb1PAyJ EcQZ6POUrfhXF+JzLhKTs+in8T68dTrZJdEU6+3KBDbhIFtduT3kdWKIWkLknqokMl3/jM yrXD/nhnetKQLiLCzI1ErhVIIgDcngcKxMhn/uqykR69W6gU3FpKoS/hwHImcWClbMYRXM ZZ2/qEJJc8zl+u4+iMgHvDAwNrVyoTtjcq68Vp5R49IqT6kgk+I/lKxfctJtAEovf71BxO VgnRWQVodU0soYFgUjRnA7v5AFNEqkCoxpw6UNeMCqjyCcqHK0+P+y2fN2Zi6g== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635242; 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=3fH86CFLSZzi92RHkeYob7PW0CNtuplpwRq83WhS9hM=; b=PLlfpCcXbPE9sQVCNcctqwLpv4QVR98DJrzu5LMZFw9foAAplClmVggiW69lEp+j724fvs m84r2rRxaEKoG3Aw== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 20/21] rv: Add documentation for rtapp monitor Date: Fri, 4 Jul 2025 15:20:12 +0200 Message-Id: <0372483eb8f87fa95bc2d16bf6f7547aed7cd681.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Add documentation describing the rtapp monitor. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- v11: Keep the doc within 80 columns --- Documentation/trace/rv/index.rst | 1 + Documentation/trace/rv/monitor_rtapp.rst | 133 +++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 Documentation/trace/rv/monitor_rtapp.rst diff --git a/Documentation/trace/rv/index.rst b/Documentation/trace/rv/inde= x.rst index 2a27f6bc9429..a2812ac5cfeb 100644 --- a/Documentation/trace/rv/index.rst +++ b/Documentation/trace/rv/index.rst @@ -14,3 +14,4 @@ Runtime Verification monitor_wip.rst monitor_wwnr.rst monitor_sched.rst + monitor_rtapp.rst diff --git a/Documentation/trace/rv/monitor_rtapp.rst b/Documentation/trace= /rv/monitor_rtapp.rst new file mode 100644 index 000000000000..c8104eda924a --- /dev/null +++ b/Documentation/trace/rv/monitor_rtapp.rst @@ -0,0 +1,133 @@ +Real-time application monitors +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D + +- Name: rtapp +- Type: container for multiple monitors +- Author: Nam Cao + +Description +----------- + +Real-time applications may have design flaws such that they experience +unexpected latency and fail to meet their time requirements. Often, these = flaws +follow a few patterns: + + - Page faults: A real-time thread may access memory that does not have a + mapped physical backing or must first be copied (such as for copy-on-w= rite). + Thus a page fault is raised and the kernel must first perform the expe= nsive + action. This causes significant delays to the real-time thread + - Priority inversion: A real-time thread blocks waiting for a lower-prio= rity + thread. This causes the real-time thread to effectively take on the + scheduling priority of the lower-priority thread. For example, the rea= l-time + thread needs to access a shared resource that is protected by a + non-pi-mutex, but the mutex is currently owned by a non-real-time thre= ad. + +The `rtapp` monitor detects these patterns. It aids developers to identify +reasons for unexpected latency with real-time applications. It is a contai= ner of +multiple sub-monitors described in the following sections. + +Monitor pagefault ++++++++++++++++++ + +The `pagefault` monitor reports real-time tasks raising page faults. Its +specification is:: + + RULE =3D always (RT imply not PAGEFAULT) + +To fix warnings reported by this monitor, `mlockall()` or `mlock()` can be= used +to ensure physical backing for memory. + +This monitor may have false negatives because the pages used by the real-t= ime +threads may just happen to be directly available during testing. To minim= ize +this, the system can be put under memory pressure (e.g. invoking the OOM = killer +using a program that does `ptr =3D malloc(SIZE_OF_RAM); memset(ptr, 0, +SIZE_OF_RAM);`) so that the kernel executes aggressive strategies to recyc= le as +much physical memory as possible. + +Monitor sleep ++++++++++++++ + +The `sleep` monitor reports real-time threads sleeping in a manner that may +cause undesirable latency. Real-time applications should only put a real-t= ime +thread to sleep for one of the following reasons: + + - Cyclic work: real-time thread sleeps waiting for the next cycle. For t= his + case, only the `clock_nanosleep` syscall should be used with `TIMER_AB= STIME` + (to avoid time drift) and `CLOCK_MONOTONIC` (to avoid the clock being + changed). No other method is safe for real-time. For example, threads + waiting for timerfd can be woken by softirq which provides no real-time + guarantee. + - Real-time thread waiting for something to happen (e.g. another thread + releasing shared resources, or a completion signal from another thread= ). In + this case, only futexes (FUTEX_LOCK_PI, FUTEX_LOCK_PI2 or one of + FUTEX_WAIT_*) should be used. Applications usually do not use futexes + directly, but use PI mutexes and PI condition variables which are buil= t on + top of futexes. Be aware that the C library might not implement condit= ional + variables as safe for real-time. As an alternative, the librtpi library + exists to provide a conditional variable implementation that is correc= t for + real-time applications in Linux. + +Beside the reason for sleeping, the eventual waker should also be +real-time-safe. Namely, one of: + + - An equal-or-higher-priority thread + - Hard interrupt handler + - Non-maskable interrupt handler + +This monitor's warning usually means one of the following: + + - Real-time thread is blocked by a non-real-time thread (e.g. due to + contention on a mutex without priority inheritance). This is priority + inversion. + - Time-critical work waits for something which is not safe for real-time= (e.g. + timerfd). + - The work executed by the real-time thread does not need to run at real= -time + priority at all. This is not a problem for the real-time thread itsel= f, but + it is potentially taking the CPU away from other important real-time w= ork. + +Application developers may purposely choose to have their real-time applic= ation +sleep in a way that is not safe for real-time. It is debatable whether tha= t is a +problem. Application developers must analyze the warnings to make a proper +assessment. + +The monitor's specification is:: + + RULE =3D always ((RT and SLEEP) imply (RT_FRIENDLY_SLEEP or ALLOWLIST)) + + RT_FRIENDLY_SLEEP =3D (RT_VALID_SLEEP_REASON or KERNEL_THREAD) + and ((not WAKE) until RT_FRIENDLY_WAKE) + + RT_VALID_SLEEP_REASON =3D FUTEX_WAIT + or RT_FRIENDLY_NANOSLEEP + + RT_FRIENDLY_NANOSLEEP =3D CLOCK_NANOSLEEP + and NANOSLEEP_TIMER_ABSTIME + and NANOSLEEP_CLOCK_MONOTONIC + + RT_FRIENDLY_WAKE =3D WOKEN_BY_EQUAL_OR_HIGHER_PRIO + or WOKEN_BY_HARDIRQ + or WOKEN_BY_NMI + or KTHREAD_SHOULD_STOP + + ALLOWLIST =3D BLOCK_ON_RT_MUTEX + or FUTEX_LOCK_PI + or TASK_IS_RCU + or TASK_IS_MIGRATION + +Beside the scenarios described above, this specification also handle some +special cases: + + - `KERNEL_THREAD`: kernel tasks do not have any pattern that can be reco= gnized + as valid real-time sleeping reasons. Therefore sleeping reason is not + checked for kernel tasks. + - `KTHREAD_SHOULD_STOP`: a non-real-time thread may stop a real-time ker= nel + thread by waking it and waiting for it to exit (`kthread_stop()`). This + wakeup is safe for real-time. + - `ALLOWLIST`: to handle known false positives with the kernel. + - `BLOCK_ON_RT_MUTEX` is included in the allowlist due to its implementa= tion. + In the release path of rt_mutex, a boosted task is de-boosted before w= aking + the rt_mutex's waiter. Consequently, the monitor may see a real-time-u= nsafe + wakeup (e.g. non-real-time task waking real-time task). This is actual= ly + real-time-safe because preemption is disabled for the duration. + - `FUTEX_LOCK_PI` is included in the allowlist for the same reason as + `BLOCK_ON_RT_MUTEX`. --=20 2.39.5 From nobody Tue Oct 7 22:50:50 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 73C33307499; Fri, 4 Jul 2025 13:20:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; cv=none; b=b6UMkpy2871/iUqg+hm6b1Ip9zW+N57q//K/7fsFRhTP09fhv0TsKL8ves0KNs9TYvWvvkfBefgoVHkxszyMt4D2T9nIig+Xv/RX7asWdViyQQaPVsBEOs0HANKM/zvNy4FPHdq+xvlGrNpa+zLZiy3lowMy4tMrmlrLBDf/ChA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751635246; c=relaxed/simple; bh=Wgc5TeCxTSHrIluk/Zchk1qeFdkcI5CAnbfWjST87wc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gvMNqBvTwWas5n7ayaNGbQ5EC3W5dU1qFftezqVkINJzv0ldZO4R4IZtu81wtDbjhImGCLbFgaegttkCyUXNe0ewk3ZRpJfWNOPi8HpoSOQEOB56hYL3ARaywolKnWh1yNJoa4A/7t95jOeZHjQOxog31XZ7ztLA/ryHLkYI7X0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=rwCJfx4n; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=XsKsIzc3; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="rwCJfx4n"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="XsKsIzc3" From: Nam Cao DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1751635242; 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=bJJiizdaOD7bLY57+4l2vOqWNZK0dHtbValv5ybO8Ck=; b=rwCJfx4naiTCCeuygYh0af93n22CLHYeXz3aH+bojC808TvwUTuyDoG6ToKVoj7qKAaY1V E4fgk2LCbmy37Iz71TRUuApX8JFve6SaC4wK7q22gpTlEZRv2rMzlZJWu4wVl+tKUk3PVq BgAkfDn4yYnmpBU3mikSMxCdAoL17f4utfUMX+4B9cd/k6JxSiDe6JlpBrB3GzCDWIBMnU PPWkjBxuuG4cTXOqcAj6NSiWoMebfTs2jhSXrd7XOUEpmacV403+TIXxMFS9yVu2U37qJ7 oYT3jCmdyRSPrhZlOsQ+j4y96ZDZpgXkjulnyLaVRyFqLSntPPvJVuazhHiyMA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1751635242; 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=bJJiizdaOD7bLY57+4l2vOqWNZK0dHtbValv5ybO8Ck=; b=XsKsIzc3n6WMWu7hvW5/iKZT/m8eccA3sO02NcRumIlsSjoynPjdFGX+t8yXB3Wi2sW4hi WojwZZFtCtLDhQCA== To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Gabriele Monaco , john.ogness@linutronix.de, Nam Cao Subject: [PATCH v11 21/21] rv: Allow to configure the number of per-task monitor Date: Fri, 4 Jul 2025 15:20:13 +0200 Message-Id: <1a380c29592fe559667775fd47a4f35d42f4f769.1751634289.git.namcao@linutronix.de> In-Reply-To: References: 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 Content-Type: text/plain; charset="utf-8" Now that there are 2 monitors for real-time applications, users may want to enable both of them simultaneously. Make the number of per-task monitor configurable. Default it to 2 for now. Reviewed-by: Gabriele Monaco Signed-off-by: Nam Cao --- include/linux/rv.h | 9 +-------- include/linux/sched.h | 8 +++----- kernel/trace/rv/Kconfig | 9 +++++++++ kernel/trace/rv/monitors/rtapp/Kconfig | 1 + kernel/trace/rv/rv.c | 8 ++++---- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/linux/rv.h b/include/linux/rv.h index 1d5579f9b75a..97baf58d88b2 100644 --- a/include/linux/rv.h +++ b/include/linux/rv.h @@ -75,14 +75,7 @@ struct ltl_monitor {}; =20 #endif /* CONFIG_RV_LTL_MONITOR */ =20 -/* - * Per-task RV monitors count. Nowadays fixed in RV_PER_TASK_MONITORS. - * If we find justification for more monitors, we can think about - * adding more or developing a dynamic method. So far, none of - * these are justified. - */ -#define RV_PER_TASK_MONITORS 1 -#define RV_PER_TASK_MONITOR_INIT (RV_PER_TASK_MONITORS) +#define RV_PER_TASK_MONITOR_INIT (CONFIG_RV_PER_TASK_MONITORS) =20 union rv_task_monitor { struct da_monitor da_mon; diff --git a/include/linux/sched.h b/include/linux/sched.h index 4f78a64beb52..fabd7fe1a07a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1642,12 +1642,10 @@ struct task_struct { =20 #ifdef CONFIG_RV /* - * Per-task RV monitor. Nowadays fixed in RV_PER_TASK_MONITORS. - * If we find justification for more monitors, we can think - * about adding more or developing a dynamic method. So far, - * none of these are justified. + * Per-task RV monitor, fixed in CONFIG_RV_PER_TASK_MONITORS. + * If memory becomes a concern, we can think about a dynamic method. */ - union rv_task_monitor rv[RV_PER_TASK_MONITORS]; + union rv_task_monitor rv[CONFIG_RV_PER_TASK_MONITORS]; #endif =20 #ifdef CONFIG_USER_EVENTS diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index 942d57575e67..c11bf7e61ebf 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -32,6 +32,15 @@ menuconfig RV For further information, see: Documentation/trace/rv/runtime-verification.rst =20 +config RV_PER_TASK_MONITORS + int "Maximum number of per-task monitor" + depends on RV + range 1 8 + default 2 + help + This option configures the maximum number of per-task RV monitors that = can run + simultaneously. + source "kernel/trace/rv/monitors/wip/Kconfig" source "kernel/trace/rv/monitors/wwnr/Kconfig" source "kernel/trace/rv/monitors/sched/Kconfig" diff --git a/kernel/trace/rv/monitors/rtapp/Kconfig b/kernel/trace/rv/monit= ors/rtapp/Kconfig index b7415c3570bb..1ce9370a9ba8 100644 --- a/kernel/trace/rv/monitors/rtapp/Kconfig +++ b/kernel/trace/rv/monitors/rtapp/Kconfig @@ -1,5 +1,6 @@ config RV_MON_RTAPP depends on RV + depends on RV_PER_TASK_MONITORS >=3D 2 bool "rtapp monitor" help Collection of monitors to check for common problems with real-time diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c index e25d65fe432a..108429d16ec1 100644 --- a/kernel/trace/rv/rv.c +++ b/kernel/trace/rv/rv.c @@ -165,7 +165,7 @@ struct dentry *get_monitors_root(void) LIST_HEAD(rv_monitors_list); =20 static int task_monitor_count; -static bool task_monitor_slots[RV_PER_TASK_MONITORS]; +static bool task_monitor_slots[CONFIG_RV_PER_TASK_MONITORS]; =20 int rv_get_task_monitor_slot(void) { @@ -173,12 +173,12 @@ int rv_get_task_monitor_slot(void) =20 lockdep_assert_held(&rv_interface_lock); =20 - if (task_monitor_count =3D=3D RV_PER_TASK_MONITORS) + if (task_monitor_count =3D=3D CONFIG_RV_PER_TASK_MONITORS) return -EBUSY; =20 task_monitor_count++; =20 - for (i =3D 0; i < RV_PER_TASK_MONITORS; i++) { + for (i =3D 0; i < CONFIG_RV_PER_TASK_MONITORS; i++) { if (task_monitor_slots[i] =3D=3D false) { task_monitor_slots[i] =3D true; return i; @@ -194,7 +194,7 @@ void rv_put_task_monitor_slot(int slot) { lockdep_assert_held(&rv_interface_lock); =20 - if (slot < 0 || slot >=3D RV_PER_TASK_MONITORS) { + if (slot < 0 || slot >=3D CONFIG_RV_PER_TASK_MONITORS) { WARN_ONCE(1, "RV releasing an invalid slot!: %d\n", slot); return; } --=20 2.39.5