Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org>
4 *
5 * Deterministic automata (DA) monitor functions, to be used together
6 * with automata models in C generated by the dot2k tool.
7 *
8 * The dot2k tool is available at tools/verification/dot2k/
9 *
10 * For further information, see:
11 * Documentation/trace/rv/monitor_synthesis.rst
12 */
13
14#ifndef _RV_DA_MONITOR_H
15#define _RV_DA_MONITOR_H
16
17#include <rv/automata.h>
18#include <linux/rv.h>
19#include <linux/stringify.h>
20#include <linux/bug.h>
21#include <linux/sched.h>
22
23/*
24 * Per-cpu variables require a unique name although static in some
25 * configurations (e.g. CONFIG_DEBUG_FORCE_WEAK_PER_CPU or alpha modules).
26 */
27#define DA_MON_NAME CONCATENATE(da_mon_, MONITOR_NAME)
28
29static struct rv_monitor rv_this;
30
31static void react(enum states curr_state, enum events event)
32{
33 rv_react(&rv_this,
34 "rv: monitor %s does not allow event %s on state %s\n",
35 __stringify(MONITOR_NAME),
36 model_get_event_name(event),
37 model_get_state_name(curr_state));
38}
39
40/*
41 * da_monitor_reset - reset a monitor and setting it to init state
42 */
43static inline void da_monitor_reset(struct da_monitor *da_mon)
44{
45 da_mon->monitoring = 0;
46 da_mon->curr_state = model_get_initial_state();
47}
48
49/*
50 * da_monitor_start - start monitoring
51 *
52 * The monitor will ignore all events until monitoring is set to true. This
53 * function needs to be called to tell the monitor to start monitoring.
54 */
55static inline void da_monitor_start(struct da_monitor *da_mon)
56{
57 da_mon->curr_state = model_get_initial_state();
58 da_mon->monitoring = 1;
59}
60
61/*
62 * da_monitoring - returns true if the monitor is processing events
63 */
64static inline bool da_monitoring(struct da_monitor *da_mon)
65{
66 return da_mon->monitoring;
67}
68
69/*
70 * da_monitor_enabled - checks if the monitor is enabled
71 */
72static inline bool da_monitor_enabled(void)
73{
74 /* global switch */
75 if (unlikely(!rv_monitoring_on()))
76 return 0;
77
78 /* monitor enabled */
79 if (unlikely(!rv_this.enabled))
80 return 0;
81
82 return 1;
83}
84
85/*
86 * da_monitor_handling_event - checks if the monitor is ready to handle events
87 */
88static inline bool da_monitor_handling_event(struct da_monitor *da_mon)
89{
90 if (!da_monitor_enabled())
91 return 0;
92
93 /* monitor is actually monitoring */
94 if (unlikely(!da_monitoring(da_mon)))
95 return 0;
96
97 return 1;
98}
99
100#if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
101/*
102 * Event handler for implicit monitors. Implicit monitor is the one which the
103 * handler does not need to specify which da_monitor to manipulate. Examples
104 * of implicit monitor are the per_cpu or the global ones.
105 *
106 * Retry in case there is a race between getting and setting the next state,
107 * warn and reset the monitor if it runs out of retries. The monitor should be
108 * able to handle various orders.
109 */
110
111static inline bool da_event(struct da_monitor *da_mon, enum events event)
112{
113 enum states curr_state, next_state;
114
115 curr_state = READ_ONCE(da_mon->curr_state);
116 for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
117 next_state = model_get_next_state(curr_state, event);
118 if (next_state == INVALID_STATE) {
119 react(curr_state, event);
120 CONCATENATE(trace_error_, MONITOR_NAME)(
121 model_get_state_name(curr_state),
122 model_get_event_name(event));
123 return false;
124 }
125 if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
126 CONCATENATE(trace_event_, MONITOR_NAME)(
127 model_get_state_name(curr_state),
128 model_get_event_name(event),
129 model_get_state_name(next_state),
130 model_is_final_state(next_state));
131 return true;
132 }
133 }
134
135 trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
136 pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
137 " retries reached for event %s, resetting monitor %s",
138 model_get_event_name(event), __stringify(MONITOR_NAME));
139 return false;
140}
141
142#elif RV_MON_TYPE == RV_MON_PER_TASK
143/*
144 * Event handler for per_task monitors.
145 *
146 * Retry in case there is a race between getting and setting the next state,
147 * warn and reset the monitor if it runs out of retries. The monitor should be
148 * able to handle various orders.
149 */
150
151static inline bool da_event(struct da_monitor *da_mon, struct task_struct *tsk,
152 enum events event)
153{
154 enum states curr_state, next_state;
155
156 curr_state = READ_ONCE(da_mon->curr_state);
157 for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
158 next_state = model_get_next_state(curr_state, event);
159 if (next_state == INVALID_STATE) {
160 react(curr_state, event);
161 CONCATENATE(trace_error_, MONITOR_NAME)(tsk->pid,
162 model_get_state_name(curr_state),
163 model_get_event_name(event));
164 return false;
165 }
166 if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
167 CONCATENATE(trace_event_, MONITOR_NAME)(tsk->pid,
168 model_get_state_name(curr_state),
169 model_get_event_name(event),
170 model_get_state_name(next_state),
171 model_is_final_state(next_state));
172 return true;
173 }
174 }
175
176 trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
177 pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
178 " retries reached for event %s, resetting monitor %s",
179 model_get_event_name(event), __stringify(MONITOR_NAME));
180 return false;
181}
182#endif /* RV_MON_TYPE */
183
184#if RV_MON_TYPE == RV_MON_GLOBAL
185/*
186 * Functions to define, init and get a global monitor.
187 */
188
189/*
190 * global monitor (a single variable)
191 */
192static struct da_monitor DA_MON_NAME;
193
194/*
195 * da_get_monitor - return the global monitor address
196 */
197static struct da_monitor *da_get_monitor(void)
198{
199 return &DA_MON_NAME;
200}
201
202/*
203 * da_monitor_reset_all - reset the single monitor
204 */
205static void da_monitor_reset_all(void)
206{
207 da_monitor_reset(da_get_monitor());
208}
209
210/*
211 * da_monitor_init - initialize a monitor
212 */
213static inline int da_monitor_init(void)
214{
215 da_monitor_reset_all();
216 return 0;
217}
218
219/*
220 * da_monitor_destroy - destroy the monitor
221 */
222static inline void da_monitor_destroy(void) { }
223
224#elif RV_MON_TYPE == RV_MON_PER_CPU
225/*
226 * Functions to define, init and get a per-cpu monitor.
227 */
228
229/*
230 * per-cpu monitor variables
231 */
232static DEFINE_PER_CPU(struct da_monitor, DA_MON_NAME);
233
234/*
235 * da_get_monitor - return current CPU monitor address
236 */
237static struct da_monitor *da_get_monitor(void)
238{
239 return this_cpu_ptr(&DA_MON_NAME);
240}
241
242/*
243 * da_monitor_reset_all - reset all CPUs' monitor
244 */
245static void da_monitor_reset_all(void)
246{
247 struct da_monitor *da_mon;
248 int cpu;
249
250 for_each_cpu(cpu, cpu_online_mask) {
251 da_mon = per_cpu_ptr(&DA_MON_NAME, cpu);
252 da_monitor_reset(da_mon);
253 }
254}
255
256/*
257 * da_monitor_init - initialize all CPUs' monitor
258 */
259static inline int da_monitor_init(void)
260{
261 da_monitor_reset_all();
262 return 0;
263}
264
265/*
266 * da_monitor_destroy - destroy the monitor
267 */
268static inline void da_monitor_destroy(void) { }
269
270#elif RV_MON_TYPE == RV_MON_PER_TASK
271/*
272 * Functions to define, init and get a per-task monitor.
273 */
274
275/*
276 * The per-task monitor is stored a vector in the task struct. This variable
277 * stores the position on the vector reserved for this monitor.
278 */
279static int task_mon_slot = RV_PER_TASK_MONITOR_INIT;
280
281/*
282 * da_get_monitor - return the monitor in the allocated slot for tsk
283 */
284static inline struct da_monitor *da_get_monitor(struct task_struct *tsk)
285{
286 return &tsk->rv[task_mon_slot].da_mon;
287}
288
289static void da_monitor_reset_all(void)
290{
291 struct task_struct *g, *p;
292 int cpu;
293
294 read_lock(&tasklist_lock);
295 for_each_process_thread(g, p)
296 da_monitor_reset(da_get_monitor(p));
297 for_each_present_cpu(cpu)
298 da_monitor_reset(da_get_monitor(idle_task(cpu)));
299 read_unlock(&tasklist_lock);
300}
301
302/*
303 * da_monitor_init - initialize the per-task monitor
304 *
305 * Try to allocate a slot in the task's vector of monitors. If there
306 * is an available slot, use it and reset all task's monitor.
307 */
308static int da_monitor_init(void)
309{
310 int slot;
311
312 slot = rv_get_task_monitor_slot();
313 if (slot < 0 || slot >= RV_PER_TASK_MONITOR_INIT)
314 return slot;
315
316 task_mon_slot = slot;
317
318 da_monitor_reset_all();
319 return 0;
320}
321
322/*
323 * da_monitor_destroy - return the allocated slot
324 */
325static inline void da_monitor_destroy(void)
326{
327 if (task_mon_slot == RV_PER_TASK_MONITOR_INIT) {
328 WARN_ONCE(1, "Disabling a disabled monitor: " __stringify(MONITOR_NAME));
329 return;
330 }
331 rv_put_task_monitor_slot(task_mon_slot);
332 task_mon_slot = RV_PER_TASK_MONITOR_INIT;
333}
334#endif /* RV_MON_TYPE */
335
336#if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
337/*
338 * Handle event for implicit monitor: da_get_monitor() will figure out
339 * the monitor.
340 */
341
342static inline void __da_handle_event(struct da_monitor *da_mon,
343 enum events event)
344{
345 bool retval;
346
347 retval = da_event(da_mon, event);
348 if (!retval)
349 da_monitor_reset(da_mon);
350}
351
352/*
353 * da_handle_event - handle an event
354 */
355static inline void da_handle_event(enum events event)
356{
357 struct da_monitor *da_mon = da_get_monitor();
358 bool retval;
359
360 retval = da_monitor_handling_event(da_mon);
361 if (!retval)
362 return;
363
364 __da_handle_event(da_mon, event);
365}
366
367/*
368 * da_handle_start_event - start monitoring or handle event
369 *
370 * This function is used to notify the monitor that the system is returning
371 * to the initial state, so the monitor can start monitoring in the next event.
372 * Thus:
373 *
374 * If the monitor already started, handle the event.
375 * If the monitor did not start yet, start the monitor but skip the event.
376 */
377static inline bool da_handle_start_event(enum events event)
378{
379 struct da_monitor *da_mon;
380
381 if (!da_monitor_enabled())
382 return 0;
383
384 da_mon = da_get_monitor();
385
386 if (unlikely(!da_monitoring(da_mon))) {
387 da_monitor_start(da_mon);
388 return 0;
389 }
390
391 __da_handle_event(da_mon, event);
392
393 return 1;
394}
395
396/*
397 * da_handle_start_run_event - start monitoring and handle event
398 *
399 * This function is used to notify the monitor that the system is in the
400 * initial state, so the monitor can start monitoring and handling event.
401 */
402static inline bool da_handle_start_run_event(enum events event)
403{
404 struct da_monitor *da_mon;
405
406 if (!da_monitor_enabled())
407 return 0;
408
409 da_mon = da_get_monitor();
410
411 if (unlikely(!da_monitoring(da_mon)))
412 da_monitor_start(da_mon);
413
414 __da_handle_event(da_mon, event);
415
416 return 1;
417}
418
419#elif RV_MON_TYPE == RV_MON_PER_TASK
420/*
421 * Handle event for per task.
422 */
423
424static inline void __da_handle_event(struct da_monitor *da_mon,
425 struct task_struct *tsk, enum events event)
426{
427 bool retval;
428
429 retval = da_event(da_mon, tsk, event);
430 if (!retval)
431 da_monitor_reset(da_mon);
432}
433
434/*
435 * da_handle_event - handle an event
436 */
437static inline void da_handle_event(struct task_struct *tsk, enum events event)
438{
439 struct da_monitor *da_mon = da_get_monitor(tsk);
440 bool retval;
441
442 retval = da_monitor_handling_event(da_mon);
443 if (!retval)
444 return;
445
446 __da_handle_event(da_mon, tsk, event);
447}
448
449/*
450 * da_handle_start_event - start monitoring or handle event
451 *
452 * This function is used to notify the monitor that the system is returning
453 * to the initial state, so the monitor can start monitoring in the next event.
454 * Thus:
455 *
456 * If the monitor already started, handle the event.
457 * If the monitor did not start yet, start the monitor but skip the event.
458 */
459static inline bool da_handle_start_event(struct task_struct *tsk,
460 enum events event)
461{
462 struct da_monitor *da_mon;
463
464 if (!da_monitor_enabled())
465 return 0;
466
467 da_mon = da_get_monitor(tsk);
468
469 if (unlikely(!da_monitoring(da_mon))) {
470 da_monitor_start(da_mon);
471 return 0;
472 }
473
474 __da_handle_event(da_mon, tsk, event);
475
476 return 1;
477}
478
479/*
480 * da_handle_start_run_event - start monitoring and handle event
481 *
482 * This function is used to notify the monitor that the system is in the
483 * initial state, so the monitor can start monitoring and handling event.
484 */
485static inline bool da_handle_start_run_event(struct task_struct *tsk,
486 enum events event)
487{
488 struct da_monitor *da_mon;
489
490 if (!da_monitor_enabled())
491 return 0;
492
493 da_mon = da_get_monitor(tsk);
494
495 if (unlikely(!da_monitoring(da_mon)))
496 da_monitor_start(da_mon);
497
498 __da_handle_event(da_mon, tsk, event);
499
500 return 1;
501}
502#endif /* RV_MON_TYPE */
503
504#endif