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 248102227b9SDaniel Bristot de Oliveira * 249102227b9SDaniel Bristot de Oliveira * Returns 0 on success. 250102227b9SDaniel Bristot de Oliveira */ 251102227b9SDaniel Bristot de Oliveira int rv_disable_monitor(struct rv_monitor_def *mdef) 252102227b9SDaniel Bristot de Oliveira { 253102227b9SDaniel Bristot de Oliveira __rv_disable_monitor(mdef, true); 254102227b9SDaniel Bristot de Oliveira return 0; 255102227b9SDaniel Bristot de Oliveira } 256102227b9SDaniel Bristot de Oliveira 257102227b9SDaniel Bristot de Oliveira /** 258102227b9SDaniel Bristot de Oliveira * rv_enable_monitor - enable a given runtime monitor 259102227b9SDaniel Bristot de Oliveira * 260102227b9SDaniel Bristot de Oliveira * Returns 0 on success, error otherwise. 261102227b9SDaniel Bristot de Oliveira */ 262102227b9SDaniel Bristot de Oliveira int rv_enable_monitor(struct rv_monitor_def *mdef) 263102227b9SDaniel Bristot de Oliveira { 264102227b9SDaniel Bristot de Oliveira int retval; 265102227b9SDaniel Bristot de Oliveira 266102227b9SDaniel Bristot de Oliveira lockdep_assert_held(&rv_interface_lock); 267102227b9SDaniel Bristot de Oliveira 268102227b9SDaniel Bristot de Oliveira if (mdef->monitor->enabled) 269102227b9SDaniel Bristot de Oliveira return 0; 270102227b9SDaniel Bristot de Oliveira 271102227b9SDaniel Bristot de Oliveira retval = mdef->monitor->enable(); 272102227b9SDaniel Bristot de Oliveira 273102227b9SDaniel Bristot de Oliveira if (!retval) 274102227b9SDaniel Bristot de Oliveira mdef->monitor->enabled = 1; 275102227b9SDaniel Bristot de Oliveira 276102227b9SDaniel Bristot de Oliveira return retval; 277102227b9SDaniel Bristot de Oliveira } 278102227b9SDaniel Bristot de Oliveira 279102227b9SDaniel Bristot de Oliveira /* 280102227b9SDaniel Bristot de Oliveira * interface for enabling/disabling a monitor. 281102227b9SDaniel Bristot de Oliveira */ 282102227b9SDaniel Bristot de Oliveira static ssize_t monitor_enable_write_data(struct file *filp, const char __user *user_buf, 283102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 284102227b9SDaniel Bristot de Oliveira { 285102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef = filp->private_data; 286102227b9SDaniel Bristot de Oliveira int retval; 287102227b9SDaniel Bristot de Oliveira bool val; 288102227b9SDaniel Bristot de Oliveira 289102227b9SDaniel Bristot de Oliveira retval = kstrtobool_from_user(user_buf, count, &val); 290102227b9SDaniel Bristot de Oliveira if (retval) 291102227b9SDaniel Bristot de Oliveira return retval; 292102227b9SDaniel Bristot de Oliveira 293102227b9SDaniel Bristot de Oliveira retval = count; 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 .llseek = no_llseek, 310102227b9SDaniel Bristot de Oliveira .write = monitor_enable_write_data, 311102227b9SDaniel Bristot de Oliveira .read = monitor_enable_read_data, 312102227b9SDaniel Bristot de Oliveira }; 313102227b9SDaniel Bristot de Oliveira 314102227b9SDaniel Bristot de Oliveira /* 315102227b9SDaniel Bristot de Oliveira * Interface to read monitors description. 316102227b9SDaniel Bristot de Oliveira */ 317102227b9SDaniel Bristot de Oliveira static ssize_t monitor_desc_read_data(struct file *filp, char __user *user_buf, size_t count, 318102227b9SDaniel Bristot de Oliveira loff_t *ppos) 319102227b9SDaniel Bristot de Oliveira { 320102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef = filp->private_data; 321102227b9SDaniel Bristot de Oliveira char buff[256]; 322102227b9SDaniel Bristot de Oliveira 323102227b9SDaniel Bristot de Oliveira memset(buff, 0, sizeof(buff)); 324102227b9SDaniel Bristot de Oliveira 325102227b9SDaniel Bristot de Oliveira snprintf(buff, sizeof(buff), "%s\n", mdef->monitor->description); 326102227b9SDaniel Bristot de Oliveira 327102227b9SDaniel Bristot de Oliveira return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff) + 1); 328102227b9SDaniel Bristot de Oliveira } 329102227b9SDaniel Bristot de Oliveira 330102227b9SDaniel Bristot de Oliveira static const struct file_operations interface_desc_fops = { 331102227b9SDaniel Bristot de Oliveira .open = simple_open, 332102227b9SDaniel Bristot de Oliveira .llseek = no_llseek, 333102227b9SDaniel Bristot de Oliveira .read = monitor_desc_read_data, 334102227b9SDaniel Bristot de Oliveira }; 335102227b9SDaniel Bristot de Oliveira 336102227b9SDaniel Bristot de Oliveira /* 337102227b9SDaniel Bristot de Oliveira * During the registration of a monitor, this function creates 338102227b9SDaniel Bristot de Oliveira * the monitor dir, where the specific options of the monitor 339102227b9SDaniel Bristot de Oliveira * are exposed. 340102227b9SDaniel Bristot de Oliveira */ 341102227b9SDaniel Bristot de Oliveira static int create_monitor_dir(struct rv_monitor_def *mdef) 342102227b9SDaniel Bristot de Oliveira { 343102227b9SDaniel Bristot de Oliveira struct dentry *root = get_monitors_root(); 344102227b9SDaniel Bristot de Oliveira const char *name = mdef->monitor->name; 345102227b9SDaniel Bristot de Oliveira struct dentry *tmp; 346102227b9SDaniel Bristot de Oliveira int retval; 347102227b9SDaniel Bristot de Oliveira 348102227b9SDaniel Bristot de Oliveira mdef->root_d = rv_create_dir(name, root); 349102227b9SDaniel Bristot de Oliveira if (!mdef->root_d) 350102227b9SDaniel Bristot de Oliveira return -ENOMEM; 351102227b9SDaniel Bristot de Oliveira 352102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("enable", RV_MODE_WRITE, mdef->root_d, mdef, &interface_enable_fops); 353102227b9SDaniel Bristot de Oliveira if (!tmp) { 354102227b9SDaniel Bristot de Oliveira retval = -ENOMEM; 355102227b9SDaniel Bristot de Oliveira goto out_remove_root; 356102227b9SDaniel Bristot de Oliveira } 357102227b9SDaniel Bristot de Oliveira 358102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("desc", RV_MODE_READ, mdef->root_d, mdef, &interface_desc_fops); 359102227b9SDaniel Bristot de Oliveira if (!tmp) { 360102227b9SDaniel Bristot de Oliveira retval = -ENOMEM; 361102227b9SDaniel Bristot de Oliveira goto out_remove_root; 362102227b9SDaniel Bristot de Oliveira } 363102227b9SDaniel Bristot de Oliveira 36404acadcbSDaniel Bristot de Oliveira retval = reactor_populate_monitor(mdef); 36504acadcbSDaniel Bristot de Oliveira if (retval) 36604acadcbSDaniel Bristot de Oliveira goto out_remove_root; 36704acadcbSDaniel Bristot de Oliveira 368102227b9SDaniel Bristot de Oliveira return 0; 369102227b9SDaniel Bristot de Oliveira 370102227b9SDaniel Bristot de Oliveira out_remove_root: 371102227b9SDaniel Bristot de Oliveira rv_remove(mdef->root_d); 372102227b9SDaniel Bristot de Oliveira return retval; 373102227b9SDaniel Bristot de Oliveira } 374102227b9SDaniel Bristot de Oliveira 375102227b9SDaniel Bristot de Oliveira /* 376102227b9SDaniel Bristot de Oliveira * Available/Enable monitor shared seq functions. 377102227b9SDaniel Bristot de Oliveira */ 378102227b9SDaniel Bristot de Oliveira static int monitors_show(struct seq_file *m, void *p) 379102227b9SDaniel Bristot de Oliveira { 380102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mon_def = p; 381102227b9SDaniel Bristot de Oliveira 382102227b9SDaniel Bristot de Oliveira seq_printf(m, "%s\n", mon_def->monitor->name); 383102227b9SDaniel Bristot de Oliveira return 0; 384102227b9SDaniel Bristot de Oliveira } 385102227b9SDaniel Bristot de Oliveira 386102227b9SDaniel Bristot de Oliveira /* 387102227b9SDaniel Bristot de Oliveira * Used by the seq file operations at the end of a read 388102227b9SDaniel Bristot de Oliveira * operation. 389102227b9SDaniel Bristot de Oliveira */ 390102227b9SDaniel Bristot de Oliveira static void monitors_stop(struct seq_file *m, void *p) 391102227b9SDaniel Bristot de Oliveira { 392102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 393102227b9SDaniel Bristot de Oliveira } 394102227b9SDaniel Bristot de Oliveira 395102227b9SDaniel Bristot de Oliveira /* 396102227b9SDaniel Bristot de Oliveira * Available monitor seq functions. 397102227b9SDaniel Bristot de Oliveira */ 398102227b9SDaniel Bristot de Oliveira static void *available_monitors_start(struct seq_file *m, loff_t *pos) 399102227b9SDaniel Bristot de Oliveira { 400102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 401102227b9SDaniel Bristot de Oliveira return seq_list_start(&rv_monitors_list, *pos); 402102227b9SDaniel Bristot de Oliveira } 403102227b9SDaniel Bristot de Oliveira 404102227b9SDaniel Bristot de Oliveira static void *available_monitors_next(struct seq_file *m, void *p, loff_t *pos) 405102227b9SDaniel Bristot de Oliveira { 406102227b9SDaniel Bristot de Oliveira return seq_list_next(p, &rv_monitors_list, pos); 407102227b9SDaniel Bristot de Oliveira } 408102227b9SDaniel Bristot de Oliveira 409102227b9SDaniel Bristot de Oliveira /* 410102227b9SDaniel Bristot de Oliveira * Enable monitor seq functions. 411102227b9SDaniel Bristot de Oliveira */ 412102227b9SDaniel Bristot de Oliveira static void *enabled_monitors_next(struct seq_file *m, void *p, loff_t *pos) 413102227b9SDaniel Bristot de Oliveira { 414102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *m_def = p; 415102227b9SDaniel Bristot de Oliveira 416102227b9SDaniel Bristot de Oliveira (*pos)++; 417102227b9SDaniel Bristot de Oliveira 418102227b9SDaniel Bristot de Oliveira list_for_each_entry_continue(m_def, &rv_monitors_list, list) { 419102227b9SDaniel Bristot de Oliveira if (m_def->monitor->enabled) 420102227b9SDaniel Bristot de Oliveira return m_def; 421102227b9SDaniel Bristot de Oliveira } 422102227b9SDaniel Bristot de Oliveira 423102227b9SDaniel Bristot de Oliveira return NULL; 424102227b9SDaniel Bristot de Oliveira } 425102227b9SDaniel Bristot de Oliveira 426102227b9SDaniel Bristot de Oliveira static void *enabled_monitors_start(struct seq_file *m, loff_t *pos) 427102227b9SDaniel Bristot de Oliveira { 428102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *m_def; 429102227b9SDaniel Bristot de Oliveira loff_t l; 430102227b9SDaniel Bristot de Oliveira 431102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 432102227b9SDaniel Bristot de Oliveira 433102227b9SDaniel Bristot de Oliveira if (list_empty(&rv_monitors_list)) 434102227b9SDaniel Bristot de Oliveira return NULL; 435102227b9SDaniel Bristot de Oliveira 436102227b9SDaniel Bristot de Oliveira m_def = list_entry(&rv_monitors_list, struct rv_monitor_def, list); 437102227b9SDaniel Bristot de Oliveira 438102227b9SDaniel Bristot de Oliveira for (l = 0; l <= *pos; ) { 439102227b9SDaniel Bristot de Oliveira m_def = enabled_monitors_next(m, m_def, &l); 440102227b9SDaniel Bristot de Oliveira if (!m_def) 441102227b9SDaniel Bristot de Oliveira break; 442102227b9SDaniel Bristot de Oliveira } 443102227b9SDaniel Bristot de Oliveira 444102227b9SDaniel Bristot de Oliveira return m_def; 445102227b9SDaniel Bristot de Oliveira } 446102227b9SDaniel Bristot de Oliveira 447102227b9SDaniel Bristot de Oliveira /* 448102227b9SDaniel Bristot de Oliveira * available/enabled monitors seq definition. 449102227b9SDaniel Bristot de Oliveira */ 450102227b9SDaniel Bristot de Oliveira static const struct seq_operations available_monitors_seq_ops = { 451102227b9SDaniel Bristot de Oliveira .start = available_monitors_start, 452102227b9SDaniel Bristot de Oliveira .next = available_monitors_next, 453102227b9SDaniel Bristot de Oliveira .stop = monitors_stop, 454102227b9SDaniel Bristot de Oliveira .show = monitors_show 455102227b9SDaniel Bristot de Oliveira }; 456102227b9SDaniel Bristot de Oliveira 457102227b9SDaniel Bristot de Oliveira static const struct seq_operations enabled_monitors_seq_ops = { 458102227b9SDaniel Bristot de Oliveira .start = enabled_monitors_start, 459102227b9SDaniel Bristot de Oliveira .next = enabled_monitors_next, 460102227b9SDaniel Bristot de Oliveira .stop = monitors_stop, 461102227b9SDaniel Bristot de Oliveira .show = monitors_show 462102227b9SDaniel Bristot de Oliveira }; 463102227b9SDaniel Bristot de Oliveira 464102227b9SDaniel Bristot de Oliveira /* 465102227b9SDaniel Bristot de Oliveira * available_monitors interface. 466102227b9SDaniel Bristot de Oliveira */ 467102227b9SDaniel Bristot de Oliveira static int available_monitors_open(struct inode *inode, struct file *file) 468102227b9SDaniel Bristot de Oliveira { 469102227b9SDaniel Bristot de Oliveira return seq_open(file, &available_monitors_seq_ops); 470102227b9SDaniel Bristot de Oliveira }; 471102227b9SDaniel Bristot de Oliveira 472102227b9SDaniel Bristot de Oliveira static const struct file_operations available_monitors_ops = { 473102227b9SDaniel Bristot de Oliveira .open = available_monitors_open, 474102227b9SDaniel Bristot de Oliveira .read = seq_read, 475102227b9SDaniel Bristot de Oliveira .llseek = seq_lseek, 476102227b9SDaniel Bristot de Oliveira .release = seq_release 477102227b9SDaniel Bristot de Oliveira }; 478102227b9SDaniel Bristot de Oliveira 479102227b9SDaniel Bristot de Oliveira /* 480102227b9SDaniel Bristot de Oliveira * enabled_monitors interface. 481102227b9SDaniel Bristot de Oliveira */ 482102227b9SDaniel Bristot de Oliveira static void disable_all_monitors(void) 483102227b9SDaniel Bristot de Oliveira { 484102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef; 485102227b9SDaniel Bristot de Oliveira int enabled = 0; 486102227b9SDaniel Bristot de Oliveira 487102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 488102227b9SDaniel Bristot de Oliveira 489102227b9SDaniel Bristot de Oliveira list_for_each_entry(mdef, &rv_monitors_list, list) 490102227b9SDaniel Bristot de Oliveira enabled += __rv_disable_monitor(mdef, false); 491102227b9SDaniel Bristot de Oliveira 492102227b9SDaniel Bristot de Oliveira if (enabled) { 493102227b9SDaniel Bristot de Oliveira /* 494102227b9SDaniel Bristot de Oliveira * Wait for the execution of all events to finish. 495102227b9SDaniel Bristot de Oliveira * Otherwise, the data used by the monitor could 496102227b9SDaniel Bristot de Oliveira * be inconsistent. i.e., if the monitor is re-enabled. 497102227b9SDaniel Bristot de Oliveira */ 498102227b9SDaniel Bristot de Oliveira tracepoint_synchronize_unregister(); 499102227b9SDaniel Bristot de Oliveira } 500102227b9SDaniel Bristot de Oliveira 501102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 502102227b9SDaniel Bristot de Oliveira } 503102227b9SDaniel Bristot de Oliveira 504102227b9SDaniel Bristot de Oliveira static int enabled_monitors_open(struct inode *inode, struct file *file) 505102227b9SDaniel Bristot de Oliveira { 506102227b9SDaniel Bristot de Oliveira if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) 507102227b9SDaniel Bristot de Oliveira disable_all_monitors(); 508102227b9SDaniel Bristot de Oliveira 509102227b9SDaniel Bristot de Oliveira return seq_open(file, &enabled_monitors_seq_ops); 510102227b9SDaniel Bristot de Oliveira }; 511102227b9SDaniel Bristot de Oliveira 512102227b9SDaniel Bristot de Oliveira static ssize_t enabled_monitors_write(struct file *filp, const char __user *user_buf, 513102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 514102227b9SDaniel Bristot de Oliveira { 515102227b9SDaniel Bristot de Oliveira char buff[MAX_RV_MONITOR_NAME_SIZE + 2]; 516102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef; 517102227b9SDaniel Bristot de Oliveira int retval = -EINVAL; 518102227b9SDaniel Bristot de Oliveira bool enable = true; 519*ae3edea8SColin Ian King char *ptr; 520102227b9SDaniel Bristot de Oliveira int len; 521102227b9SDaniel Bristot de Oliveira 522102227b9SDaniel Bristot de Oliveira if (count < 1 || count > MAX_RV_MONITOR_NAME_SIZE + 1) 523102227b9SDaniel Bristot de Oliveira return -EINVAL; 524102227b9SDaniel Bristot de Oliveira 525102227b9SDaniel Bristot de Oliveira memset(buff, 0, sizeof(buff)); 526102227b9SDaniel Bristot de Oliveira 527102227b9SDaniel Bristot de Oliveira retval = simple_write_to_buffer(buff, sizeof(buff) - 1, ppos, user_buf, count); 528102227b9SDaniel Bristot de Oliveira if (retval < 0) 529102227b9SDaniel Bristot de Oliveira return -EFAULT; 530102227b9SDaniel Bristot de Oliveira 531102227b9SDaniel Bristot de Oliveira ptr = strim(buff); 532102227b9SDaniel Bristot de Oliveira 533102227b9SDaniel Bristot de Oliveira if (ptr[0] == '!') { 534102227b9SDaniel Bristot de Oliveira enable = false; 535102227b9SDaniel Bristot de Oliveira ptr++; 536102227b9SDaniel Bristot de Oliveira } 537102227b9SDaniel Bristot de Oliveira 538102227b9SDaniel Bristot de Oliveira len = strlen(ptr); 539102227b9SDaniel Bristot de Oliveira if (!len) 540102227b9SDaniel Bristot de Oliveira return count; 541102227b9SDaniel Bristot de Oliveira 542102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 543102227b9SDaniel Bristot de Oliveira 544102227b9SDaniel Bristot de Oliveira retval = -EINVAL; 545102227b9SDaniel Bristot de Oliveira 546102227b9SDaniel Bristot de Oliveira list_for_each_entry(mdef, &rv_monitors_list, list) { 547102227b9SDaniel Bristot de Oliveira if (strcmp(ptr, mdef->monitor->name) != 0) 548102227b9SDaniel Bristot de Oliveira continue; 549102227b9SDaniel Bristot de Oliveira 550102227b9SDaniel Bristot de Oliveira /* 551102227b9SDaniel Bristot de Oliveira * Monitor found! 552102227b9SDaniel Bristot de Oliveira */ 553102227b9SDaniel Bristot de Oliveira if (enable) 554102227b9SDaniel Bristot de Oliveira retval = rv_enable_monitor(mdef); 555102227b9SDaniel Bristot de Oliveira else 556102227b9SDaniel Bristot de Oliveira retval = rv_disable_monitor(mdef); 557102227b9SDaniel Bristot de Oliveira 558102227b9SDaniel Bristot de Oliveira if (!retval) 559102227b9SDaniel Bristot de Oliveira retval = count; 560102227b9SDaniel Bristot de Oliveira 561102227b9SDaniel Bristot de Oliveira break; 562102227b9SDaniel Bristot de Oliveira } 563102227b9SDaniel Bristot de Oliveira 564102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 565102227b9SDaniel Bristot de Oliveira return retval; 566102227b9SDaniel Bristot de Oliveira } 567102227b9SDaniel Bristot de Oliveira 568102227b9SDaniel Bristot de Oliveira static const struct file_operations enabled_monitors_ops = { 569102227b9SDaniel Bristot de Oliveira .open = enabled_monitors_open, 570102227b9SDaniel Bristot de Oliveira .read = seq_read, 571102227b9SDaniel Bristot de Oliveira .write = enabled_monitors_write, 572102227b9SDaniel Bristot de Oliveira .llseek = seq_lseek, 573102227b9SDaniel Bristot de Oliveira .release = seq_release, 574102227b9SDaniel Bristot de Oliveira }; 575102227b9SDaniel Bristot de Oliveira 576102227b9SDaniel Bristot de Oliveira /* 577102227b9SDaniel Bristot de Oliveira * Monitoring on global switcher! 578102227b9SDaniel Bristot de Oliveira */ 579102227b9SDaniel Bristot de Oliveira static bool __read_mostly monitoring_on; 580102227b9SDaniel Bristot de Oliveira 581102227b9SDaniel Bristot de Oliveira /** 582102227b9SDaniel Bristot de Oliveira * rv_monitoring_on - checks if monitoring is on 583102227b9SDaniel Bristot de Oliveira * 584102227b9SDaniel Bristot de Oliveira * Returns 1 if on, 0 otherwise. 585102227b9SDaniel Bristot de Oliveira */ 586102227b9SDaniel Bristot de Oliveira bool rv_monitoring_on(void) 587102227b9SDaniel Bristot de Oliveira { 588102227b9SDaniel Bristot de Oliveira /* Ensures that concurrent monitors read consistent monitoring_on */ 589102227b9SDaniel Bristot de Oliveira smp_rmb(); 590102227b9SDaniel Bristot de Oliveira return READ_ONCE(monitoring_on); 591102227b9SDaniel Bristot de Oliveira } 592102227b9SDaniel Bristot de Oliveira 593102227b9SDaniel Bristot de Oliveira /* 594102227b9SDaniel Bristot de Oliveira * monitoring_on general switcher. 595102227b9SDaniel Bristot de Oliveira */ 596102227b9SDaniel Bristot de Oliveira static ssize_t monitoring_on_read_data(struct file *filp, char __user *user_buf, 597102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 598102227b9SDaniel Bristot de Oliveira { 599102227b9SDaniel Bristot de Oliveira const char *buff; 600102227b9SDaniel Bristot de Oliveira 601102227b9SDaniel Bristot de Oliveira buff = rv_monitoring_on() ? "1\n" : "0\n"; 602102227b9SDaniel Bristot de Oliveira 603102227b9SDaniel Bristot de Oliveira return simple_read_from_buffer(user_buf, count, ppos, buff, strlen(buff) + 1); 604102227b9SDaniel Bristot de Oliveira } 605102227b9SDaniel Bristot de Oliveira 606102227b9SDaniel Bristot de Oliveira static void turn_monitoring_off(void) 607102227b9SDaniel Bristot de Oliveira { 608102227b9SDaniel Bristot de Oliveira WRITE_ONCE(monitoring_on, false); 609102227b9SDaniel Bristot de Oliveira /* Ensures that concurrent monitors read consistent monitoring_on */ 610102227b9SDaniel Bristot de Oliveira smp_wmb(); 611102227b9SDaniel Bristot de Oliveira } 612102227b9SDaniel Bristot de Oliveira 613102227b9SDaniel Bristot de Oliveira static void reset_all_monitors(void) 614102227b9SDaniel Bristot de Oliveira { 615102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *mdef; 616102227b9SDaniel Bristot de Oliveira 617102227b9SDaniel Bristot de Oliveira list_for_each_entry(mdef, &rv_monitors_list, list) { 618102227b9SDaniel Bristot de Oliveira if (mdef->monitor->enabled) 619102227b9SDaniel Bristot de Oliveira mdef->monitor->reset(); 620102227b9SDaniel Bristot de Oliveira } 621102227b9SDaniel Bristot de Oliveira } 622102227b9SDaniel Bristot de Oliveira 623102227b9SDaniel Bristot de Oliveira static void turn_monitoring_on(void) 624102227b9SDaniel Bristot de Oliveira { 625102227b9SDaniel Bristot de Oliveira WRITE_ONCE(monitoring_on, true); 626102227b9SDaniel Bristot de Oliveira /* Ensures that concurrent monitors read consistent monitoring_on */ 627102227b9SDaniel Bristot de Oliveira smp_wmb(); 628102227b9SDaniel Bristot de Oliveira } 629102227b9SDaniel Bristot de Oliveira 630102227b9SDaniel Bristot de Oliveira static void turn_monitoring_on_with_reset(void) 631102227b9SDaniel Bristot de Oliveira { 632102227b9SDaniel Bristot de Oliveira lockdep_assert_held(&rv_interface_lock); 633102227b9SDaniel Bristot de Oliveira 634102227b9SDaniel Bristot de Oliveira if (rv_monitoring_on()) 635102227b9SDaniel Bristot de Oliveira return; 636102227b9SDaniel Bristot de Oliveira 637102227b9SDaniel Bristot de Oliveira /* 638102227b9SDaniel Bristot de Oliveira * Monitors might be out of sync with the system if events were not 639102227b9SDaniel Bristot de Oliveira * processed because of !rv_monitoring_on(). 640102227b9SDaniel Bristot de Oliveira * 641102227b9SDaniel Bristot de Oliveira * Reset all monitors, forcing a re-sync. 642102227b9SDaniel Bristot de Oliveira */ 643102227b9SDaniel Bristot de Oliveira reset_all_monitors(); 644102227b9SDaniel Bristot de Oliveira turn_monitoring_on(); 645102227b9SDaniel Bristot de Oliveira } 646102227b9SDaniel Bristot de Oliveira 647102227b9SDaniel Bristot de Oliveira static ssize_t monitoring_on_write_data(struct file *filp, const char __user *user_buf, 648102227b9SDaniel Bristot de Oliveira size_t count, loff_t *ppos) 649102227b9SDaniel Bristot de Oliveira { 650102227b9SDaniel Bristot de Oliveira int retval; 651102227b9SDaniel Bristot de Oliveira bool val; 652102227b9SDaniel Bristot de Oliveira 653102227b9SDaniel Bristot de Oliveira retval = kstrtobool_from_user(user_buf, count, &val); 654102227b9SDaniel Bristot de Oliveira if (retval) 655102227b9SDaniel Bristot de Oliveira return retval; 656102227b9SDaniel Bristot de Oliveira 657102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 658102227b9SDaniel Bristot de Oliveira 659102227b9SDaniel Bristot de Oliveira if (val) 660102227b9SDaniel Bristot de Oliveira turn_monitoring_on_with_reset(); 661102227b9SDaniel Bristot de Oliveira else 662102227b9SDaniel Bristot de Oliveira turn_monitoring_off(); 663102227b9SDaniel Bristot de Oliveira 664102227b9SDaniel Bristot de Oliveira /* 665102227b9SDaniel Bristot de Oliveira * Wait for the execution of all events to finish 666102227b9SDaniel Bristot de Oliveira * before returning to user-space. 667102227b9SDaniel Bristot de Oliveira */ 668102227b9SDaniel Bristot de Oliveira tracepoint_synchronize_unregister(); 669102227b9SDaniel Bristot de Oliveira 670102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 671102227b9SDaniel Bristot de Oliveira 672102227b9SDaniel Bristot de Oliveira return count; 673102227b9SDaniel Bristot de Oliveira } 674102227b9SDaniel Bristot de Oliveira 675102227b9SDaniel Bristot de Oliveira static const struct file_operations monitoring_on_fops = { 676102227b9SDaniel Bristot de Oliveira .open = simple_open, 677102227b9SDaniel Bristot de Oliveira .llseek = no_llseek, 678102227b9SDaniel Bristot de Oliveira .write = monitoring_on_write_data, 679102227b9SDaniel Bristot de Oliveira .read = monitoring_on_read_data, 680102227b9SDaniel Bristot de Oliveira }; 681102227b9SDaniel Bristot de Oliveira 682102227b9SDaniel Bristot de Oliveira static void destroy_monitor_dir(struct rv_monitor_def *mdef) 683102227b9SDaniel Bristot de Oliveira { 68404acadcbSDaniel Bristot de Oliveira reactor_cleanup_monitor(mdef); 685102227b9SDaniel Bristot de Oliveira rv_remove(mdef->root_d); 686102227b9SDaniel Bristot de Oliveira } 687102227b9SDaniel Bristot de Oliveira 688102227b9SDaniel Bristot de Oliveira /** 689102227b9SDaniel Bristot de Oliveira * rv_register_monitor - register a rv monitor. 690102227b9SDaniel Bristot de Oliveira * @monitor: The rv_monitor to be registered. 691102227b9SDaniel Bristot de Oliveira * 692102227b9SDaniel Bristot de Oliveira * Returns 0 if successful, error otherwise. 693102227b9SDaniel Bristot de Oliveira */ 694102227b9SDaniel Bristot de Oliveira int rv_register_monitor(struct rv_monitor *monitor) 695102227b9SDaniel Bristot de Oliveira { 696102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *r; 697102227b9SDaniel Bristot de Oliveira int retval = 0; 698102227b9SDaniel Bristot de Oliveira 699102227b9SDaniel Bristot de Oliveira if (strlen(monitor->name) >= MAX_RV_MONITOR_NAME_SIZE) { 700102227b9SDaniel Bristot de Oliveira pr_info("Monitor %s has a name longer than %d\n", monitor->name, 701102227b9SDaniel Bristot de Oliveira MAX_RV_MONITOR_NAME_SIZE); 702102227b9SDaniel Bristot de Oliveira return -1; 703102227b9SDaniel Bristot de Oliveira } 704102227b9SDaniel Bristot de Oliveira 705102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 706102227b9SDaniel Bristot de Oliveira 707102227b9SDaniel Bristot de Oliveira list_for_each_entry(r, &rv_monitors_list, list) { 708102227b9SDaniel Bristot de Oliveira if (strcmp(monitor->name, r->monitor->name) == 0) { 709102227b9SDaniel Bristot de Oliveira pr_info("Monitor %s is already registered\n", monitor->name); 710102227b9SDaniel Bristot de Oliveira retval = -1; 711102227b9SDaniel Bristot de Oliveira goto out_unlock; 712102227b9SDaniel Bristot de Oliveira } 713102227b9SDaniel Bristot de Oliveira } 714102227b9SDaniel Bristot de Oliveira 715102227b9SDaniel Bristot de Oliveira r = kzalloc(sizeof(struct rv_monitor_def), GFP_KERNEL); 716102227b9SDaniel Bristot de Oliveira if (!r) { 717102227b9SDaniel Bristot de Oliveira retval = -ENOMEM; 718102227b9SDaniel Bristot de Oliveira goto out_unlock; 719102227b9SDaniel Bristot de Oliveira } 720102227b9SDaniel Bristot de Oliveira 721102227b9SDaniel Bristot de Oliveira r->monitor = monitor; 722102227b9SDaniel Bristot de Oliveira 723102227b9SDaniel Bristot de Oliveira retval = create_monitor_dir(r); 724102227b9SDaniel Bristot de Oliveira if (retval) { 725102227b9SDaniel Bristot de Oliveira kfree(r); 726102227b9SDaniel Bristot de Oliveira goto out_unlock; 727102227b9SDaniel Bristot de Oliveira } 728102227b9SDaniel Bristot de Oliveira 729102227b9SDaniel Bristot de Oliveira list_add_tail(&r->list, &rv_monitors_list); 730102227b9SDaniel Bristot de Oliveira 731102227b9SDaniel Bristot de Oliveira out_unlock: 732102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 733102227b9SDaniel Bristot de Oliveira return retval; 734102227b9SDaniel Bristot de Oliveira } 735102227b9SDaniel Bristot de Oliveira 736102227b9SDaniel Bristot de Oliveira /** 737102227b9SDaniel Bristot de Oliveira * rv_unregister_monitor - unregister a rv monitor. 738102227b9SDaniel Bristot de Oliveira * @monitor: The rv_monitor to be unregistered. 739102227b9SDaniel Bristot de Oliveira * 740102227b9SDaniel Bristot de Oliveira * Returns 0 if successful, error otherwise. 741102227b9SDaniel Bristot de Oliveira */ 742102227b9SDaniel Bristot de Oliveira int rv_unregister_monitor(struct rv_monitor *monitor) 743102227b9SDaniel Bristot de Oliveira { 744102227b9SDaniel Bristot de Oliveira struct rv_monitor_def *ptr, *next; 745102227b9SDaniel Bristot de Oliveira 746102227b9SDaniel Bristot de Oliveira mutex_lock(&rv_interface_lock); 747102227b9SDaniel Bristot de Oliveira 748102227b9SDaniel Bristot de Oliveira list_for_each_entry_safe(ptr, next, &rv_monitors_list, list) { 749102227b9SDaniel Bristot de Oliveira if (strcmp(monitor->name, ptr->monitor->name) == 0) { 750102227b9SDaniel Bristot de Oliveira rv_disable_monitor(ptr); 751102227b9SDaniel Bristot de Oliveira list_del(&ptr->list); 752102227b9SDaniel Bristot de Oliveira destroy_monitor_dir(ptr); 753102227b9SDaniel Bristot de Oliveira } 754102227b9SDaniel Bristot de Oliveira } 755102227b9SDaniel Bristot de Oliveira 756102227b9SDaniel Bristot de Oliveira mutex_unlock(&rv_interface_lock); 757102227b9SDaniel Bristot de Oliveira return 0; 758102227b9SDaniel Bristot de Oliveira } 759102227b9SDaniel Bristot de Oliveira 760102227b9SDaniel Bristot de Oliveira int __init rv_init_interface(void) 761102227b9SDaniel Bristot de Oliveira { 762102227b9SDaniel Bristot de Oliveira struct dentry *tmp; 76304acadcbSDaniel Bristot de Oliveira int retval; 764102227b9SDaniel Bristot de Oliveira 765102227b9SDaniel Bristot de Oliveira rv_root.root_dir = rv_create_dir("rv", NULL); 766102227b9SDaniel Bristot de Oliveira if (!rv_root.root_dir) 767102227b9SDaniel Bristot de Oliveira goto out_err; 768102227b9SDaniel Bristot de Oliveira 769102227b9SDaniel Bristot de Oliveira rv_root.monitors_dir = rv_create_dir("monitors", rv_root.root_dir); 770102227b9SDaniel Bristot de Oliveira if (!rv_root.monitors_dir) 771102227b9SDaniel Bristot de Oliveira goto out_err; 772102227b9SDaniel Bristot de Oliveira 773102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("available_monitors", RV_MODE_READ, rv_root.root_dir, NULL, 774102227b9SDaniel Bristot de Oliveira &available_monitors_ops); 775102227b9SDaniel Bristot de Oliveira if (!tmp) 776102227b9SDaniel Bristot de Oliveira goto out_err; 777102227b9SDaniel Bristot de Oliveira 778102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("enabled_monitors", RV_MODE_WRITE, rv_root.root_dir, NULL, 779102227b9SDaniel Bristot de Oliveira &enabled_monitors_ops); 780102227b9SDaniel Bristot de Oliveira if (!tmp) 781102227b9SDaniel Bristot de Oliveira goto out_err; 782102227b9SDaniel Bristot de Oliveira 783102227b9SDaniel Bristot de Oliveira tmp = rv_create_file("monitoring_on", RV_MODE_WRITE, rv_root.root_dir, NULL, 784102227b9SDaniel Bristot de Oliveira &monitoring_on_fops); 785102227b9SDaniel Bristot de Oliveira if (!tmp) 786102227b9SDaniel Bristot de Oliveira goto out_err; 78704acadcbSDaniel Bristot de Oliveira retval = init_rv_reactors(rv_root.root_dir); 78804acadcbSDaniel Bristot de Oliveira if (retval) 78904acadcbSDaniel Bristot de Oliveira goto out_err; 790102227b9SDaniel Bristot de Oliveira 791102227b9SDaniel Bristot de Oliveira turn_monitoring_on(); 792102227b9SDaniel Bristot de Oliveira 793102227b9SDaniel Bristot de Oliveira return 0; 794102227b9SDaniel Bristot de Oliveira 795102227b9SDaniel Bristot de Oliveira out_err: 796102227b9SDaniel Bristot de Oliveira rv_remove(rv_root.root_dir); 797102227b9SDaniel Bristot de Oliveira printk(KERN_ERR "RV: Error while creating the RV interface\n"); 798102227b9SDaniel Bristot de Oliveira return 1; 799102227b9SDaniel Bristot de Oliveira } 800