// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <[email protected]> * * Runtime reactor interface. * * A runtime monitor can cause a reaction to the detection of an * exception on the model's execution. By default, the monitors have * tracing reactions, printing the monitor output via tracepoints. * But other reactions can be added (on-demand) via this interface. * * == Registering reactors == * * The struct rv_reactor defines a callback function to be executed * in case of a model exception happens. The callback function * receives a message to be (optionally) printed before executing * the reaction. * * A RV reactor is registered via: * int rv_register_reactor(struct rv_reactor *reactor) * And unregistered via: * int rv_unregister_reactor(struct rv_reactor *reactor) * * These functions are exported to modules, enabling reactors to be * dynamically loaded. * * == User interface == * * The user interface resembles the kernel tracing interface and * presents these files: * * "available_reactors" * - List the available reactors, one per line. * * For example: * # cat available_reactors * nop * panic * printk * * "reacting_on" * - It is an on/off general switch for reactors, disabling * all reactions. * * "monitors/MONITOR/reactors" * - List available reactors, with the select reaction for the given * MONITOR inside []. The default one is the nop (no operation) * reactor. * - Writing the name of an reactor enables it to the given * MONITOR. * * For example: * # cat monitors/wip/reactors * [nop] * panic * printk * # echo panic > monitors/wip/reactors * # cat monitors/wip/reactors * nop * [panic] * printk */ #include <linux/slab.h> #include "rv.h" /* * Interface for the reactor register. */ static LIST_HEAD(rv_reactors_list); static struct rv_reactor_def *get_reactor_rdef_by_name(char *name) { … } /* * Available reactors seq functions. */ static int reactors_show(struct seq_file *m, void *p) { … } static void reactors_stop(struct seq_file *m, void *p) { … } static void *reactors_start(struct seq_file *m, loff_t *pos) { … } static void *reactors_next(struct seq_file *m, void *p, loff_t *pos) { … } /* * available_reactors seq definition. */ static const struct seq_operations available_reactors_seq_ops = …; /* * available_reactors interface. */ static int available_reactors_open(struct inode *inode, struct file *file) { return seq_open(file, &available_reactors_seq_ops); }; static const struct file_operations available_reactors_ops = …; /* * Monitor's reactor file. */ static int monitor_reactor_show(struct seq_file *m, void *p) { … } /* * available_reactors seq definition. */ static const struct seq_operations monitor_reactors_seq_ops = …; static void monitor_swap_reactors(struct rv_monitor_def *mdef, struct rv_reactor_def *rdef, bool reacting) { … } static ssize_t monitor_reactors_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { … } /* * available_reactors interface. */ static int monitor_reactors_open(struct inode *inode, struct file *file) { struct rv_monitor_def *mdef = inode->i_private; struct seq_file *seq_f; int ret; ret = seq_open(file, &monitor_reactors_seq_ops); if (ret < 0) return ret; /* * seq_open stores the seq_file on the file->private data. */ seq_f = file->private_data; /* * Copy the create file "private" data to the seq_file private data. */ seq_f->private = mdef; return 0; }; static const struct file_operations monitor_reactors_ops = …; static int __rv_register_reactor(struct rv_reactor *reactor) { … } /** * rv_register_reactor - register a rv reactor. * @reactor: The rv_reactor to be registered. * * Returns 0 if successful, error otherwise. */ int rv_register_reactor(struct rv_reactor *reactor) { … } /** * rv_unregister_reactor - unregister a rv reactor. * @reactor: The rv_reactor to be unregistered. * * Returns 0 if successful, error otherwise. */ int rv_unregister_reactor(struct rv_reactor *reactor) { … } /* * reacting_on interface. */ static bool __read_mostly reacting_on; /** * rv_reacting_on - checks if reacting is on * * Returns 1 if on, 0 otherwise. */ bool rv_reacting_on(void) { … } static ssize_t reacting_on_read_data(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos) { … } static void turn_reacting_off(void) { … } static void turn_reacting_on(void) { … } static ssize_t reacting_on_write_data(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos) { … } static const struct file_operations reacting_on_fops = …; /** * reactor_populate_monitor - creates per monitor reactors file * @mdef: monitor's definition. * * Returns 0 if successful, error otherwise. */ int reactor_populate_monitor(struct rv_monitor_def *mdef) { … } /** * reactor_cleanup_monitor - cleanup a monitor reference * @mdef: monitor's definition. */ void reactor_cleanup_monitor(struct rv_monitor_def *mdef) { … } /* * Nop reactor register */ static void rv_nop_reaction(char *msg) { … } static struct rv_reactor rv_nop = …; int init_rv_reactors(struct dentry *root_dir) { … }