1102227b9SDaniel Bristot de Oliveira // SPDX-License-Identifier: GPL-2.0 2102227b9SDaniel Bristot de Oliveira /* 3102227b9SDaniel Bristot de Oliveira * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org> 4102227b9SDaniel Bristot de Oliveira * 5102227b9SDaniel Bristot de Oliveira * This is the online Runtime Verification (RV) interface. 6102227b9SDaniel Bristot de Oliveira * 7102227b9SDaniel Bristot de Oliveira * RV is a lightweight (yet rigorous) method that complements classical 8102227b9SDaniel Bristot de Oliveira * exhaustive verification techniques (such as model checking and 9102227b9SDaniel Bristot de Oliveira * theorem proving) with a more practical approach to complex systems. 10102227b9SDaniel Bristot de Oliveira * 11102227b9SDaniel Bristot de Oliveira * RV works by analyzing the trace of the system's actual execution, 12102227b9SDaniel Bristot de Oliveira * comparing it against a formal specification of the system behavior. 13102227b9SDaniel Bristot de Oliveira * RV can give precise information on the runtime behavior of the 14102227b9SDaniel Bristot de Oliveira * monitored system while enabling the reaction for unexpected 15102227b9SDaniel Bristot de Oliveira * events, avoiding, for example, the propagation of a failure on 16102227b9SDaniel Bristot de Oliveira * safety-critical systems. 17102227b9SDaniel Bristot de Oliveira * 18102227b9SDaniel Bristot de Oliveira * The development of this interface roots in the development of the 19102227b9SDaniel Bristot de Oliveira * paper: 20102227b9SDaniel Bristot de Oliveira * 21102227b9SDaniel Bristot de Oliveira * De Oliveira, Daniel Bristot; Cucinotta, Tommaso; De Oliveira, Romulo 22102227b9SDaniel Bristot de Oliveira * Silva. Efficient formal verification for the Linux kernel. In: 23102227b9SDaniel Bristot de Oliveira * International Conference on Software Engineering and Formal Methods. 24102227b9SDaniel Bristot de Oliveira * Springer, Cham, 2019. p. 315-332. 25102227b9SDaniel Bristot de Oliveira * 26102227b9SDaniel Bristot de Oliveira * And: 27102227b9SDaniel Bristot de Oliveira * 28102227b9SDaniel Bristot de Oliveira * De Oliveira, Daniel Bristot, et al. Automata-based formal analysis 29102227b9SDaniel Bristot de Oliveira * and verification of the real-time Linux kernel. PhD Thesis, 2020. 30102227b9SDaniel Bristot de Oliveira * 31102227b9SDaniel Bristot de Oliveira * == Runtime monitor interface == 32102227b9SDaniel Bristot de Oliveira * 33102227b9SDaniel Bristot de Oliveira * A monitor is the central part of the runtime verification of a system. 34102227b9SDaniel Bristot de Oliveira * 35102227b9SDaniel Bristot de Oliveira * The monitor stands in between the formal specification of the desired 36102227b9SDaniel Bristot de Oliveira * (or undesired) behavior, and the trace of the actual system. 37102227b9SDaniel Bristot de Oliveira * 38102227b9SDaniel Bristot de Oliveira * In Linux terms, the runtime verification monitors are encapsulated 39102227b9SDaniel Bristot de Oliveira * inside the "RV monitor" abstraction. A RV monitor includes a reference 40102227b9SDaniel Bristot de Oliveira * model of the system, a set of instances of the monitor (per-cpu monitor, 41102227b9SDaniel Bristot de Oliveira * per-task monitor, and so on), and the helper functions that glue the 42102227b9SDaniel Bristot de Oliveira * monitor to the system via trace. Generally, a monitor includes some form 43102227b9SDaniel Bristot de Oliveira * of trace output as a reaction for event parsing and exceptions, 44102227b9SDaniel Bristot de Oliveira * as depicted bellow: 45102227b9SDaniel Bristot de Oliveira * 46102227b9SDaniel Bristot de Oliveira * Linux +----- RV Monitor ----------------------------------+ Formal 47102227b9SDaniel Bristot de Oliveira * Realm | | Realm 48102227b9SDaniel Bristot de Oliveira * +-------------------+ +----------------+ +-----------------+ 49102227b9SDaniel Bristot de Oliveira * | Linux kernel | | Monitor | | Reference | 50102227b9SDaniel Bristot de Oliveira * | Tracing | -> | Instance(s) | <- | Model | 51102227b9SDaniel Bristot de Oliveira * | (instrumentation) | | (verification) | | (specification) | 52102227b9SDaniel Bristot de Oliveira * +-------------------+ +----------------+ +-----------------+ 53102227b9SDaniel Bristot de Oliveira * | | | 54102227b9SDaniel Bristot de Oliveira * | V | 55102227b9SDaniel Bristot de Oliveira * | +----------+ | 56102227b9SDaniel Bristot de Oliveira * | | Reaction | | 57102227b9SDaniel Bristot de Oliveira * | +--+--+--+-+ | 58102227b9SDaniel Bristot de Oliveira * | | | | | 59102227b9SDaniel Bristot de Oliveira * | | | +-> trace output ? | 60102227b9SDaniel Bristot de Oliveira * +------------------------|--|----------------------+ 61102227b9SDaniel Bristot de Oliveira * | +----> panic ? 62102227b9SDaniel Bristot de Oliveira * +-------> <user-specified> 63102227b9SDaniel Bristot de Oliveira * 64102227b9SDaniel Bristot de Oliveira * This file implements the interface for loading RV monitors, and 65102227b9SDaniel Bristot de Oliveira * to control the verification session. 66102227b9SDaniel Bristot de Oliveira * 67102227b9SDaniel Bristot de Oliveira * == Registering monitors == 68102227b9SDaniel Bristot de Oliveira * 69102227b9SDaniel Bristot de Oliveira * The struct rv_monitor defines a set of callback functions to control 70102227b9SDaniel Bristot de Oliveira * a verification session. For instance, when a given monitor is enabled, 71102227b9SDaniel Bristot de Oliveira * the "enable" callback function is called to hook the instrumentation 72102227b9SDaniel Bristot de Oliveira * functions to the kernel trace events. The "disable" function is called 73102227b9SDaniel Bristot de Oliveira * when disabling the verification session. 74102227b9SDaniel Bristot de Oliveira * 75102227b9SDaniel Bristot de Oliveira * A RV monitor is registered via: 76102227b9SDaniel Bristot de Oliveira * int rv_register_monitor(struct rv_monitor *monitor); 77102227b9SDaniel Bristot de Oliveira * And unregistered via: 78102227b9SDaniel Bristot de Oliveira * int rv_unregister_monitor(struct rv_monitor *monitor); 79102227b9SDaniel Bristot de Oliveira * 80102227b9SDaniel Bristot de Oliveira * == User interface == 81102227b9SDaniel Bristot de Oliveira * 82102227b9SDaniel Bristot de Oliveira * The user interface resembles kernel tracing interface. It presents 83102227b9SDaniel Bristot de Oliveira * these files: 84102227b9SDaniel Bristot de Oliveira * 85102227b9SDaniel Bristot de Oliveira * "available_monitors" 86102227b9SDaniel Bristot de Oliveira * - List the available monitors, one per line. 87102227b9SDaniel Bristot de Oliveira * 88102227b9SDaniel Bristot de Oliveira * For example: 89102227b9SDaniel Bristot de Oliveira * # cat available_monitors 90102227b9SDaniel Bristot de Oliveira * wip 91102227b9SDaniel Bristot de Oliveira * wwnr 92102227b9SDaniel Bristot de Oliveira * 93102227b9SDaniel Bristot de Oliveira * "enabled_monitors" 94102227b9SDaniel Bristot de Oliveira * - Lists the enabled monitors, one per line; 95102227b9SDaniel Bristot de Oliveira * - Writing to it enables a given monitor; 96102227b9SDaniel Bristot de Oliveira * - Writing a monitor name with a '!' prefix disables it; 97102227b9SDaniel Bristot de Oliveira * - Truncating the file disables all enabled monitors. 98102227b9SDaniel Bristot de Oliveira * 99102227b9SDaniel Bristot de Oliveira * For example: 100102227b9SDaniel Bristot de Oliveira * # cat enabled_monitors 101102227b9SDaniel Bristot de Oliveira * # echo wip > enabled_monitors 102102227b9SDaniel Bristot de Oliveira * # echo wwnr >> enabled_monitors 103102227b9SDaniel Bristot de Oliveira * # cat enabled_monitors 104102227b9SDaniel Bristot de Oliveira * wip 105102227b9SDaniel Bristot de Oliveira * wwnr 106102227b9SDaniel Bristot de Oliveira * # echo '!wip' >> enabled_monitors 107102227b9SDaniel Bristot de Oliveira * # cat enabled_monitors 108102227b9SDaniel Bristot de Oliveira * wwnr 109102227b9SDaniel Bristot de Oliveira * # echo > enabled_monitors 110102227b9SDaniel Bristot de Oliveira * # cat enabled_monitors 111102227b9SDaniel Bristot de Oliveira * # 112102227b9SDaniel Bristot de Oliveira * 113102227b9SDaniel Bristot de Oliveira * Note that more than one monitor can be enabled concurrently. 114102227b9SDaniel Bristot de Oliveira * 115102227b9SDaniel Bristot de Oliveira * "monitoring_on" 116102227b9SDaniel Bristot de Oliveira * - It is an on/off general switcher for monitoring. Note 117102227b9SDaniel Bristot de Oliveira * that it does not disable enabled monitors or detach events, 118102227b9SDaniel Bristot de Oliveira * but stops the per-entity monitors from monitoring the events 119102227b9SDaniel Bristot de Oliveira * received from the instrumentation. It resembles the "tracing_on" 120102227b9SDaniel Bristot de Oliveira * switcher. 121102227b9SDaniel Bristot de Oliveira * 122102227b9SDaniel Bristot de Oliveira * "monitors/" 123102227b9SDaniel Bristot de Oliveira * Each monitor will have its own directory inside "monitors/". There 124102227b9SDaniel Bristot de Oliveira * the monitor specific files will be presented. 125102227b9SDaniel Bristot de Oliveira * The "monitors/" directory resembles the "events" directory on 126102227b9SDaniel Bristot de Oliveira * tracefs. 127102227b9SDaniel Bristot de Oliveira * 128102227b9SDaniel Bristot de Oliveira * For example: 129102227b9SDaniel Bristot de Oliveira * # cd monitors/wip/ 130102227b9SDaniel Bristot de Oliveira * # ls 131102227b9SDaniel Bristot de Oliveira * desc enable 132102227b9SDaniel Bristot de Oliveira * # cat desc 133102227b9SDaniel Bristot de Oliveira * auto-generated wakeup in preemptive monitor. 134102227b9SDaniel Bristot de Oliveira * # cat enable 135102227b9SDaniel Bristot de Oliveira * 0 136ff0aaf67SDaniel Bristot de Oliveira * 137ff0aaf67SDaniel Bristot de Oliveira * For further information, see: 138ff0aaf67SDaniel Bristot de Oliveira * Documentation/trace/rv/runtime-verification.rst 139102227b9SDaniel Bristot de Oliveira */ 140102227b9SDaniel Bristot de Oliveira 141102227b9SDaniel Bristot de Oliveira #include <linux/kernel.h> 142102227b9SDaniel Bristot de Oliveira #include <linux/module.h> 143102227b9SDaniel Bristot de Oliveira #include <linux/init.h> 144102227b9SDaniel Bristot de Oliveira #include <linux/slab.h> 145102227b9SDaniel Bristot de Oliveira 14679257534SDaniel Bristot de Oliveira #ifdef CONFIG_DA_MON_EVENTS 14779257534SDaniel Bristot de Oliveira #define CREATE_TRACE_POINTS 14879257534SDaniel Bristot de Oliveira #include <trace/events/rv.h> 14979257534SDaniel Bristot de Oliveira #endif 15079257534SDaniel Bristot de Oliveira 151102227b9SDaniel Bristot de Oliveira #include "rv.h" 152102227b9SDaniel Bristot de Oliveira 153102227b9SDaniel Bristot de Oliveira DEFINE_MUTEX(rv_interface_lock); 154102227b9SDaniel Bristot de Oliveira 155102227b9SDaniel Bristot de Oliveira static struct rv_interface rv_root; 156102227b9SDaniel Bristot de Oliveira 157102227b9SDaniel Bristot de Oliveira struct dentry *get_monitors_root(void) 158102227b9SDaniel Bristot de Oliveira { 159102227b9SDaniel Bristot de Oliveira return rv_root.monitors_dir; 160102227b9SDaniel Bristot de Oliveira } 161102227b9SDaniel Bristot de Oliveira 162102227b9SDaniel Bristot de Oliveira /* 163102227b9SDaniel Bristot de Oliveira * Interface for the monitor register. 164102227b9SDaniel Bristot de Oliveira */ 165102227b9SDaniel Bristot de Oliveira static LIST_HEAD(rv_monitors_list); 166102227b9SDaniel Bristot de Oliveira 167102227b9SDaniel Bristot de Oliveira static int task_monitor_count; 168102227b9SDaniel Bristot de Oliveira static bool task_monitor_slots[RV_PER_TASK_MONITORS]; 169102227b9SDaniel Bristot de Oliveira 170102227b9SDaniel Bristot de Oliveira int rv_get_task_monitor_slot(void) 171102227b9SDaniel Bristot de Oliveira { 172102227b9SDaniel Bristot de Oliveira int i; 173102227b9SDaniel Bristot de Oliveira 174102227b9SDaniel Bristot de Oliveira lockdep_assert_held(&rv_interface_lock); 175102227b9SDaniel Bristot de Oliveira 176102227b9SDaniel Bristot de Oliveira if (task_monitor_count == RV_PER_TASK_MONITORS) 177102227b9SDaniel Bristot de Oliveira return -EBUSY; 178102227b9SDaniel Bristot de Oliveira 179102227b9SDaniel Bristot de Oliveira task_monitor_count++; 180102227b9SDaniel Bristot de Oliveira 181102227b9SDaniel Bristot de Oliveira for (i = 0; i < RV_PER_TASK_MONITORS; i++) { 182102227b9SDaniel Bristot de Oliveira if (task_monitor_slots[i] == false) { 183102227b9SDaniel Bristot de Oliveira task_monitor_slots[i] = true; 184102227b9SDaniel Bristot de Oliveira return i; 185102227b9SDaniel Bristot de Oliveira } 186102227b9SDaniel Bristot de Oliveira } 187102227b9SDaniel Bristot de Oliveira 188102227b9SDaniel Bristot de Oliveira WARN_ONCE(1, "RV task_monitor_count and slots are out of sync\n"); 189102227b9SDaniel Bristot de Oliveira 190102227b9SDaniel Bristot de Oliveira return -EINVAL; 191102227b9SDaniel Bristot de Oliveira } 192102227b9SDaniel Bristot de Oliveira 193102227b9SDaniel Bristot de Oliveira void rv_put_task_monitor_slot(int slot) 194102227b9SDaniel Bristot de Oliveira { 195102227b9SDaniel Bristot de Oliveira lockdep_assert_held(&rv_interface_lock); 196102227b9SDaniel Bristot de Oliveira 197102227b9SDaniel Bristot de Oliveira if (slot < 0 || slot >= RV_PER_TASK_MONITORS) { 198102227b9SDaniel Bristot de Oliveira WARN_ONCE(1, "RV releasing an invalid slot!: %d\n", slot); 199102227b9SDaniel Bristot de Oliveira return; 200102227b9SDaniel Bristot de Oliveira } 201102227b9SDaniel Bristot de Oliveira 202102227b9SDaniel Bristot de Oliveira WARN_ONCE(!task_monitor_slots[slot], "RV releasing unused task_monitor_slots: %d\n", 203102227b9SDaniel Bristot de Oliveira slot); 204102227b9SDaniel Bristot de Oliveira 205102227b9SDaniel Bristot de Oliveira task_monitor_count--; 206102227b9SDaniel Bristot de Oliveira task_monitor_slots[slot] = false; 207102227b9SDaniel Bristot de Oliveira } 208102227b9SDaniel Bristot de Oliveira 209102227b9SDaniel Bristot de Oliveira /* 210102227b9SDaniel Bristot de Oliveira * This section collects the monitor/ files and folders. 211102227b9SDaniel Bristot de Oliveira */ 212102227b9SDaniel Bristot de Oliveira static ssize_t monitor_enable_read_data(struct file *filp, char __user *user_buf, size_t count, 213102227b9SDaniel Bristot de Oliveira loff_t *ppos) 214102227b9SDaniel Bristot de Oliveira { 215102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef = filp->private_data; 216102227b9SDaniel Bristot de Oliveira const char *buff; 217102227b9SDaniel Bristot de Oliveira 218102227b9SDaniel Bristot de Oliveira buff = mdef->monitor->enabled ? "1\n" : "0\n"; 219102227b9SDaniel Bristot de Oliveira 220102227b9SDaniel Bristot de Oliveira return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff)+1); 221102227b9SDaniel Bristot de Oliveira } 222102227b9SDaniel Bristot de Oliveira 223102227b9SDaniel Bristot de Oliveira /* 224102227b9SDaniel Bristot de Oliveira * __rv_disable_monitor - disabled an enabled monitor 225102227b9SDaniel Bristot de Oliveira */ 226102227b9SDaniel Bristot de Oliveira static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync) 227102227b9SDaniel Bristot de Oliveira { 228102227b9SDaniel Bristot de Oliveira lockdep_assert_held(&rv_interface_lock); 229102227b9SDaniel Bristot de Oliveira 230102227b9SDaniel Bristot de Oliveira if (mdef->monitor->enabled) { 231102227b9SDaniel Bristot de Oliveira mdef->monitor->enabled = 0; 232102227b9SDaniel Bristot de Oliveira mdef->monitor->disable(); 233102227b9SDaniel Bristot de Oliveira 234102227b9SDaniel Bristot de Oliveira /* 235102227b9SDaniel Bristot de Oliveira * Wait for the execution of all events to finish. 236102227b9SDaniel Bristot de Oliveira * Otherwise, the data used by the monitor could 237102227b9SDaniel Bristot de Oliveira * be inconsistent. i.e., if the monitor is re-enabled. 238102227b9SDaniel Bristot de Oliveira */ 239102227b9SDaniel Bristot de Oliveira if (sync) 240102227b9SDaniel Bristot de Oliveira tracepoint_synchronize_unregister(); 241102227b9SDaniel Bristot de Oliveira return 1; 242102227b9SDaniel Bristot de Oliveira } 243102227b9SDaniel Bristot de Oliveira return 0; 244102227b9SDaniel Bristot de Oliveira } 245102227b9SDaniel Bristot de Oliveira 246102227b9SDaniel Bristot de Oliveira /** 247102227b9SDaniel Bristot de Oliveira * rv_disable_monitor - disable a given runtime monitor 248*1e8b7b3dSYang Li * @mdef: Pointer to the monitor definition structure. 249102227b9SDaniel Bristot de Oliveira * 250102227b9SDaniel Bristot de Oliveira * Returns 0 on success. 251102227b9SDaniel Bristot de Oliveira */ 252102227b9SDaniel Bristot de Oliveira int rv_disable_monitor(struct rv_monitor_def *mdef) 253102227b9SDaniel Bristot de Oliveira { 254102227b9SDaniel Bristot de Oliveira __rv_disable_monitor(mdef, true); 255102227b9SDaniel Bristot de Oliveira return 0; 256102227b9SDaniel Bristot de Oliveira } 257102227b9SDaniel Bristot de Oliveira 258102227b9SDaniel Bristot de Oliveira /** 259102227b9SDaniel Bristot de Oliveira * rv_enable_monitor - enable a given runtime monitor 260*1e8b7b3dSYang Li * @mdef: Pointer to the monitor definition structure. 261102227b9SDaniel Bristot de Oliveira * 262102227b9SDaniel Bristot de Oliveira * Returns 0 on success, error otherwise. 263102227b9SDaniel Bristot de Oliveira */ 264102227b9SDaniel Bristot de Oliveira int rv_enable_monitor(struct rv_monitor_def *mdef) 265102227b9SDaniel Bristot de Oliveira { 266102227b9SDaniel Bristot de Oliveira int retval; 267102227b9SDaniel Bristot de Oliveira 268102227b9SDaniel Bristot de Oliveira lockdep_assert_held(&rv_interface_lock); 269102227b9SDaniel Bristot de Oliveira 270102227b9SDaniel Bristot de Oliveira if (mdef->monitor->enabled) 271102227b9SDaniel Bristot de Oliveira return 0; 272102227b9SDaniel Bristot de Oliveira 273102227b9SDaniel Bristot de Oliveira retval = mdef->monitor->enable(); 274102227b9SDaniel Bristot de Oliveira 275102227b9SDaniel Bristot de Oliveira if (!retval) 276102227b9SDaniel Bristot de Oliveira mdef->monitor->enabled = 1; 277102227b9SDaniel Bristot de Oliveira 278102227b9SDaniel Bristot de Oliveira return retval; 279102227b9SDaniel Bristot de Oliveira } 280102227b9SDaniel Bristot de Oliveira 281102227b9SDaniel Bristot de Oliveira /* 282102227b9SDaniel Bristot de Oliveira * interface for enabling/disabling a monitor. 283102227b9SDaniel Bristot de Oliveira */ 284102227b9SDaniel Bristot de Oliveira static ssize_t monitor_enable_write_data(struct file *filp, const char __user *user_buf, 285102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 286102227b9SDaniel Bristot de Oliveira { 287102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef = filp->private_data; 288102227b9SDaniel Bristot de Oliveira int retval; 289102227b9SDaniel Bristot de Oliveira bool val; 290102227b9SDaniel Bristot de Oliveira 291102227b9SDaniel Bristot de Oliveira retval = kstrtobool_from_user(user_buf, count, &val); 292102227b9SDaniel Bristot de Oliveira if (retval) 293102227b9SDaniel Bristot de Oliveira return retval; 294102227b9SDaniel Bristot de Oliveira 295102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 296102227b9SDaniel Bristot de Oliveira 297102227b9SDaniel Bristot de Oliveira if (val) 298102227b9SDaniel Bristot de Oliveira retval = rv_enable_monitor(mdef); 299102227b9SDaniel Bristot de Oliveira else 300102227b9SDaniel Bristot de Oliveira retval = rv_disable_monitor(mdef); 301102227b9SDaniel Bristot de Oliveira 302102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 303102227b9SDaniel Bristot de Oliveira 304102227b9SDaniel Bristot de Oliveira return retval ? : count; 305102227b9SDaniel Bristot de Oliveira } 306102227b9SDaniel Bristot de Oliveira 307102227b9SDaniel Bristot de Oliveira static const struct file_operations interface_enable_fops = { 308102227b9SDaniel Bristot de Oliveira .open = simple_open, 309102227b9SDaniel Bristot de Oliveira .write = monitor_enable_write_data, 310102227b9SDaniel Bristot de Oliveira .read = monitor_enable_read_data, 311102227b9SDaniel Bristot de Oliveira }; 312102227b9SDaniel Bristot de Oliveira 313102227b9SDaniel Bristot de Oliveira /* 314102227b9SDaniel Bristot de Oliveira * Interface to read monitors description. 315102227b9SDaniel Bristot de Oliveira */ 316102227b9SDaniel Bristot de Oliveira static ssize_t monitor_desc_read_data(struct file *filp, char __user *user_buf, size_t count, 317102227b9SDaniel Bristot de Oliveira loff_t *ppos) 318102227b9SDaniel Bristot de Oliveira { 319102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef = filp->private_data; 320102227b9SDaniel Bristot de Oliveira char buff[256]; 321102227b9SDaniel Bristot de Oliveira 322102227b9SDaniel Bristot de Oliveira memset(buff, 0, sizeof(buff)); 323102227b9SDaniel Bristot de Oliveira 324102227b9SDaniel Bristot de Oliveira snprintf(buff, sizeof(buff), "%s\n", mdef->monitor->description); 325102227b9SDaniel Bristot de Oliveira 326102227b9SDaniel Bristot de Oliveira return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff) + 1); 327102227b9SDaniel Bristot de Oliveira } 328102227b9SDaniel Bristot de Oliveira 329102227b9SDaniel Bristot de Oliveira static const struct file_operations interface_desc_fops = { 330102227b9SDaniel Bristot de Oliveira .open = simple_open, 331102227b9SDaniel Bristot de Oliveira .read = monitor_desc_read_data, 332102227b9SDaniel Bristot de Oliveira }; 333102227b9SDaniel Bristot de Oliveira 334102227b9SDaniel Bristot de Oliveira /* 335102227b9SDaniel Bristot de Oliveira * During the registration of a monitor, this function creates 336102227b9SDaniel Bristot de Oliveira * the monitor dir, where the specific options of the monitor 337102227b9SDaniel Bristot de Oliveira * are exposed. 338102227b9SDaniel Bristot de Oliveira */ 339102227b9SDaniel Bristot de Oliveira static int create_monitor_dir(struct rv_monitor_def *mdef) 340102227b9SDaniel Bristot de Oliveira { 341102227b9SDaniel Bristot de Oliveira struct dentry *root = get_monitors_root(); 342102227b9SDaniel Bristot de Oliveira const char *name = mdef->monitor->name; 343102227b9SDaniel Bristot de Oliveira struct dentry *tmp; 344102227b9SDaniel Bristot de Oliveira int retval; 345102227b9SDaniel Bristot de Oliveira 346102227b9SDaniel Bristot de Oliveira mdef->root_d = rv_create_dir(name, root); 347102227b9SDaniel Bristot de Oliveira if (!mdef->root_d) 348102227b9SDaniel Bristot de Oliveira return -ENOMEM; 349102227b9SDaniel Bristot de Oliveira 350102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("enable", RV_MODE_WRITE, mdef->root_d, mdef, &interface_enable_fops); 351102227b9SDaniel Bristot de Oliveira if (!tmp) { 352102227b9SDaniel Bristot de Oliveira retval = -ENOMEM; 353102227b9SDaniel Bristot de Oliveira goto out_remove_root; 354102227b9SDaniel Bristot de Oliveira } 355102227b9SDaniel Bristot de Oliveira 356102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("desc", RV_MODE_READ, mdef->root_d, mdef, &interface_desc_fops); 357102227b9SDaniel Bristot de Oliveira if (!tmp) { 358102227b9SDaniel Bristot de Oliveira retval = -ENOMEM; 359102227b9SDaniel Bristot de Oliveira goto out_remove_root; 360102227b9SDaniel Bristot de Oliveira } 361102227b9SDaniel Bristot de Oliveira 36204acadcbSDaniel Bristot de Oliveira retval = reactor_populate_monitor(mdef); 36304acadcbSDaniel Bristot de Oliveira if (retval) 36404acadcbSDaniel Bristot de Oliveira goto out_remove_root; 36504acadcbSDaniel Bristot de Oliveira 366102227b9SDaniel Bristot de Oliveira return 0; 367102227b9SDaniel Bristot de Oliveira 368102227b9SDaniel Bristot de Oliveira out_remove_root: 369102227b9SDaniel Bristot de Oliveira rv_remove(mdef->root_d); 370102227b9SDaniel Bristot de Oliveira return retval; 371102227b9SDaniel Bristot de Oliveira } 372102227b9SDaniel Bristot de Oliveira 373102227b9SDaniel Bristot de Oliveira /* 374102227b9SDaniel Bristot de Oliveira * Available/Enable monitor shared seq functions. 375102227b9SDaniel Bristot de Oliveira */ 376102227b9SDaniel Bristot de Oliveira static int monitors_show(struct seq_file *m, void *p) 377102227b9SDaniel Bristot de Oliveira { 378102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mon_def = p; 379102227b9SDaniel Bristot de Oliveira 380102227b9SDaniel Bristot de Oliveira seq_printf(m, "%s\n", mon_def->monitor->name); 381102227b9SDaniel Bristot de Oliveira return 0; 382102227b9SDaniel Bristot de Oliveira } 383102227b9SDaniel Bristot de Oliveira 384102227b9SDaniel Bristot de Oliveira /* 385102227b9SDaniel Bristot de Oliveira * Used by the seq file operations at the end of a read 386102227b9SDaniel Bristot de Oliveira * operation. 387102227b9SDaniel Bristot de Oliveira */ 388102227b9SDaniel Bristot de Oliveira static void monitors_stop(struct seq_file *m, void *p) 389102227b9SDaniel Bristot de Oliveira { 390102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 391102227b9SDaniel Bristot de Oliveira } 392102227b9SDaniel Bristot de Oliveira 393102227b9SDaniel Bristot de Oliveira /* 394102227b9SDaniel Bristot de Oliveira * Available monitor seq functions. 395102227b9SDaniel Bristot de Oliveira */ 396102227b9SDaniel Bristot de Oliveira static void *available_monitors_start(struct seq_file *m, loff_t *pos) 397102227b9SDaniel Bristot de Oliveira { 398102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 399102227b9SDaniel Bristot de Oliveira return seq_list_start(&rv_monitors_list, *pos); 400102227b9SDaniel Bristot de Oliveira } 401102227b9SDaniel Bristot de Oliveira 402102227b9SDaniel Bristot de Oliveira static void *available_monitors_next(struct seq_file *m, void *p, loff_t *pos) 403102227b9SDaniel Bristot de Oliveira { 404102227b9SDaniel Bristot de Oliveira return seq_list_next(p, &rv_monitors_list, pos); 405102227b9SDaniel Bristot de Oliveira } 406102227b9SDaniel Bristot de Oliveira 407102227b9SDaniel Bristot de Oliveira /* 408102227b9SDaniel Bristot de Oliveira * Enable monitor seq functions. 409102227b9SDaniel Bristot de Oliveira */ 410102227b9SDaniel Bristot de Oliveira static void *enabled_monitors_next(struct seq_file *m, void *p, loff_t *pos) 411102227b9SDaniel Bristot de Oliveira { 412102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *m_def = p; 413102227b9SDaniel Bristot de Oliveira 414102227b9SDaniel Bristot de Oliveira (*pos)++; 415102227b9SDaniel Bristot de Oliveira 416102227b9SDaniel Bristot de Oliveira list_for_each_entry_continue(m_def, &rv_monitors_list, list) { 417102227b9SDaniel Bristot de Oliveira if (m_def->monitor->enabled) 418102227b9SDaniel Bristot de Oliveira return m_def; 419102227b9SDaniel Bristot de Oliveira } 420102227b9SDaniel Bristot de Oliveira 421102227b9SDaniel Bristot de Oliveira return NULL; 422102227b9SDaniel Bristot de Oliveira } 423102227b9SDaniel Bristot de Oliveira 424102227b9SDaniel Bristot de Oliveira static void *enabled_monitors_start(struct seq_file *m, loff_t *pos) 425102227b9SDaniel Bristot de Oliveira { 426102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *m_def; 427102227b9SDaniel Bristot de Oliveira loff_t l; 428102227b9SDaniel Bristot de Oliveira 429102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 430102227b9SDaniel Bristot de Oliveira 431102227b9SDaniel Bristot de Oliveira if (list_empty(&rv_monitors_list)) 432102227b9SDaniel Bristot de Oliveira return NULL; 433102227b9SDaniel Bristot de Oliveira 434102227b9SDaniel Bristot de Oliveira m_def = list_entry(&rv_monitors_list, struct rv_monitor_def, list); 435102227b9SDaniel Bristot de Oliveira 436102227b9SDaniel Bristot de Oliveira for (l = 0; l <= *pos; ) { 437102227b9SDaniel Bristot de Oliveira m_def = enabled_monitors_next(m, m_def, &l); 438102227b9SDaniel Bristot de Oliveira if (!m_def) 439102227b9SDaniel Bristot de Oliveira break; 440102227b9SDaniel Bristot de Oliveira } 441102227b9SDaniel Bristot de Oliveira 442102227b9SDaniel Bristot de Oliveira return m_def; 443102227b9SDaniel Bristot de Oliveira } 444102227b9SDaniel Bristot de Oliveira 445102227b9SDaniel Bristot de Oliveira /* 446102227b9SDaniel Bristot de Oliveira * available/enabled monitors seq definition. 447102227b9SDaniel Bristot de Oliveira */ 448102227b9SDaniel Bristot de Oliveira static const struct seq_operations available_monitors_seq_ops = { 449102227b9SDaniel Bristot de Oliveira .start = available_monitors_start, 450102227b9SDaniel Bristot de Oliveira .next = available_monitors_next, 451102227b9SDaniel Bristot de Oliveira .stop = monitors_stop, 452102227b9SDaniel Bristot de Oliveira .show = monitors_show 453102227b9SDaniel Bristot de Oliveira }; 454102227b9SDaniel Bristot de Oliveira 455102227b9SDaniel Bristot de Oliveira static const struct seq_operations enabled_monitors_seq_ops = { 456102227b9SDaniel Bristot de Oliveira .start = enabled_monitors_start, 457102227b9SDaniel Bristot de Oliveira .next = enabled_monitors_next, 458102227b9SDaniel Bristot de Oliveira .stop = monitors_stop, 459102227b9SDaniel Bristot de Oliveira .show = monitors_show 460102227b9SDaniel Bristot de Oliveira }; 461102227b9SDaniel Bristot de Oliveira 462102227b9SDaniel Bristot de Oliveira /* 463102227b9SDaniel Bristot de Oliveira * available_monitors interface. 464102227b9SDaniel Bristot de Oliveira */ 465102227b9SDaniel Bristot de Oliveira static int available_monitors_open(struct inode *inode, struct file *file) 466102227b9SDaniel Bristot de Oliveira { 467102227b9SDaniel Bristot de Oliveira return seq_open(file, &available_monitors_seq_ops); 468102227b9SDaniel Bristot de Oliveira }; 469102227b9SDaniel Bristot de Oliveira 470102227b9SDaniel Bristot de Oliveira static const struct file_operations available_monitors_ops = { 471102227b9SDaniel Bristot de Oliveira .open = available_monitors_open, 472102227b9SDaniel Bristot de Oliveira .read = seq_read, 473102227b9SDaniel Bristot de Oliveira .llseek = seq_lseek, 474102227b9SDaniel Bristot de Oliveira .release = seq_release 475102227b9SDaniel Bristot de Oliveira }; 476102227b9SDaniel Bristot de Oliveira 477102227b9SDaniel Bristot de Oliveira /* 478102227b9SDaniel Bristot de Oliveira * enabled_monitors interface. 479102227b9SDaniel Bristot de Oliveira */ 480102227b9SDaniel Bristot de Oliveira static void disable_all_monitors(void) 481102227b9SDaniel Bristot de Oliveira { 482102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef; 483102227b9SDaniel Bristot de Oliveira int enabled = 0; 484102227b9SDaniel Bristot de Oliveira 485102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 486102227b9SDaniel Bristot de Oliveira 487102227b9SDaniel Bristot de Oliveira list_for_each_entry(mdef, &rv_monitors_list, list) 488102227b9SDaniel Bristot de Oliveira enabled += __rv_disable_monitor(mdef, false); 489102227b9SDaniel Bristot de Oliveira 490102227b9SDaniel Bristot de Oliveira if (enabled) { 491102227b9SDaniel Bristot de Oliveira /* 492102227b9SDaniel Bristot de Oliveira * Wait for the execution of all events to finish. 493102227b9SDaniel Bristot de Oliveira * Otherwise, the data used by the monitor could 494102227b9SDaniel Bristot de Oliveira * be inconsistent. i.e., if the monitor is re-enabled. 495102227b9SDaniel Bristot de Oliveira */ 496102227b9SDaniel Bristot de Oliveira tracepoint_synchronize_unregister(); 497102227b9SDaniel Bristot de Oliveira } 498102227b9SDaniel Bristot de Oliveira 499102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 500102227b9SDaniel Bristot de Oliveira } 501102227b9SDaniel Bristot de Oliveira 502102227b9SDaniel Bristot de Oliveira static int enabled_monitors_open(struct inode *inode, struct file *file) 503102227b9SDaniel Bristot de Oliveira { 504102227b9SDaniel Bristot de Oliveira if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) 505102227b9SDaniel Bristot de Oliveira disable_all_monitors(); 506102227b9SDaniel Bristot de Oliveira 507102227b9SDaniel Bristot de Oliveira return seq_open(file, &enabled_monitors_seq_ops); 508102227b9SDaniel Bristot de Oliveira }; 509102227b9SDaniel Bristot de Oliveira 510102227b9SDaniel Bristot de Oliveira static ssize_t enabled_monitors_write(struct file *filp, const char __user *user_buf, 511102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 512102227b9SDaniel Bristot de Oliveira { 513102227b9SDaniel Bristot de Oliveira char buff[MAX_RV_MONITOR_NAME_SIZE + 2]; 514102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef; 515102227b9SDaniel Bristot de Oliveira int retval = -EINVAL; 516102227b9SDaniel Bristot de Oliveira bool enable = true; 517ae3edea8SColin Ian King char *ptr; 518102227b9SDaniel Bristot de Oliveira int len; 519102227b9SDaniel Bristot de Oliveira 520102227b9SDaniel Bristot de Oliveira if (count < 1 || count > MAX_RV_MONITOR_NAME_SIZE + 1) 521102227b9SDaniel Bristot de Oliveira return -EINVAL; 522102227b9SDaniel Bristot de Oliveira 523102227b9SDaniel Bristot de Oliveira memset(buff, 0, sizeof(buff)); 524102227b9SDaniel Bristot de Oliveira 525102227b9SDaniel Bristot de Oliveira retval = simple_write_to_buffer(buff, sizeof(buff) - 1, ppos, user_buf, count); 526102227b9SDaniel Bristot de Oliveira if (retval < 0) 527102227b9SDaniel Bristot de Oliveira return -EFAULT; 528102227b9SDaniel Bristot de Oliveira 529102227b9SDaniel Bristot de Oliveira ptr = strim(buff); 530102227b9SDaniel Bristot de Oliveira 531102227b9SDaniel Bristot de Oliveira if (ptr[0] == '!') { 532102227b9SDaniel Bristot de Oliveira enable = false; 533102227b9SDaniel Bristot de Oliveira ptr++; 534102227b9SDaniel Bristot de Oliveira } 535102227b9SDaniel Bristot de Oliveira 536102227b9SDaniel Bristot de Oliveira len = strlen(ptr); 537102227b9SDaniel Bristot de Oliveira if (!len) 538102227b9SDaniel Bristot de Oliveira return count; 539102227b9SDaniel Bristot de Oliveira 540102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 541102227b9SDaniel Bristot de Oliveira 542102227b9SDaniel Bristot de Oliveira retval = -EINVAL; 543102227b9SDaniel Bristot de Oliveira 544102227b9SDaniel Bristot de Oliveira list_for_each_entry(mdef, &rv_monitors_list, list) { 545102227b9SDaniel Bristot de Oliveira if (strcmp(ptr, mdef->monitor->name) != 0) 546102227b9SDaniel Bristot de Oliveira continue; 547102227b9SDaniel Bristot de Oliveira 548102227b9SDaniel Bristot de Oliveira /* 549102227b9SDaniel Bristot de Oliveira * Monitor found! 550102227b9SDaniel Bristot de Oliveira */ 551102227b9SDaniel Bristot de Oliveira if (enable) 552102227b9SDaniel Bristot de Oliveira retval = rv_enable_monitor(mdef); 553102227b9SDaniel Bristot de Oliveira else 554102227b9SDaniel Bristot de Oliveira retval = rv_disable_monitor(mdef); 555102227b9SDaniel Bristot de Oliveira 556102227b9SDaniel Bristot de Oliveira if (!retval) 557102227b9SDaniel Bristot de Oliveira retval = count; 558102227b9SDaniel Bristot de Oliveira 559102227b9SDaniel Bristot de Oliveira break; 560102227b9SDaniel Bristot de Oliveira } 561102227b9SDaniel Bristot de Oliveira 562102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 563102227b9SDaniel Bristot de Oliveira return retval; 564102227b9SDaniel Bristot de Oliveira } 565102227b9SDaniel Bristot de Oliveira 566102227b9SDaniel Bristot de Oliveira static const struct file_operations enabled_monitors_ops = { 567102227b9SDaniel Bristot de Oliveira .open = enabled_monitors_open, 568102227b9SDaniel Bristot de Oliveira .read = seq_read, 569102227b9SDaniel Bristot de Oliveira .write = enabled_monitors_write, 570102227b9SDaniel Bristot de Oliveira .llseek = seq_lseek, 571102227b9SDaniel Bristot de Oliveira .release = seq_release, 572102227b9SDaniel Bristot de Oliveira }; 573102227b9SDaniel Bristot de Oliveira 574102227b9SDaniel Bristot de Oliveira /* 575102227b9SDaniel Bristot de Oliveira * Monitoring on global switcher! 576102227b9SDaniel Bristot de Oliveira */ 577102227b9SDaniel Bristot de Oliveira static bool __read_mostly monitoring_on; 578102227b9SDaniel Bristot de Oliveira 579102227b9SDaniel Bristot de Oliveira /** 580102227b9SDaniel Bristot de Oliveira * rv_monitoring_on - checks if monitoring is on 581102227b9SDaniel Bristot de Oliveira * 582102227b9SDaniel Bristot de Oliveira * Returns 1 if on, 0 otherwise. 583102227b9SDaniel Bristot de Oliveira */ 584102227b9SDaniel Bristot de Oliveira bool rv_monitoring_on(void) 585102227b9SDaniel Bristot de Oliveira { 586102227b9SDaniel Bristot de Oliveira /* Ensures that concurrent monitors read consistent monitoring_on */ 587102227b9SDaniel Bristot de Oliveira smp_rmb(); 588102227b9SDaniel Bristot de Oliveira return READ_ONCE(monitoring_on); 589102227b9SDaniel Bristot de Oliveira } 590102227b9SDaniel Bristot de Oliveira 591102227b9SDaniel Bristot de Oliveira /* 592102227b9SDaniel Bristot de Oliveira * monitoring_on general switcher. 593102227b9SDaniel Bristot de Oliveira */ 594102227b9SDaniel Bristot de Oliveira static ssize_t monitoring_on_read_data(struct file *filp, char __user *user_buf, 595102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 596102227b9SDaniel Bristot de Oliveira { 597102227b9SDaniel Bristot de Oliveira const char *buff; 598102227b9SDaniel Bristot de Oliveira 599102227b9SDaniel Bristot de Oliveira buff = rv_monitoring_on() ? "1\n" : "0\n"; 600102227b9SDaniel Bristot de Oliveira 601102227b9SDaniel Bristot de Oliveira return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff) + 1); 602102227b9SDaniel Bristot de Oliveira } 603102227b9SDaniel Bristot de Oliveira 604102227b9SDaniel Bristot de Oliveira static void turn_monitoring_off(void) 605102227b9SDaniel Bristot de Oliveira { 606102227b9SDaniel Bristot de Oliveira WRITE_ONCE(monitoring_on, false); 607102227b9SDaniel Bristot de Oliveira /* Ensures that concurrent monitors read consistent monitoring_on */ 608102227b9SDaniel Bristot de Oliveira smp_wmb(); 609102227b9SDaniel Bristot de Oliveira } 610102227b9SDaniel Bristot de Oliveira 611102227b9SDaniel Bristot de Oliveira static void reset_all_monitors(void) 612102227b9SDaniel Bristot de Oliveira { 613102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef; 614102227b9SDaniel Bristot de Oliveira 615102227b9SDaniel Bristot de Oliveira list_for_each_entry(mdef, &rv_monitors_list, list) { 616102227b9SDaniel Bristot de Oliveira if (mdef->monitor->enabled) 617102227b9SDaniel Bristot de Oliveira mdef->monitor->reset(); 618102227b9SDaniel Bristot de Oliveira } 619102227b9SDaniel Bristot de Oliveira } 620102227b9SDaniel Bristot de Oliveira 621102227b9SDaniel Bristot de Oliveira static void turn_monitoring_on(void) 622102227b9SDaniel Bristot de Oliveira { 623102227b9SDaniel Bristot de Oliveira WRITE_ONCE(monitoring_on, true); 624102227b9SDaniel Bristot de Oliveira /* Ensures that concurrent monitors read consistent monitoring_on */ 625102227b9SDaniel Bristot de Oliveira smp_wmb(); 626102227b9SDaniel Bristot de Oliveira } 627102227b9SDaniel Bristot de Oliveira 628102227b9SDaniel Bristot de Oliveira static void turn_monitoring_on_with_reset(void) 629102227b9SDaniel Bristot de Oliveira { 630102227b9SDaniel Bristot de Oliveira lockdep_assert_held(&rv_interface_lock); 631102227b9SDaniel Bristot de Oliveira 632102227b9SDaniel Bristot de Oliveira if (rv_monitoring_on()) 633102227b9SDaniel Bristot de Oliveira return; 634102227b9SDaniel Bristot de Oliveira 635102227b9SDaniel Bristot de Oliveira /* 636102227b9SDaniel Bristot de Oliveira * Monitors might be out of sync with the system if events were not 637102227b9SDaniel Bristot de Oliveira * processed because of !rv_monitoring_on(). 638102227b9SDaniel Bristot de Oliveira * 639102227b9SDaniel Bristot de Oliveira * Reset all monitors, forcing a re-sync. 640102227b9SDaniel Bristot de Oliveira */ 641102227b9SDaniel Bristot de Oliveira reset_all_monitors(); 642102227b9SDaniel Bristot de Oliveira turn_monitoring_on(); 643102227b9SDaniel Bristot de Oliveira } 644102227b9SDaniel Bristot de Oliveira 645102227b9SDaniel Bristot de Oliveira static ssize_t monitoring_on_write_data(struct file *filp, const char __user *user_buf, 646102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 647102227b9SDaniel Bristot de Oliveira { 648102227b9SDaniel Bristot de Oliveira int retval; 649102227b9SDaniel Bristot de Oliveira bool val; 650102227b9SDaniel Bristot de Oliveira 651102227b9SDaniel Bristot de Oliveira retval = kstrtobool_from_user(user_buf, count, &val); 652102227b9SDaniel Bristot de Oliveira if (retval) 653102227b9SDaniel Bristot de Oliveira return retval; 654102227b9SDaniel Bristot de Oliveira 655102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 656102227b9SDaniel Bristot de Oliveira 657102227b9SDaniel Bristot de Oliveira if (val) 658102227b9SDaniel Bristot de Oliveira turn_monitoring_on_with_reset(); 659102227b9SDaniel Bristot de Oliveira else 660102227b9SDaniel Bristot de Oliveira turn_monitoring_off(); 661102227b9SDaniel Bristot de Oliveira 662102227b9SDaniel Bristot de Oliveira /* 663102227b9SDaniel Bristot de Oliveira * Wait for the execution of all events to finish 664102227b9SDaniel Bristot de Oliveira * before returning to user-space. 665102227b9SDaniel Bristot de Oliveira */ 666102227b9SDaniel Bristot de Oliveira tracepoint_synchronize_unregister(); 667102227b9SDaniel Bristot de Oliveira 668102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 669102227b9SDaniel Bristot de Oliveira 670102227b9SDaniel Bristot de Oliveira return count; 671102227b9SDaniel Bristot de Oliveira } 672102227b9SDaniel Bristot de Oliveira 673102227b9SDaniel Bristot de Oliveira static const struct file_operations monitoring_on_fops = { 674102227b9SDaniel Bristot de Oliveira .open = simple_open, 675102227b9SDaniel Bristot de Oliveira .write = monitoring_on_write_data, 676102227b9SDaniel Bristot de Oliveira .read = monitoring_on_read_data, 677102227b9SDaniel Bristot de Oliveira }; 678102227b9SDaniel Bristot de Oliveira 679102227b9SDaniel Bristot de Oliveira static void destroy_monitor_dir(struct rv_monitor_def *mdef) 680102227b9SDaniel Bristot de Oliveira { 68104acadcbSDaniel Bristot de Oliveira reactor_cleanup_monitor(mdef); 682102227b9SDaniel Bristot de Oliveira rv_remove(mdef->root_d); 683102227b9SDaniel Bristot de Oliveira } 684102227b9SDaniel Bristot de Oliveira 685102227b9SDaniel Bristot de Oliveira /** 686102227b9SDaniel Bristot de Oliveira * rv_register_monitor - register a rv monitor. 687102227b9SDaniel Bristot de Oliveira * @monitor: The rv_monitor to be registered. 688102227b9SDaniel Bristot de Oliveira * 689102227b9SDaniel Bristot de Oliveira * Returns 0 if successful, error otherwise. 690102227b9SDaniel Bristot de Oliveira */ 691102227b9SDaniel Bristot de Oliveira int rv_register_monitor(struct rv_monitor *monitor) 692102227b9SDaniel Bristot de Oliveira { 693102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *r; 694102227b9SDaniel Bristot de Oliveira int retval = 0; 695102227b9SDaniel Bristot de Oliveira 696102227b9SDaniel Bristot de Oliveira if (strlen(monitor->name) >= MAX_RV_MONITOR_NAME_SIZE) { 697102227b9SDaniel Bristot de Oliveira pr_info("Monitor %s has a name longer than %d\n", monitor->name, 698102227b9SDaniel Bristot de Oliveira MAX_RV_MONITOR_NAME_SIZE); 699102227b9SDaniel Bristot de Oliveira return -1; 700102227b9SDaniel Bristot de Oliveira } 701102227b9SDaniel Bristot de Oliveira 702102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 703102227b9SDaniel Bristot de Oliveira 704102227b9SDaniel Bristot de Oliveira list_for_each_entry(r, &rv_monitors_list, list) { 705102227b9SDaniel Bristot de Oliveira if (strcmp(monitor->name, r->monitor->name) == 0) { 706102227b9SDaniel Bristot de Oliveira pr_info("Monitor %s is already registered\n", monitor->name); 707102227b9SDaniel Bristot de Oliveira retval = -1; 708102227b9SDaniel Bristot de Oliveira goto out_unlock; 709102227b9SDaniel Bristot de Oliveira } 710102227b9SDaniel Bristot de Oliveira } 711102227b9SDaniel Bristot de Oliveira 712102227b9SDaniel Bristot de Oliveira r = kzalloc(sizeof(struct rv_monitor_def), GFP_KERNEL); 713102227b9SDaniel Bristot de Oliveira if (!r) { 714102227b9SDaniel Bristot de Oliveira retval = -ENOMEM; 715102227b9SDaniel Bristot de Oliveira goto out_unlock; 716102227b9SDaniel Bristot de Oliveira } 717102227b9SDaniel Bristot de Oliveira 718102227b9SDaniel Bristot de Oliveira r->monitor = monitor; 719102227b9SDaniel Bristot de Oliveira 720102227b9SDaniel Bristot de Oliveira retval = create_monitor_dir(r); 721102227b9SDaniel Bristot de Oliveira if (retval) { 722102227b9SDaniel Bristot de Oliveira kfree(r); 723102227b9SDaniel Bristot de Oliveira goto out_unlock; 724102227b9SDaniel Bristot de Oliveira } 725102227b9SDaniel Bristot de Oliveira 726102227b9SDaniel Bristot de Oliveira list_add_tail(&r->list, &rv_monitors_list); 727102227b9SDaniel Bristot de Oliveira 728102227b9SDaniel Bristot de Oliveira out_unlock: 729102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 730102227b9SDaniel Bristot de Oliveira return retval; 731102227b9SDaniel Bristot de Oliveira } 732102227b9SDaniel Bristot de Oliveira 733102227b9SDaniel Bristot de Oliveira /** 734102227b9SDaniel Bristot de Oliveira * rv_unregister_monitor - unregister a rv monitor. 735102227b9SDaniel Bristot de Oliveira * @monitor: The rv_monitor to be unregistered. 736102227b9SDaniel Bristot de Oliveira * 737102227b9SDaniel Bristot de Oliveira * Returns 0 if successful, error otherwise. 738102227b9SDaniel Bristot de Oliveira */ 739102227b9SDaniel Bristot de Oliveira int rv_unregister_monitor(struct rv_monitor *monitor) 740102227b9SDaniel Bristot de Oliveira { 741102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *ptr, *next; 742102227b9SDaniel Bristot de Oliveira 743102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 744102227b9SDaniel Bristot de Oliveira 745102227b9SDaniel Bristot de Oliveira list_for_each_entry_safe(ptr, next, &rv_monitors_list, list) { 746102227b9SDaniel Bristot de Oliveira if (strcmp(monitor->name, ptr->monitor->name) == 0) { 747102227b9SDaniel Bristot de Oliveira rv_disable_monitor(ptr); 748102227b9SDaniel Bristot de Oliveira list_del(&ptr->list); 749102227b9SDaniel Bristot de Oliveira destroy_monitor_dir(ptr); 750102227b9SDaniel Bristot de Oliveira } 751102227b9SDaniel Bristot de Oliveira } 752102227b9SDaniel Bristot de Oliveira 753102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 754102227b9SDaniel Bristot de Oliveira return 0; 755102227b9SDaniel Bristot de Oliveira } 756102227b9SDaniel Bristot de Oliveira 757102227b9SDaniel Bristot de Oliveira int __init rv_init_interface(void) 758102227b9SDaniel Bristot de Oliveira { 759102227b9SDaniel Bristot de Oliveira struct dentry *tmp; 76004acadcbSDaniel Bristot de Oliveira int retval; 761102227b9SDaniel Bristot de Oliveira 762102227b9SDaniel Bristot de Oliveira rv_root.root_dir = rv_create_dir("rv", NULL); 763102227b9SDaniel Bristot de Oliveira if (!rv_root.root_dir) 764102227b9SDaniel Bristot de Oliveira goto out_err; 765102227b9SDaniel Bristot de Oliveira 766102227b9SDaniel Bristot de Oliveira rv_root.monitors_dir = rv_create_dir("monitors", rv_root.root_dir); 767102227b9SDaniel Bristot de Oliveira if (!rv_root.monitors_dir) 768102227b9SDaniel Bristot de Oliveira goto out_err; 769102227b9SDaniel Bristot de Oliveira 770102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("available_monitors", RV_MODE_READ, rv_root.root_dir, NULL, 771102227b9SDaniel Bristot de Oliveira &available_monitors_ops); 772102227b9SDaniel Bristot de Oliveira if (!tmp) 773102227b9SDaniel Bristot de Oliveira goto out_err; 774102227b9SDaniel Bristot de Oliveira 775102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("enabled_monitors", RV_MODE_WRITE, rv_root.root_dir, NULL, 776102227b9SDaniel Bristot de Oliveira &enabled_monitors_ops); 777102227b9SDaniel Bristot de Oliveira if (!tmp) 778102227b9SDaniel Bristot de Oliveira goto out_err; 779102227b9SDaniel Bristot de Oliveira 780102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("monitoring_on", RV_MODE_WRITE, rv_root.root_dir, NULL, 781102227b9SDaniel Bristot de Oliveira &monitoring_on_fops); 782102227b9SDaniel Bristot de Oliveira if (!tmp) 783102227b9SDaniel Bristot de Oliveira goto out_err; 78404acadcbSDaniel Bristot de Oliveira retval = init_rv_reactors(rv_root.root_dir); 78504acadcbSDaniel Bristot de Oliveira if (retval) 78604acadcbSDaniel Bristot de Oliveira goto out_err; 787102227b9SDaniel Bristot de Oliveira 788102227b9SDaniel Bristot de Oliveira turn_monitoring_on(); 789102227b9SDaniel Bristot de Oliveira 790102227b9SDaniel Bristot de Oliveira return 0; 791102227b9SDaniel Bristot de Oliveira 792102227b9SDaniel Bristot de Oliveira out_err: 793102227b9SDaniel Bristot de Oliveira rv_remove(rv_root.root_dir); 794102227b9SDaniel Bristot de Oliveira printk(KERN_ERR "RV: Error while creating the RV interface\n"); 795102227b9SDaniel Bristot de Oliveira return 1; 796102227b9SDaniel Bristot de Oliveira } 797