summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorGabriele Monaco <gmonaco@redhat.com>2026-06-01 18:38:34 +0300
committerGabriele Monaco <gmonaco@redhat.com>2026-06-03 13:33:24 +0300
commit700782ec8f6589c5792b323efd6e004dd183328b (patch)
tree4990aef64666b82a230056f6ff8f220dc2c44008 /include
parent713c9e1ea7623846f8e0bb657f1b9d211d1a61e6 (diff)
downloadlinux-700782ec8f6589c5792b323efd6e004dd183328b.tar.xz
rv: Add automatic cleanup handlers for per-task HA monitors
Hybrid automata monitors may start timers, depending on the model, these may remain active on an exiting task and cause false positives or even access freed memory. Add an enable/disable hook in the HA code, currently only populated by the per-task handler for registration and deregistration. This hooks to the sched_process_exit event and ensures the timer is stopped for every exiting task. The handler is enabled automatically but may be disabled, for instance if the monitor uses the event for another purpose (but should still manually ensure timers are stopped). Fixes: f5587d1b6ec9 ("rv: Add Hybrid Automata monitor type") Reviewed-by: Nam Cao <namcao@linutronix.de> Link: https://lore.kernel.org/r/20260601153840.124372-8-gmonaco@redhat.com Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
Diffstat (limited to 'include')
-rw-r--r--include/rv/ha_monitor.h60
1 files changed, 60 insertions, 0 deletions
diff --git a/include/rv/ha_monitor.h b/include/rv/ha_monitor.h
index bd87055567cc..4002b5247c46 100644
--- a/include/rv/ha_monitor.h
+++ b/include/rv/ha_monitor.h
@@ -28,6 +28,7 @@ static inline void ha_monitor_init_env(struct da_monitor *da_mon);
static inline void ha_monitor_reset_env(struct da_monitor *da_mon);
static inline void ha_setup_timer(struct ha_monitor *ha_mon);
static inline bool ha_cancel_timer(struct ha_monitor *ha_mon);
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon);
static bool ha_monitor_handle_constraint(struct da_monitor *da_mon,
enum states curr_state,
enum events event,
@@ -37,6 +38,26 @@ static bool ha_monitor_handle_constraint(struct da_monitor *da_mon,
#define da_monitor_init_hook ha_monitor_init_env
#define da_monitor_reset_hook ha_monitor_reset_env
+#if !defined(HA_SKIP_AUTO_CLEANUP) && RV_MON_TYPE == RV_MON_PER_TASK
+/*
+ * Automatic cleanup handlers for per-task HA monitors, only skip if you know
+ * what you are doing (e.g. you want to implement cleanup manually in another
+ * handler doing more things).
+ */
+static void ha_handle_sched_process_exit(void *data, struct task_struct *p,
+ bool group_dead);
+
+#define ha_monitor_enable_hook() \
+ rv_attach_trace_probe(__stringify(MONITOR_NAME), sched_process_exit, \
+ ha_handle_sched_process_exit)
+#define ha_monitor_disable_hook() \
+ rv_detach_trace_probe(__stringify(MONITOR_NAME), sched_process_exit, \
+ ha_handle_sched_process_exit)
+#else
+#define ha_monitor_enable_hook() ((void)0)
+#define ha_monitor_disable_hook() ((void)0)
+#endif
+
#include <rv/da_monitor.h>
#include <linux/seq_buf.h>
@@ -115,6 +136,22 @@ static enum hrtimer_restart ha_monitor_timer_callback(struct hrtimer *hrtimer);
#define ha_get_ns() 0
#endif /* HA_CLK_NS */
+static int ha_monitor_init(void)
+{
+ int ret;
+
+ ret = da_monitor_init();
+ if (ret == 0)
+ ha_monitor_enable_hook();
+ return ret;
+}
+
+static void ha_monitor_destroy(void)
+{
+ ha_monitor_disable_hook();
+ da_monitor_destroy();
+}
+
/* Should be supplied by the monitor */
static u64 ha_get_env(struct ha_monitor *ha_mon, enum envs env, u64 time_ns);
static bool ha_verify_constraint(struct ha_monitor *ha_mon,
@@ -200,6 +237,20 @@ static inline void ha_trace_error_env(struct ha_monitor *ha_mon,
{
CONCATENATE(trace_error_env_, MONITOR_NAME)(id, curr_state, event, env);
}
+
+#if !defined(HA_SKIP_AUTO_CLEANUP) && RV_MON_TYPE == RV_MON_PER_TASK
+static void ha_handle_sched_process_exit(void *data, struct task_struct *p,
+ bool group_dead)
+{
+ struct da_monitor *da_mon = da_get_monitor(p);
+
+ if (likely(da_monitoring(da_mon))) {
+ da_monitor_reset(da_mon);
+ ha_cancel_timer_sync(to_ha_monitor(da_mon));
+ }
+}
+#endif
+
#endif /* RV_MON_TYPE */
/*
@@ -412,6 +463,10 @@ static inline bool ha_cancel_timer(struct ha_monitor *ha_mon)
{
return timer_delete(&ha_mon->timer);
}
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon)
+{
+ timer_delete_sync(&ha_mon->timer);
+}
#elif HA_TIMER_TYPE == HA_TIMER_HRTIMER
/*
* Helper functions to handle the monitor timer.
@@ -463,6 +518,10 @@ static inline bool ha_cancel_timer(struct ha_monitor *ha_mon)
{
return hrtimer_try_to_cancel(&ha_mon->hrtimer) == 1;
}
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon)
+{
+ hrtimer_cancel(&ha_mon->hrtimer);
+}
#else /* HA_TIMER_NONE */
/*
* Start function is intentionally not defined, monitors using timers must
@@ -473,6 +532,7 @@ static inline bool ha_cancel_timer(struct ha_monitor *ha_mon)
{
return false;
}
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon) { }
#endif
#endif