]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - kernel/trace/trace_events_hist.c
tracing: Add 'hist:' to hist trigger error log error string
[linux.git] / kernel / trace / trace_events_hist.c
index f62de5f43e79dfd97a4e94bd38a502d2ca224ac7..c322826e07265dc3a83ec2ba04abec6e73b2946d 100644 (file)
        C(INVALID_SUBSYS_EVENT, "Invalid subsystem or event name"),     \
        C(INVALID_REF_KEY,      "Using variable references in keys not supported"), \
        C(VAR_NOT_FOUND,        "Couldn't find variable"),              \
-       C(FIELD_NOT_FOUND,      "Couldn't find field"),
+       C(FIELD_NOT_FOUND,      "Couldn't find field"),                 \
+       C(EMPTY_ASSIGNMENT,     "Empty assignment"),                    \
+       C(INVALID_SORT_MODIFIER,"Invalid sort modifier"),               \
+       C(EMPTY_SORT_FIELD,     "Empty sort field"),                    \
+       C(TOO_MANY_SORT_FIELDS, "Too many sort fields (Max = 2)"),      \
+       C(INVALID_SORT_FIELD,   "Sort field must be a key or a val"),
 
 #undef C
 #define C(a, b)                HIST_ERR_##a
@@ -607,7 +612,8 @@ static void last_cmd_set(struct trace_event_file *file, char *str)
        if (!str)
                return;
 
-       strncpy(last_cmd, str, MAX_FILTER_STR_VAL - 1);
+       strcpy(last_cmd, "hist:");
+       strncat(last_cmd, str, MAX_FILTER_STR_VAL - 1 - sizeof("hist:"));
 
        if (file) {
                call = file->event_call;
@@ -833,7 +839,7 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter,
                fmt = synth_field_fmt(se->fields[i]->type);
 
                /* parameter types */
-               if (tr->trace_flags & TRACE_ITER_VERBOSE)
+               if (tr && tr->trace_flags & TRACE_ITER_VERBOSE)
                        trace_seq_printf(s, "%s ", fmt);
 
                snprintf(print_fmt, sizeof(print_fmt), "%%s=%s%%s", fmt);
@@ -879,7 +885,7 @@ static notrace void trace_event_raw_event_synth(void *__data,
        struct trace_event_file *trace_file = __data;
        struct synth_trace_event *entry;
        struct trace_event_buffer fbuffer;
-       struct ring_buffer *buffer;
+       struct trace_buffer *buffer;
        struct synth_event *event;
        unsigned int i, n_u64;
        int fields_size = 0;
@@ -895,7 +901,7 @@ static notrace void trace_event_raw_event_synth(void *__data,
         * Avoid ring buffer recursion detection, as this event
         * is being performed within another event.
         */
-       buffer = trace_file->tr->trace_buffer.buffer;
+       buffer = trace_file->tr->array_buffer.buffer;
        ring_buffer_nest_start(buffer);
 
        entry = trace_event_buffer_reserve(&fbuffer, trace_file,
@@ -1384,6 +1390,11 @@ static int create_or_delete_synth_event(int argc, char **argv)
        return ret == -ECANCELED ? -EINVAL : ret;
 }
 
+int synth_event_run_command(const char *command)
+{
+       return trace_run_command(command, create_or_delete_synth_event);
+}
+
 static int synth_event_create(int argc, const char **argv)
 {
        const char *name = argv[0];
@@ -1766,11 +1777,13 @@ static struct hist_field *find_var(struct hist_trigger_data *hist_data,
        struct event_trigger_data *test;
        struct hist_field *hist_field;
 
+       lockdep_assert_held(&event_mutex);
+
        hist_field = find_var_field(hist_data, var_name);
        if (hist_field)
                return hist_field;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        test_data = test->private_data;
                        hist_field = find_var_field(test_data, var_name);
@@ -1820,7 +1833,9 @@ static struct hist_field *find_file_var(struct trace_event_file *file,
        struct event_trigger_data *test;
        struct hist_field *hist_field;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       lockdep_assert_held(&event_mutex);
+
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        test_data = test->private_data;
                        hist_field = find_var_field(test_data, var_name);
@@ -2030,12 +2045,6 @@ static int parse_map_size(char *str)
        unsigned long size, map_bits;
        int ret;
 
-       strsep(&str, "=");
-       if (!str) {
-               ret = -EINVAL;
-               goto out;
-       }
-
        ret = kstrtoul(str, 0, &size);
        if (ret)
                goto out;
@@ -2095,25 +2104,25 @@ static int parse_action(char *str, struct hist_trigger_attrs *attrs)
 static int parse_assignment(struct trace_array *tr,
                            char *str, struct hist_trigger_attrs *attrs)
 {
-       int ret = 0;
+       int len, ret = 0;
 
-       if ((str_has_prefix(str, "key=")) ||
-           (str_has_prefix(str, "keys="))) {
-               attrs->keys_str = kstrdup(str, GFP_KERNEL);
+       if ((len = str_has_prefix(str, "key=")) ||
+           (len = str_has_prefix(str, "keys="))) {
+               attrs->keys_str = kstrdup(str + len, GFP_KERNEL);
                if (!attrs->keys_str) {
                        ret = -ENOMEM;
                        goto out;
                }
-       } else if ((str_has_prefix(str, "val=")) ||
-                  (str_has_prefix(str, "vals=")) ||
-                  (str_has_prefix(str, "values="))) {
-               attrs->vals_str = kstrdup(str, GFP_KERNEL);
+       } else if ((len = str_has_prefix(str, "val=")) ||
+                  (len = str_has_prefix(str, "vals=")) ||
+                  (len = str_has_prefix(str, "values="))) {
+               attrs->vals_str = kstrdup(str + len, GFP_KERNEL);
                if (!attrs->vals_str) {
                        ret = -ENOMEM;
                        goto out;
                }
-       } else if (str_has_prefix(str, "sort=")) {
-               attrs->sort_key_str = kstrdup(str, GFP_KERNEL);
+       } else if ((len = str_has_prefix(str, "sort="))) {
+               attrs->sort_key_str = kstrdup(str + len, GFP_KERNEL);
                if (!attrs->sort_key_str) {
                        ret = -ENOMEM;
                        goto out;
@@ -2124,12 +2133,8 @@ static int parse_assignment(struct trace_array *tr,
                        ret = -ENOMEM;
                        goto out;
                }
-       } else if (str_has_prefix(str, "clock=")) {
-               strsep(&str, "=");
-               if (!str) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       } else if ((len = str_has_prefix(str, "clock="))) {
+               str += len;
 
                str = strstrip(str);
                attrs->clock = kstrdup(str, GFP_KERNEL);
@@ -2137,8 +2142,8 @@ static int parse_assignment(struct trace_array *tr,
                        ret = -ENOMEM;
                        goto out;
                }
-       } else if (str_has_prefix(str, "size=")) {
-               int map_bits = parse_map_size(str);
+       } else if ((len = str_has_prefix(str, "size="))) {
+               int map_bits = parse_map_size(str + len);
 
                if (map_bits < 0) {
                        ret = map_bits;
@@ -2178,8 +2183,15 @@ parse_hist_trigger_attrs(struct trace_array *tr, char *trigger_str)
 
        while (trigger_str) {
                char *str = strsep(&trigger_str, ":");
+               char *rhs;
 
-               if (strchr(str, '=')) {
+               rhs = strchr(str, '=');
+               if (rhs) {
+                       if (!strlen(++rhs)) {
+                               ret = -EINVAL;
+                               hist_err(tr, HIST_ERR_EMPTY_ASSIGNMENT, errpos(str));
+                               goto free;
+                       }
                        ret = parse_assignment(tr, str, attrs);
                        if (ret)
                                goto free;
@@ -3115,7 +3127,9 @@ static char *find_trigger_filter(struct hist_trigger_data *hist_data,
 {
        struct event_trigger_data *test;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       lockdep_assert_held(&event_mutex);
+
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        if (test->private_data == hist_data)
                                return test->filter_str;
@@ -3166,9 +3180,11 @@ find_compatible_hist(struct hist_trigger_data *target_hist_data,
        struct event_trigger_data *test;
        unsigned int n_keys;
 
+       lockdep_assert_held(&event_mutex);
+
        n_keys = target_hist_data->n_fields - target_hist_data->n_vals;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        hist_data = test->private_data;
 
@@ -4110,8 +4126,11 @@ static int check_synth_field(struct synth_event *event,
 
        field = event->fields[field_pos];
 
-       if (strcmp(field->type, hist_field->type) != 0)
-               return -EINVAL;
+       if (strcmp(field->type, hist_field->type) != 0) {
+               if (field->size != hist_field->size ||
+                   field->is_signed != hist_field->is_signed)
+                       return -EINVAL;
+       }
 
        return 0;
 }
@@ -4506,10 +4525,6 @@ static int create_val_fields(struct hist_trigger_data *hist_data,
        if (!fields_str)
                goto out;
 
-       strsep(&fields_str, "=");
-       if (!fields_str)
-               goto out;
-
        for (i = 0, j = 1; i < TRACING_MAP_VALS_MAX &&
                     j < TRACING_MAP_VALS_MAX; i++) {
                field_str = strsep(&fields_str, ",");
@@ -4604,10 +4619,6 @@ static int create_key_fields(struct hist_trigger_data *hist_data,
        if (!fields_str)
                goto out;
 
-       strsep(&fields_str, "=");
-       if (!fields_str)
-               goto out;
-
        for (i = n_vals; i < n_vals + TRACING_MAP_KEYS_MAX; i++) {
                field_str = strsep(&fields_str, ",");
                if (!field_str)
@@ -4739,7 +4750,7 @@ static int create_hist_fields(struct hist_trigger_data *hist_data,
        return ret;
 }
 
-static int is_descending(const char *str)
+static int is_descending(struct trace_array *tr, const char *str)
 {
        if (!str)
                return 0;
@@ -4750,11 +4761,14 @@ static int is_descending(const char *str)
        if (strcmp(str, "ascending") == 0)
                return 0;
 
+       hist_err(tr, HIST_ERR_INVALID_SORT_MODIFIER, errpos((char *)str));
+
        return -EINVAL;
 }
 
 static int create_sort_keys(struct hist_trigger_data *hist_data)
 {
+       struct trace_array *tr = hist_data->event_file->tr;
        char *fields_str = hist_data->attrs->sort_key_str;
        struct tracing_map_sort_key *sort_key;
        int descending, ret = 0;
@@ -4765,12 +4779,6 @@ static int create_sort_keys(struct hist_trigger_data *hist_data)
        if (!fields_str)
                goto out;
 
-       strsep(&fields_str, "=");
-       if (!fields_str) {
-               ret = -EINVAL;
-               goto out;
-       }
-
        for (i = 0; i < TRACING_MAP_SORT_KEYS_MAX; i++) {
                struct hist_field *hist_field;
                char *field_str, *field_name;
@@ -4779,25 +4787,30 @@ static int create_sort_keys(struct hist_trigger_data *hist_data)
                sort_key = &hist_data->sort_keys[i];
 
                field_str = strsep(&fields_str, ",");
-               if (!field_str) {
-                       if (i == 0)
-                               ret = -EINVAL;
+               if (!field_str)
+                       break;
+
+               if (!*field_str) {
+                       ret = -EINVAL;
+                       hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort="));
                        break;
                }
 
                if ((i == TRACING_MAP_SORT_KEYS_MAX - 1) && fields_str) {
+                       hist_err(tr, HIST_ERR_TOO_MANY_SORT_FIELDS, errpos("sort="));
                        ret = -EINVAL;
                        break;
                }
 
                field_name = strsep(&field_str, ".");
-               if (!field_name) {
+               if (!field_name || !*field_name) {
                        ret = -EINVAL;
+                       hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort="));
                        break;
                }
 
                if (strcmp(field_name, "hitcount") == 0) {
-                       descending = is_descending(field_str);
+                       descending = is_descending(tr, field_str);
                        if (descending < 0) {
                                ret = descending;
                                break;
@@ -4819,7 +4832,7 @@ static int create_sort_keys(struct hist_trigger_data *hist_data)
 
                        if (strcmp(field_name, test_name) == 0) {
                                sort_key->field_idx = idx;
-                               descending = is_descending(field_str);
+                               descending = is_descending(tr, field_str);
                                if (descending < 0) {
                                        ret = descending;
                                        goto out;
@@ -4830,6 +4843,7 @@ static int create_sort_keys(struct hist_trigger_data *hist_data)
                }
                if (j == hist_data->n_fields) {
                        ret = -EINVAL;
+                       hist_err(tr, HIST_ERR_INVALID_SORT_FIELD, errpos(field_name));
                        break;
                }
        }
@@ -5528,7 +5542,7 @@ static int hist_show(struct seq_file *m, void *v)
                goto out_unlock;
        }
 
-       list_for_each_entry_rcu(data, &event_file->triggers, list) {
+       list_for_each_entry(data, &event_file->triggers, list) {
                if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
                        hist_trigger_show(m, data, n++);
        }
@@ -5921,7 +5935,9 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
        if (hist_data->attrs->name && !named_data)
                goto new;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       lockdep_assert_held(&event_mutex);
+
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        if (!hist_trigger_match(data, test, named_data, false))
                                continue;
@@ -6005,10 +6021,12 @@ static bool have_hist_trigger_match(struct event_trigger_data *data,
        struct event_trigger_data *test, *named_data = NULL;
        bool match = false;
 
+       lockdep_assert_held(&event_mutex);
+
        if (hist_data->attrs->name)
                named_data = find_named_trigger(hist_data->attrs->name);
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        if (hist_trigger_match(data, test, named_data, false)) {
                                match = true;
@@ -6026,10 +6044,12 @@ static bool hist_trigger_check_refs(struct event_trigger_data *data,
        struct hist_trigger_data *hist_data = data->private_data;
        struct event_trigger_data *test, *named_data = NULL;
 
+       lockdep_assert_held(&event_mutex);
+
        if (hist_data->attrs->name)
                named_data = find_named_trigger(hist_data->attrs->name);
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        if (!hist_trigger_match(data, test, named_data, false))
                                continue;
@@ -6051,10 +6071,12 @@ static void hist_unregister_trigger(char *glob, struct event_trigger_ops *ops,
        struct event_trigger_data *test, *named_data = NULL;
        bool unregistered = false;
 
+       lockdep_assert_held(&event_mutex);
+
        if (hist_data->attrs->name)
                named_data = find_named_trigger(hist_data->attrs->name);
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        if (!hist_trigger_match(data, test, named_data, false))
                                continue;
@@ -6080,7 +6102,9 @@ static bool hist_file_check_refs(struct trace_event_file *file)
        struct hist_trigger_data *hist_data;
        struct event_trigger_data *test;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       lockdep_assert_held(&event_mutex);
+
+       list_for_each_entry(test, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        hist_data = test->private_data;
                        if (check_var_refs(hist_data))
@@ -6323,7 +6347,8 @@ hist_enable_trigger(struct event_trigger_data *data, void *rec,
        struct enable_trigger_data *enable_data = data->private_data;
        struct event_trigger_data *test;
 
-       list_for_each_entry_rcu(test, &enable_data->file->triggers, list) {
+       list_for_each_entry_rcu(test, &enable_data->file->triggers, list,
+                               lockdep_is_held(&event_mutex)) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        if (enable_data->enable)
                                test->paused = false;