Add support for synthetic event error logging, which entails adding a
logging function for it, a way to save the synthetic event command,
and a set of specific synthetic event parse error strings and
handling.

[ <rost...@goodmis.org>: wrote save_cmdstr() seq_buf implementation. ]
Signed-off-by: Tom Zanussi <zanu...@kernel.org>
---
 kernel/trace/trace_events_synth.c | 92 ++++++++++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace_events_synth.c 
b/kernel/trace/trace_events_synth.c
index 8c9d6e464da0..7efe39be6576 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -20,6 +20,48 @@
 
 #include "trace_synth.h"
 
+#undef ERRORS
+#define ERRORS \
+       C(BAD_NAME,             "Illegal name"),                \
+       C(CMD_INCOMPLETE,       "Incomplete command"),          \
+       C(EVENT_EXISTS,         "Event already exists"),        \
+       C(TOO_MANY_FIELDS,      "Too many fields"),             \
+       C(INCOMPLETE_TYPE,      "Incomplete type"),             \
+       C(INVALID_TYPE,         "Invalid type"),                \
+       C(INVALID_FIELD,        "Invalid field"),               \
+       C(CMD_TOO_LONG,         "Command too long"),
+
+#undef C
+#define C(a, b)                SYNTH_ERR_##a
+
+enum { ERRORS };
+
+#undef C
+#define C(a, b)                b
+
+static const char *err_text[] = { ERRORS };
+
+static char last_cmd[MAX_FILTER_STR_VAL];
+
+static int errpos(const char *str)
+{
+       return err_pos(last_cmd, str);
+}
+
+static void last_cmd_set(char *str)
+{
+       if (!str)
+               return;
+
+       strncpy(last_cmd, str, MAX_FILTER_STR_VAL - 1);
+}
+
+static void synth_err(u8 err_type, u8 err_pos)
+{
+       tracing_log_err(NULL, "synthetic_events", last_cmd, err_text,
+                       err_type, err_pos);
+}
+
 static int create_synth_event(int argc, const char **argv);
 static int synth_event_show(struct seq_file *m, struct dyn_event *ev);
 static int synth_event_release(struct dyn_event *ev);
@@ -545,8 +587,10 @@ static struct synth_field *parse_synth_field(int argc, 
const char **argv,
                field_type++;
 
        if (!strcmp(field_type, "unsigned")) {
-               if (argc < 3)
+               if (argc < 3) {
+                       synth_err(SYNTH_ERR_INCOMPLETE_TYPE, 
errpos(field_type));
                        return ERR_PTR(-EINVAL);
+               }
                prefix = "unsigned ";
                field_type = argv[1];
                field_name = argv[2];
@@ -573,6 +617,7 @@ static struct synth_field *parse_synth_field(int argc, 
const char **argv,
                goto free;
        }
        if (!is_good_name(field->name)) {
+               synth_err(SYNTH_ERR_BAD_NAME, errpos(field_name));
                ret = -EINVAL;
                goto free;
        }
@@ -601,6 +646,7 @@ static struct synth_field *parse_synth_field(int argc, 
const char **argv,
 
        size = synth_field_size(field->type);
        if (size < 0) {
+               synth_err(SYNTH_ERR_INVALID_TYPE, errpos(field_type));
                ret = -EINVAL;
                goto free;
        } else if (size == 0) {
@@ -621,6 +667,7 @@ static struct synth_field *parse_synth_field(int argc, 
const char **argv,
                        field->is_dynamic = true;
                        size = sizeof(u64);
                } else {
+                       synth_err(SYNTH_ERR_INVALID_TYPE, errpos(field_type));
                        ret = -EINVAL;
                        goto free;
                }
@@ -1098,12 +1145,47 @@ int synth_event_gen_cmd_array_start(struct dynevent_cmd 
*cmd, const char *name,
 }
 EXPORT_SYMBOL_GPL(synth_event_gen_cmd_array_start);
 
+static int save_cmdstr(int argc, const char *name, const char **argv)
+{
+        struct seq_buf s;
+       char *buf;
+       int i;
+
+        buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
+        if (!buf)
+                return -ENOMEM;
+
+        seq_buf_init(&s, buf, MAX_DYNEVENT_CMD_LEN);
+
+        seq_buf_puts(&s, name);
+
+        for (i = 0; i < argc; i++) {
+                seq_buf_putc(&s, ' ');
+                seq_buf_puts(&s, argv[i]);
+        }
+
+        if (!seq_buf_buffer_left(&s)) {
+                synth_err(SYNTH_ERR_CMD_TOO_LONG, 0);
+                kfree(buf);
+                return -EINVAL;
+        }
+        buf[s.len] = 0;
+        last_cmd_set(buf);
+
+        kfree(buf);
+        return 0;
+}
+
 static int __create_synth_event(int argc, const char *name, const char **argv)
 {
        struct synth_field *field, *fields[SYNTH_FIELDS_MAX];
        struct synth_event *event = NULL;
        int i, consumed = 0, n_fields = 0, ret = 0;
 
+       ret = save_cmdstr(argc, name, argv);
+       if (ret)
+               return ret;
+
        /*
         * Argument syntax:
         *  - Add synthetic event: <event_name> field[;field] ...
@@ -1111,18 +1193,22 @@ static int __create_synth_event(int argc, const char 
*name, const char **argv)
         *      where 'field' = type field_name
         */
 
-       if (name[0] == '\0' || argc < 1)
+       if (name[0] == '\0' || argc < 1) {
+               synth_err(SYNTH_ERR_CMD_INCOMPLETE, 0);
                return -EINVAL;
+       }
 
        mutex_lock(&event_mutex);
 
        if (!is_good_name(name)) {
+               synth_err(SYNTH_ERR_BAD_NAME, errpos(name));
                ret = -EINVAL;
                goto out;
        }
 
        event = find_synth_event(name);
        if (event) {
+               synth_err(SYNTH_ERR_EVENT_EXISTS, errpos(name));
                ret = -EEXIST;
                goto out;
        }
@@ -1131,6 +1217,7 @@ static int __create_synth_event(int argc, const char 
*name, const char **argv)
                if (strcmp(argv[i], ";") == 0)
                        continue;
                if (n_fields == SYNTH_FIELDS_MAX) {
+                       synth_err(SYNTH_ERR_TOO_MANY_FIELDS, 0);
                        ret = -EINVAL;
                        goto err;
                }
@@ -1145,6 +1232,7 @@ static int __create_synth_event(int argc, const char 
*name, const char **argv)
        }
 
        if (i < argc && strcmp(argv[i], ";") != 0) {
+               synth_err(SYNTH_ERR_INVALID_FIELD, errpos(argv[i]));
                ret = -EINVAL;
                goto err;
        }
-- 
2.17.1

Reply via email to