File Index
Files and directories
Sign in
FILE

rv_reactors.c

File preview with syntax highlighting.

linux-6.19.14/kernel/trace/rv/rv_reactors.c C
  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 * Runtime reactor interface.
  6 *
  7 * A runtime monitor can cause a reaction to the detection of an
  8 * exception on the model's execution. By default, the monitors have
  9 * tracing reactions, printing the monitor output via tracepoints.
 10 * But other reactions can be added (on-demand) via this interface.
 11 *
 12 * == Registering reactors ==
 13 *
 14 * The struct rv_reactor defines a callback function to be executed
 15 * in case of a model exception happens. The callback function
 16 * receives a message to be (optionally) printed before executing
 17 * the reaction.
 18 *
 19 * A RV reactor is registered via:
 20 *   int rv_register_reactor(struct rv_reactor *reactor)
 21 * And unregistered via:
 22 *   int rv_unregister_reactor(struct rv_reactor *reactor)
 23 *
 24 * These functions are exported to modules, enabling reactors to be
 25 * dynamically loaded.
 26 *
 27 * == User interface ==
 28 *
 29 * The user interface resembles the kernel tracing interface and
 30 * presents these files:
 31 *
 32 *  "available_reactors"
 33 *    - List the available reactors, one per line.
 34 *
 35 *    For example:
 36 *      # cat available_reactors
 37 *      nop
 38 *      panic
 39 *      printk
 40 *
 41 *  "reacting_on"
 42 *    - It is an on/off general switch for reactors, disabling
 43 *    all reactions.
 44 *
 45 *  "monitors/MONITOR/reactors"
 46 *    - List available reactors, with the select reaction for the given
 47 *    MONITOR inside []. The default one is the nop (no operation)
 48 *    reactor.
 49 *    - Writing the name of an reactor enables it to the given
 50 *    MONITOR.
 51 *
 52 *    For example:
 53 *      # cat monitors/wip/reactors
 54 *      [nop]
 55 *      panic
 56 *      printk
 57 *      # echo panic > monitors/wip/reactors
 58 *      # cat monitors/wip/reactors
 59 *      nop
 60 *      [panic]
 61 *      printk
 62 */
 63
 64#include <linux/lockdep.h>
 65#include <linux/slab.h>
 66
 67#include "rv.h"
 68
 69/*
 70 * Interface for the reactor register.
 71 */
 72static LIST_HEAD(rv_reactors_list);
 73
 74static struct rv_reactor *get_reactor_rdef_by_name(char *name)
 75{
 76	struct rv_reactor *r;
 77
 78	list_for_each_entry(r, &rv_reactors_list, list) {
 79		if (strcmp(name, r->name) == 0)
 80			return r;
 81	}
 82	return NULL;
 83}
 84
 85/*
 86 * Available reactors seq functions.
 87 */
 88static int reactors_show(struct seq_file *m, void *p)
 89{
 90	struct rv_reactor *reactor = container_of(p, struct rv_reactor, list);
 91
 92	seq_printf(m, "%s\n", reactor->name);
 93	return 0;
 94}
 95
 96static void reactors_stop(struct seq_file *m, void *p)
 97{
 98	mutex_unlock(&rv_interface_lock);
 99}
100
101static void *reactors_start(struct seq_file *m, loff_t *pos)
102{
103	mutex_lock(&rv_interface_lock);
104	return seq_list_start(&rv_reactors_list, *pos);
105}
106
107static void *reactors_next(struct seq_file *m, void *p, loff_t *pos)
108{
109	return seq_list_next(p, &rv_reactors_list, pos);
110}
111
112/*
113 * available_reactors seq definition.
114 */
115static const struct seq_operations available_reactors_seq_ops = {
116	.start	= reactors_start,
117	.next	= reactors_next,
118	.stop	= reactors_stop,
119	.show	= reactors_show
120};
121
122/*
123 * available_reactors interface.
124 */
125static int available_reactors_open(struct inode *inode, struct file *file)
126{
127	return seq_open(file, &available_reactors_seq_ops);
128};
129
130static const struct file_operations available_reactors_ops = {
131	.open    = available_reactors_open,
132	.read    = seq_read,
133	.llseek  = seq_lseek,
134	.release = seq_release
135};
136
137/*
138 * Monitor's reactor file.
139 */
140static int monitor_reactor_show(struct seq_file *m, void *p)
141{
142	struct rv_monitor *mon = m->private;
143	struct rv_reactor *reactor = container_of(p, struct rv_reactor, list);
144
145	if (mon->reactor == reactor)
146		seq_printf(m, "[%s]\n", reactor->name);
147	else
148		seq_printf(m, "%s\n", reactor->name);
149	return 0;
150}
151
152/*
153 * available_reactors seq definition.
154 */
155static const struct seq_operations monitor_reactors_seq_ops = {
156	.start	= reactors_start,
157	.next	= reactors_next,
158	.stop	= reactors_stop,
159	.show	= monitor_reactor_show
160};
161
162static void monitor_swap_reactors_single(struct rv_monitor *mon,
163					 struct rv_reactor *reactor,
164					 bool nested)
165{
166	bool monitor_enabled;
167
168	/* nothing to do */
169	if (mon->reactor == reactor)
170		return;
171
172	monitor_enabled = mon->enabled;
173	if (monitor_enabled)
174		rv_disable_monitor(mon);
175
176	mon->reactor = reactor;
177	mon->react = reactor->react;
178
179	/* enable only once if iterating through a container */
180	if (monitor_enabled && !nested)
181		rv_enable_monitor(mon);
182}
183
184static void monitor_swap_reactors(struct rv_monitor *mon, struct rv_reactor *reactor)
185{
186	struct rv_monitor *p = mon;
187
188	if (rv_is_container_monitor(mon))
189		list_for_each_entry_continue(p, &rv_monitors_list, list) {
190			if (p->parent != mon)
191				break;
192			monitor_swap_reactors_single(p, reactor, true);
193		}
194	/*
195	 * This call enables and disables the monitor if they were active.
196	 * In case of a container, we already disabled all and will enable all.
197	 * All nested monitors are enabled also if they were off, we may refine
198	 * this logic in the future.
199	 */
200	monitor_swap_reactors_single(mon, reactor, false);
201}
202
203static ssize_t
204monitor_reactors_write(struct file *file, const char __user *user_buf,
205		      size_t count, loff_t *ppos)
206{
207	char buff[MAX_RV_REACTOR_NAME_SIZE + 2];
208	struct rv_monitor *mon;
209	struct rv_reactor *reactor;
210	struct seq_file *seq_f;
211	int retval = -EINVAL;
212	char *ptr;
213	int len;
214
215	if (count < 1 || count > MAX_RV_REACTOR_NAME_SIZE + 1)
216		return -EINVAL;
217
218	memset(buff, 0, sizeof(buff));
219
220	retval = simple_write_to_buffer(buff, sizeof(buff) - 1, ppos, user_buf, count);
221	if (retval < 0)
222		return -EFAULT;
223
224	ptr = strim(buff);
225
226	len = strlen(ptr);
227	if (!len)
228		return count;
229
230	/*
231	 * See monitor_reactors_open()
232	 */
233	seq_f = file->private_data;
234	mon = seq_f->private;
235
236	guard(mutex)(&rv_interface_lock);
237
238	list_for_each_entry(reactor, &rv_reactors_list, list) {
239		if (strcmp(ptr, reactor->name) != 0)
240			continue;
241
242		monitor_swap_reactors(mon, reactor);
243
244		return count;
245	}
246
247	return -EINVAL;
248}
249
250/*
251 * available_reactors interface.
252 */
253static int monitor_reactors_open(struct inode *inode, struct file *file)
254{
255	struct rv_monitor *mon = inode->i_private;
256	struct seq_file *seq_f;
257	int ret;
258
259	ret = seq_open(file, &monitor_reactors_seq_ops);
260	if (ret < 0)
261		return ret;
262
263	/*
264	 * seq_open stores the seq_file on the file->private data.
265	 */
266	seq_f = file->private_data;
267
268	/*
269	 * Copy the create file "private" data to the seq_file private data.
270	 */
271	seq_f->private = mon;
272
273	return 0;
274};
275
276static const struct file_operations monitor_reactors_ops = {
277	.open    = monitor_reactors_open,
278	.read    = seq_read,
279	.llseek  = seq_lseek,
280	.release = seq_release,
281	.write = monitor_reactors_write
282};
283
284static int __rv_register_reactor(struct rv_reactor *reactor)
285{
286	struct rv_reactor *r;
287
288	list_for_each_entry(r, &rv_reactors_list, list) {
289		if (strcmp(reactor->name, r->name) == 0) {
290			pr_info("Reactor %s is already registered\n", reactor->name);
291			return -EINVAL;
292		}
293	}
294
295	list_add_tail(&reactor->list, &rv_reactors_list);
296
297	return 0;
298}
299
300/**
301 * rv_register_reactor - register a rv reactor.
302 * @reactor:	The rv_reactor to be registered.
303 *
304 * Returns 0 if successful, error otherwise.
305 */
306int rv_register_reactor(struct rv_reactor *reactor)
307{
308	if (strlen(reactor->name) >= MAX_RV_REACTOR_NAME_SIZE) {
309		pr_info("Reactor %s has a name longer than %d\n",
310			reactor->name, MAX_RV_MONITOR_NAME_SIZE);
311		return -EINVAL;
312	}
313
314	guard(mutex)(&rv_interface_lock);
315	return __rv_register_reactor(reactor);
316}
317
318/**
319 * rv_unregister_reactor - unregister a rv reactor.
320 * @reactor:	The rv_reactor to be unregistered.
321 *
322 * Returns 0 if successful, error otherwise.
323 */
324int rv_unregister_reactor(struct rv_reactor *reactor)
325{
326	guard(mutex)(&rv_interface_lock);
327	list_del(&reactor->list);
328	return 0;
329}
330
331/*
332 * reacting_on interface.
333 */
334static bool __read_mostly reacting_on;
335
336/**
337 * rv_reacting_on - checks if reacting is on
338 *
339 * Returns 1 if on, 0 otherwise.
340 */
341static bool rv_reacting_on(void)
342{
343	/* Ensures that concurrent monitors read consistent reacting_on */
344	smp_rmb();
345	return READ_ONCE(reacting_on);
346}
347
348static ssize_t reacting_on_read_data(struct file *filp,
349				     char __user *user_buf,
350				     size_t count, loff_t *ppos)
351{
352	char *buff;
353
354	buff = rv_reacting_on() ? "1\n" : "0\n";
355
356	return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff)+1);
357}
358
359static void turn_reacting_off(void)
360{
361	WRITE_ONCE(reacting_on, false);
362	/* Ensures that concurrent monitors read consistent reacting_on */
363	smp_wmb();
364}
365
366static void turn_reacting_on(void)
367{
368	WRITE_ONCE(reacting_on, true);
369	/* Ensures that concurrent monitors read consistent reacting_on */
370	smp_wmb();
371}
372
373static ssize_t reacting_on_write_data(struct file *filp, const char __user *user_buf,
374				      size_t count, loff_t *ppos)
375{
376	int retval;
377	bool val;
378
379	retval = kstrtobool_from_user(user_buf, count, &val);
380	if (retval)
381		return retval;
382
383	guard(mutex)(&rv_interface_lock);
384
385	if (val)
386		turn_reacting_on();
387	else
388		turn_reacting_off();
389
390	/*
391	 * Wait for the execution of all events to finish
392	 * before returning to user-space.
393	 */
394	tracepoint_synchronize_unregister();
395
396	return count;
397}
398
399static const struct file_operations reacting_on_fops = {
400	.open   = simple_open,
401	.write  = reacting_on_write_data,
402	.read   = reacting_on_read_data,
403};
404
405/**
406 * reactor_populate_monitor - creates per monitor reactors file
407 * @mon:	The monitor.
408 * @root:	The directory of the monitor.
409 *
410 * Returns 0 if successful, error otherwise.
411 */
412int reactor_populate_monitor(struct rv_monitor *mon, struct dentry *root)
413{
414	struct dentry *tmp;
415
416	tmp = rv_create_file("reactors", RV_MODE_WRITE, root, mon, &monitor_reactors_ops);
417	if (!tmp)
418		return -ENOMEM;
419
420	/*
421	 * Configure as the rv_nop reactor.
422	 */
423	mon->reactor = get_reactor_rdef_by_name("nop");
424
425	return 0;
426}
427
428/*
429 * Nop reactor register
430 */
431__printf(1, 0) static void rv_nop_reaction(const char *msg, va_list args)
432{
433}
434
435static struct rv_reactor rv_nop = {
436	.name = "nop",
437	.description = "no-operation reactor: do nothing.",
438	.react = rv_nop_reaction
439};
440
441int init_rv_reactors(struct dentry *root_dir)
442{
443	int retval;
444
445	struct dentry *available __free(rv_remove) =
446		rv_create_file("available_reactors", RV_MODE_READ, root_dir,
447				NULL, &available_reactors_ops);
448
449	struct dentry *reacting __free(rv_remove) =
450		rv_create_file("reacting_on", RV_MODE_WRITE, root_dir, NULL, &reacting_on_fops);
451
452	if (!reacting || !available)
453		return -ENOMEM;
454
455	retval = __rv_register_reactor(&rv_nop);
456	if (retval)
457		return retval;
458
459	turn_reacting_on();
460
461	retain_and_null_ptr(available);
462	retain_and_null_ptr(reacting);
463	return 0;
464}
465
466void rv_react(struct rv_monitor *monitor, const char *msg, ...)
467{
468	static DEFINE_WAIT_OVERRIDE_MAP(rv_react_map, LD_WAIT_FREE);
469	va_list args;
470
471	if (!rv_reacting_on() || !monitor->react)
472		return;
473
474	va_start(args, msg);
475
476	lock_map_acquire_try(&rv_react_map);
477	monitor->react(msg, args);
478	lock_map_release(&rv_react_map);
479
480	va_end(args);
481}
~/ Read-only file preview.