LCOV - code coverage report
Current view: top level - kernel/trace - trace_dynevent.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 12 79 15.2 %
Date: 2020-09-30 20:25:40 Functions: 2 11 18.2 %
Branches: 8 72 11.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Generic dynamic event control interface
       4                 :            :  *
       5                 :            :  * Copyright (C) 2018 Masami Hiramatsu <mhiramat@kernel.org>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/debugfs.h>
       9                 :            : #include <linux/kernel.h>
      10                 :            : #include <linux/list.h>
      11                 :            : #include <linux/mm.h>
      12                 :            : #include <linux/mutex.h>
      13                 :            : #include <linux/tracefs.h>
      14                 :            : 
      15                 :            : #include "trace.h"
      16                 :            : #include "trace_dynevent.h"
      17                 :            : 
      18                 :            : static DEFINE_MUTEX(dyn_event_ops_mutex);
      19                 :            : static LIST_HEAD(dyn_event_ops_list);
      20                 :            : 
      21                 :        207 : int dyn_event_register(struct dyn_event_operations *ops)
      22                 :            : {
      23   [ +  -  +  -  :        414 :         if (!ops || !ops->create || !ops->show || !ops->is_busy ||
          +  -  +  -  +  
                      - ]
      24         [ +  - ]:        414 :             !ops->free || !ops->match)
      25                 :            :                 return -EINVAL;
      26                 :            : 
      27                 :        207 :         INIT_LIST_HEAD(&ops->list);
      28                 :        207 :         mutex_lock(&dyn_event_ops_mutex);
      29                 :            :         list_add_tail(&ops->list, &dyn_event_ops_list);
      30                 :        207 :         mutex_unlock(&dyn_event_ops_mutex);
      31                 :        207 :         return 0;
      32                 :            : }
      33                 :            : 
      34                 :          0 : int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
      35                 :            : {
      36                 :            :         struct dyn_event *pos, *n;
      37                 :            :         char *system = NULL, *event, *p;
      38                 :            :         int ret = -ENOENT;
      39                 :            : 
      40         [ #  # ]:          0 :         if (argv[0][0] == '-') {
      41         [ #  # ]:          0 :                 if (argv[0][1] != ':')
      42                 :            :                         return -EINVAL;
      43                 :          0 :                 event = &argv[0][2];
      44                 :            :         } else {
      45                 :          0 :                 event = strchr(argv[0], ':');
      46         [ #  # ]:          0 :                 if (!event)
      47                 :            :                         return -EINVAL;
      48                 :          0 :                 event++;
      49                 :            :         }
      50                 :          0 :         argc--; argv++;
      51                 :            : 
      52                 :          0 :         p = strchr(event, '/');
      53         [ #  # ]:          0 :         if (p) {
      54                 :            :                 system = event;
      55                 :          0 :                 event = p + 1;
      56                 :          0 :                 *p = '\0';
      57                 :            :         }
      58         [ #  # ]:          0 :         if (event[0] == '\0')
      59                 :            :                 return -EINVAL;
      60                 :            : 
      61                 :          0 :         mutex_lock(&event_mutex);
      62         [ #  # ]:          0 :         for_each_dyn_event_safe(pos, n) {
      63   [ #  #  #  # ]:          0 :                 if (type && type != pos->ops)
      64                 :          0 :                         continue;
      65         [ #  # ]:          0 :                 if (!pos->ops->match(system, event,
      66                 :            :                                 argc, (const char **)argv, pos))
      67                 :          0 :                         continue;
      68                 :            : 
      69                 :          0 :                 ret = pos->ops->free(pos);
      70         [ #  # ]:          0 :                 if (ret)
      71                 :            :                         break;
      72                 :            :         }
      73                 :          0 :         mutex_unlock(&event_mutex);
      74                 :            : 
      75                 :          0 :         return ret;
      76                 :            : }
      77                 :            : 
      78                 :          0 : static int create_dyn_event(int argc, char **argv)
      79                 :            : {
      80                 :            :         struct dyn_event_operations *ops;
      81                 :            :         int ret = -ENODEV;
      82                 :            : 
      83         [ #  # ]:          0 :         if (argv[0][0] == '-' || argv[0][0] == '!')
      84                 :          0 :                 return dyn_event_release(argc, argv, NULL);
      85                 :            : 
      86                 :          0 :         mutex_lock(&dyn_event_ops_mutex);
      87         [ #  # ]:          0 :         list_for_each_entry(ops, &dyn_event_ops_list, list) {
      88                 :          0 :                 ret = ops->create(argc, (const char **)argv);
      89         [ #  # ]:          0 :                 if (!ret || ret != -ECANCELED)
      90                 :            :                         break;
      91                 :            :         }
      92                 :          0 :         mutex_unlock(&dyn_event_ops_mutex);
      93         [ #  # ]:          0 :         if (ret == -ECANCELED)
      94                 :            :                 ret = -EINVAL;
      95                 :            : 
      96                 :          0 :         return ret;
      97                 :            : }
      98                 :            : 
      99                 :            : /* Protected by event_mutex */
     100                 :            : LIST_HEAD(dyn_event_list);
     101                 :            : 
     102                 :          0 : void *dyn_event_seq_start(struct seq_file *m, loff_t *pos)
     103                 :            : {
     104                 :          0 :         mutex_lock(&event_mutex);
     105                 :          0 :         return seq_list_start(&dyn_event_list, *pos);
     106                 :            : }
     107                 :            : 
     108                 :          0 : void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos)
     109                 :            : {
     110                 :          0 :         return seq_list_next(v, &dyn_event_list, pos);
     111                 :            : }
     112                 :            : 
     113                 :          0 : void dyn_event_seq_stop(struct seq_file *m, void *v)
     114                 :            : {
     115                 :          0 :         mutex_unlock(&event_mutex);
     116                 :          0 : }
     117                 :            : 
     118                 :          0 : static int dyn_event_seq_show(struct seq_file *m, void *v)
     119                 :            : {
     120                 :            :         struct dyn_event *ev = v;
     121                 :            : 
     122   [ #  #  #  # ]:          0 :         if (ev && ev->ops)
     123                 :          0 :                 return ev->ops->show(m, ev);
     124                 :            : 
     125                 :            :         return 0;
     126                 :            : }
     127                 :            : 
     128                 :            : static const struct seq_operations dyn_event_seq_op = {
     129                 :            :         .start  = dyn_event_seq_start,
     130                 :            :         .next   = dyn_event_seq_next,
     131                 :            :         .stop   = dyn_event_seq_stop,
     132                 :            :         .show   = dyn_event_seq_show
     133                 :            : };
     134                 :            : 
     135                 :            : /*
     136                 :            :  * dyn_events_release_all - Release all specific events
     137                 :            :  * @type:       the dyn_event_operations * which filters releasing events
     138                 :            :  *
     139                 :            :  * This releases all events which ->ops matches @type. If @type is NULL,
     140                 :            :  * all events are released.
     141                 :            :  * Return -EBUSY if any of them are in use, and return other errors when
     142                 :            :  * it failed to free the given event. Except for -EBUSY, event releasing
     143                 :            :  * process will be aborted at that point and there may be some other
     144                 :            :  * releasable events on the list.
     145                 :            :  */
     146                 :          0 : int dyn_events_release_all(struct dyn_event_operations *type)
     147                 :            : {
     148                 :            :         struct dyn_event *ev, *tmp;
     149                 :            :         int ret = 0;
     150                 :            : 
     151                 :          0 :         mutex_lock(&event_mutex);
     152         [ #  # ]:          0 :         for_each_dyn_event(ev) {
     153   [ #  #  #  # ]:          0 :                 if (type && ev->ops != type)
     154                 :          0 :                         continue;
     155         [ #  # ]:          0 :                 if (ev->ops->is_busy(ev)) {
     156                 :            :                         ret = -EBUSY;
     157                 :            :                         goto out;
     158                 :            :                 }
     159                 :            :         }
     160         [ #  # ]:          0 :         for_each_dyn_event_safe(ev, tmp) {
     161   [ #  #  #  # ]:          0 :                 if (type && ev->ops != type)
     162                 :          0 :                         continue;
     163                 :          0 :                 ret = ev->ops->free(ev);
     164         [ #  # ]:          0 :                 if (ret)
     165                 :            :                         break;
     166                 :            :         }
     167                 :            : out:
     168                 :          0 :         mutex_unlock(&event_mutex);
     169                 :            : 
     170                 :          0 :         return ret;
     171                 :            : }
     172                 :            : 
     173                 :          0 : static int dyn_event_open(struct inode *inode, struct file *file)
     174                 :            : {
     175                 :            :         int ret;
     176                 :            : 
     177                 :          0 :         ret = tracing_check_open_get_tr(NULL);
     178         [ #  # ]:          0 :         if (ret)
     179                 :            :                 return ret;
     180                 :            : 
     181   [ #  #  #  # ]:          0 :         if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
     182                 :          0 :                 ret = dyn_events_release_all(NULL);
     183         [ #  # ]:          0 :                 if (ret < 0)
     184                 :            :                         return ret;
     185                 :            :         }
     186                 :            : 
     187                 :          0 :         return seq_open(file, &dyn_event_seq_op);
     188                 :            : }
     189                 :            : 
     190                 :          0 : static ssize_t dyn_event_write(struct file *file, const char __user *buffer,
     191                 :            :                                 size_t count, loff_t *ppos)
     192                 :            : {
     193                 :          0 :         return trace_parse_run_command(file, buffer, count, ppos,
     194                 :            :                                        create_dyn_event);
     195                 :            : }
     196                 :            : 
     197                 :            : static const struct file_operations dynamic_events_ops = {
     198                 :            :         .owner          = THIS_MODULE,
     199                 :            :         .open           = dyn_event_open,
     200                 :            :         .read           = seq_read,
     201                 :            :         .llseek         = seq_lseek,
     202                 :            :         .release        = seq_release,
     203                 :            :         .write          = dyn_event_write,
     204                 :            : };
     205                 :            : 
     206                 :            : /* Make a tracefs interface for controlling dynamic events */
     207                 :        207 : static __init int init_dynamic_event(void)
     208                 :            : {
     209                 :            :         struct dentry *d_tracer;
     210                 :            :         struct dentry *entry;
     211                 :            : 
     212                 :        207 :         d_tracer = tracing_init_dentry();
     213         [ +  - ]:        207 :         if (IS_ERR(d_tracer))
     214                 :            :                 return 0;
     215                 :            : 
     216                 :        207 :         entry = tracefs_create_file("dynamic_events", 0644, d_tracer,
     217                 :            :                                     NULL, &dynamic_events_ops);
     218                 :            : 
     219                 :            :         /* Event list interface */
     220         [ -  + ]:        207 :         if (!entry)
     221                 :          0 :                 pr_warn("Could not create tracefs 'dynamic_events' entry\n");
     222                 :            : 
     223                 :            :         return 0;
     224                 :            : }
     225                 :            : fs_initcall(init_dynamic_event);

Generated by: LCOV version 1.14