LCOV - code coverage report
Current view: top level - kernel/trace - trace_dynevent.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 15 144 10.4 %
Date: 2022-04-01 14:58:12 Functions: 2 18 11.1 %
Branches: 8 90 8.9 %

           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                 :          6 : int dyn_event_register(struct dyn_event_operations *ops)
      22                 :            : {
      23   [ +  -  +  -  :          6 :         if (!ops || !ops->create || !ops->show || !ops->is_busy ||
             +  -  +  - ]
      24   [ +  -  +  - ]:          6 :             !ops->free || !ops->match)
      25                 :            :                 return -EINVAL;
      26                 :            : 
      27                 :          6 :         INIT_LIST_HEAD(&ops->list);
      28                 :          6 :         mutex_lock(&dyn_event_ops_mutex);
      29                 :          6 :         list_add_tail(&ops->list, &dyn_event_ops_list);
      30                 :          6 :         mutex_unlock(&dyn_event_ops_mutex);
      31                 :          6 :         return 0;
      32                 :            : }
      33                 :            : 
      34                 :          0 : int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
      35                 :            : {
      36                 :          0 :         struct dyn_event *pos, *n;
      37                 :          0 :         char *system = NULL, *event, *p;
      38                 :          0 :         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                 :          0 :                 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                 :          0 :         struct dyn_event_operations *ops;
      81                 :          0 :         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                 :          0 :                 ret = -EINVAL;
      95                 :            : 
      96                 :            :         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                 :          0 :         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                 :          0 :         struct dyn_event *ev, *tmp;
     149                 :          0 :         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                 :          0 :                         ret = -EBUSY;
     157                 :          0 :                         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                 :          0 : 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                 :          0 :         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                 :          3 : static __init int init_dynamic_event(void)
     208                 :            : {
     209                 :          3 :         struct dentry *d_tracer;
     210                 :          3 :         struct dentry *entry;
     211                 :            : 
     212                 :          3 :         d_tracer = tracing_init_dentry();
     213         [ +  - ]:          3 :         if (IS_ERR(d_tracer))
     214                 :            :                 return 0;
     215                 :            : 
     216                 :          3 :         entry = tracefs_create_file("dynamic_events", 0644, d_tracer,
     217                 :            :                                     NULL, &dynamic_events_ops);
     218                 :            : 
     219                 :            :         /* Event list interface */
     220         [ -  + ]:          3 :         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);
     226                 :            : 
     227                 :            : /**
     228                 :            :  * dynevent_arg_add - Add an arg to a dynevent_cmd
     229                 :            :  * @cmd: A pointer to the dynevent_cmd struct representing the new event cmd
     230                 :            :  * @arg: The argument to append to the current cmd
     231                 :            :  * @check_arg: An (optional) pointer to a function checking arg sanity
     232                 :            :  *
     233                 :            :  * Append an argument to a dynevent_cmd.  The argument string will be
     234                 :            :  * appended to the current cmd string, followed by a separator, if
     235                 :            :  * applicable.  Before the argument is added, the @check_arg function,
     236                 :            :  * if present, will be used to check the sanity of the current arg
     237                 :            :  * string.
     238                 :            :  *
     239                 :            :  * The cmd string and separator should be set using the
     240                 :            :  * dynevent_arg_init() before any arguments are added using this
     241                 :            :  * function.
     242                 :            :  *
     243                 :            :  * Return: 0 if successful, error otherwise.
     244                 :            :  */
     245                 :          0 : int dynevent_arg_add(struct dynevent_cmd *cmd,
     246                 :            :                      struct dynevent_arg *arg,
     247                 :            :                      dynevent_check_arg_fn_t check_arg)
     248                 :            : {
     249                 :          0 :         int ret = 0;
     250                 :            : 
     251         [ #  # ]:          0 :         if (check_arg) {
     252                 :          0 :                 ret = check_arg(arg);
     253         [ #  # ]:          0 :                 if (ret)
     254                 :            :                         return ret;
     255                 :            :         }
     256                 :            : 
     257                 :          0 :         ret = seq_buf_printf(&cmd->seq, " %s%c", arg->str, arg->separator);
     258         [ #  # ]:          0 :         if (ret) {
     259                 :          0 :                 pr_err("String is too long: %s%c\n", arg->str, arg->separator);
     260                 :          0 :                 return -E2BIG;
     261                 :            :         }
     262                 :            : 
     263                 :            :         return ret;
     264                 :            : }
     265                 :            : 
     266                 :            : /**
     267                 :            :  * dynevent_arg_pair_add - Add an arg pair to a dynevent_cmd
     268                 :            :  * @cmd: A pointer to the dynevent_cmd struct representing the new event cmd
     269                 :            :  * @arg_pair: The argument pair to append to the current cmd
     270                 :            :  * @check_arg: An (optional) pointer to a function checking arg sanity
     271                 :            :  *
     272                 :            :  * Append an argument pair to a dynevent_cmd.  An argument pair
     273                 :            :  * consists of a left-hand-side argument and a right-hand-side
     274                 :            :  * argument separated by an operator, which can be whitespace, all
     275                 :            :  * followed by a separator, if applicable.  This can be used to add
     276                 :            :  * arguments of the form 'type variable_name;' or 'x+y'.
     277                 :            :  *
     278                 :            :  * The lhs argument string will be appended to the current cmd string,
     279                 :            :  * followed by an operator, if applicable, followd by the rhs string,
     280                 :            :  * followed finally by a separator, if applicable.  Before the
     281                 :            :  * argument is added, the @check_arg function, if present, will be
     282                 :            :  * used to check the sanity of the current arg strings.
     283                 :            :  *
     284                 :            :  * The cmd strings, operator, and separator should be set using the
     285                 :            :  * dynevent_arg_pair_init() before any arguments are added using this
     286                 :            :  * function.
     287                 :            :  *
     288                 :            :  * Return: 0 if successful, error otherwise.
     289                 :            :  */
     290                 :          0 : int dynevent_arg_pair_add(struct dynevent_cmd *cmd,
     291                 :            :                           struct dynevent_arg_pair *arg_pair,
     292                 :            :                           dynevent_check_arg_fn_t check_arg)
     293                 :            : {
     294                 :          0 :         int ret = 0;
     295                 :            : 
     296         [ #  # ]:          0 :         if (check_arg) {
     297                 :          0 :                 ret = check_arg(arg_pair);
     298         [ #  # ]:          0 :                 if (ret)
     299                 :            :                         return ret;
     300                 :            :         }
     301                 :            : 
     302                 :          0 :         ret = seq_buf_printf(&cmd->seq, " %s%c%s%c", arg_pair->lhs,
     303                 :          0 :                              arg_pair->operator, arg_pair->rhs,
     304                 :          0 :                              arg_pair->separator);
     305         [ #  # ]:          0 :         if (ret) {
     306                 :          0 :                 pr_err("field string is too long: %s%c%s%c\n", arg_pair->lhs,
     307                 :            :                        arg_pair->operator, arg_pair->rhs,
     308                 :            :                        arg_pair->separator);
     309                 :          0 :                 return -E2BIG;
     310                 :            :         }
     311                 :            : 
     312                 :            :         return ret;
     313                 :            : }
     314                 :            : 
     315                 :            : /**
     316                 :            :  * dynevent_str_add - Add a string to a dynevent_cmd
     317                 :            :  * @cmd: A pointer to the dynevent_cmd struct representing the new event cmd
     318                 :            :  * @str: The string to append to the current cmd
     319                 :            :  *
     320                 :            :  * Append a string to a dynevent_cmd.  The string will be appended to
     321                 :            :  * the current cmd string as-is, with nothing prepended or appended.
     322                 :            :  *
     323                 :            :  * Return: 0 if successful, error otherwise.
     324                 :            :  */
     325                 :          0 : int dynevent_str_add(struct dynevent_cmd *cmd, const char *str)
     326                 :            : {
     327                 :          0 :         int ret = 0;
     328                 :            : 
     329                 :          0 :         ret = seq_buf_puts(&cmd->seq, str);
     330         [ #  # ]:          0 :         if (ret) {
     331                 :          0 :                 pr_err("String is too long: %s\n", str);
     332                 :          0 :                 return -E2BIG;
     333                 :            :         }
     334                 :            : 
     335                 :            :         return ret;
     336                 :            : }
     337                 :            : 
     338                 :            : /**
     339                 :            :  * dynevent_cmd_init - Initialize a dynevent_cmd object
     340                 :            :  * @cmd: A pointer to the dynevent_cmd struct representing the cmd
     341                 :            :  * @buf: A pointer to the buffer to generate the command into
     342                 :            :  * @maxlen: The length of the buffer the command will be generated into
     343                 :            :  * @type: The type of the cmd, checked against further operations
     344                 :            :  * @run_command: The type-specific function that will actually run the command
     345                 :            :  *
     346                 :            :  * Initialize a dynevent_cmd.  A dynevent_cmd is used to build up and
     347                 :            :  * run dynamic event creation commands, such as commands for creating
     348                 :            :  * synthetic and kprobe events.  Before calling any of the functions
     349                 :            :  * used to build the command, a dynevent_cmd object should be
     350                 :            :  * instantiated and initialized using this function.
     351                 :            :  *
     352                 :            :  * The initialization sets things up by saving a pointer to the
     353                 :            :  * user-supplied buffer and its length via the @buf and @maxlen
     354                 :            :  * params, and by saving the cmd-specific @type and @run_command
     355                 :            :  * params which are used to check subsequent dynevent_cmd operations
     356                 :            :  * and actually run the command when complete.
     357                 :            :  */
     358                 :          0 : void dynevent_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen,
     359                 :            :                        enum dynevent_type type,
     360                 :            :                        dynevent_create_fn_t run_command)
     361                 :            : {
     362                 :          0 :         memset(cmd, '\0', sizeof(*cmd));
     363                 :            : 
     364                 :          0 :         seq_buf_init(&cmd->seq, buf, maxlen);
     365                 :          0 :         cmd->type = type;
     366                 :          0 :         cmd->run_command = run_command;
     367                 :          0 : }
     368                 :            : 
     369                 :            : /**
     370                 :            :  * dynevent_arg_init - Initialize a dynevent_arg object
     371                 :            :  * @arg: A pointer to the dynevent_arg struct representing the arg
     372                 :            :  * @separator: An (optional) separator, appended after adding the arg
     373                 :            :  *
     374                 :            :  * Initialize a dynevent_arg object.  A dynevent_arg represents an
     375                 :            :  * object used to append single arguments to the current command
     376                 :            :  * string.  After the arg string is successfully appended to the
     377                 :            :  * command string, the optional @separator is appended.  If no
     378                 :            :  * separator was specified when initializing the arg, a space will be
     379                 :            :  * appended.
     380                 :            :  */
     381                 :          0 : void dynevent_arg_init(struct dynevent_arg *arg,
     382                 :            :                        char separator)
     383                 :            : {
     384                 :          0 :         memset(arg, '\0', sizeof(*arg));
     385                 :            : 
     386         [ #  # ]:          0 :         if (!separator)
     387                 :          0 :                 separator = ' ';
     388                 :          0 :         arg->separator = separator;
     389                 :          0 : }
     390                 :            : 
     391                 :            : /**
     392                 :            :  * dynevent_arg_pair_init - Initialize a dynevent_arg_pair object
     393                 :            :  * @arg_pair: A pointer to the dynevent_arg_pair struct representing the arg
     394                 :            :  * @operator: An (optional) operator, appended after adding the first arg
     395                 :            :  * @separator: An (optional) separator, appended after adding the second arg
     396                 :            :  *
     397                 :            :  * Initialize a dynevent_arg_pair object.  A dynevent_arg_pair
     398                 :            :  * represents an object used to append argument pairs such as 'type
     399                 :            :  * variable_name;' or 'x+y' to the current command string.  An
     400                 :            :  * argument pair consists of a left-hand-side argument and a
     401                 :            :  * right-hand-side argument separated by an operator, which can be
     402                 :            :  * whitespace, all followed by a separator, if applicable.  After the
     403                 :            :  * first arg string is successfully appended to the command string,
     404                 :            :  * the optional @operator is appended, followed by the second arg and
     405                 :            :  * and optional @separator.  If no separator was specified when
     406                 :            :  * initializing the arg, a space will be appended.
     407                 :            :  */
     408                 :          0 : void dynevent_arg_pair_init(struct dynevent_arg_pair *arg_pair,
     409                 :            :                             char operator, char separator)
     410                 :            : {
     411                 :          0 :         memset(arg_pair, '\0', sizeof(*arg_pair));
     412                 :            : 
     413         [ #  # ]:          0 :         if (!operator)
     414                 :          0 :                 operator = ' ';
     415                 :          0 :         arg_pair->operator = operator;
     416                 :            : 
     417         [ #  # ]:          0 :         if (!separator)
     418                 :          0 :                 separator = ' ';
     419                 :          0 :         arg_pair->separator = separator;
     420                 :          0 : }
     421                 :            : 
     422                 :            : /**
     423                 :            :  * dynevent_create - Create the dynamic event contained in dynevent_cmd
     424                 :            :  * @cmd: The dynevent_cmd object containing the dynamic event creation command
     425                 :            :  *
     426                 :            :  * Once a dynevent_cmd object has been successfully built up via the
     427                 :            :  * dynevent_cmd_init(), dynevent_arg_add() and dynevent_arg_pair_add()
     428                 :            :  * functions, this function runs the final command to actually create
     429                 :            :  * the event.
     430                 :            :  *
     431                 :            :  * Return: 0 if the event was successfully created, error otherwise.
     432                 :            :  */
     433                 :          0 : int dynevent_create(struct dynevent_cmd *cmd)
     434                 :            : {
     435                 :          0 :         return cmd->run_command(cmd);
     436                 :            : }
     437                 :            : EXPORT_SYMBOL_GPL(dynevent_create);

Generated by: LCOV version 1.14