~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/trace/rv/rv_reactors.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php