tracing: Define event fields early stage
authorMasami Hiramatsu <mhiramat@kernel.org>
Thu, 10 Sep 2020 12:38:48 +0000 (21:38 +0900)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Tue, 22 Sep 2020 01:06:04 +0000 (21:06 -0400)
Define event fields at early stage so that boot-time tracing can
access the event fields (like per-event filter setting).

Link: https://lkml.kernel.org/r/159974152862.478751.2023768466808361350.stgit@devnote2
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
kernel/trace/trace_events.c

index ee25d84..8e87fba 100644 (file)
@@ -2123,12 +2123,48 @@ event_subsystem_dir(struct trace_array *tr, const char *name,
        return NULL;
 }
 
+static int
+event_define_fields(struct trace_event_call *call)
+{
+       struct list_head *head;
+       int ret = 0;
+
+       /*
+        * Other events may have the same class. Only update
+        * the fields if they are not already defined.
+        */
+       head = trace_get_fields(call);
+       if (list_empty(head)) {
+               struct trace_event_fields *field = call->class->fields_array;
+               unsigned int offset = sizeof(struct trace_entry);
+
+               for (; field->type; field++) {
+                       if (field->type == TRACE_FUNCTION_TYPE) {
+                               field->define_fields(call);
+                               break;
+                       }
+
+                       offset = ALIGN(offset, field->align);
+                       ret = trace_define_field(call, field->type, field->name,
+                                                offset, field->size,
+                                                field->is_signed, field->filter_type);
+                       if (WARN_ON_ONCE(ret)) {
+                               pr_err("error code is %d\n", ret);
+                               break;
+                       }
+
+                       offset += field->size;
+               }
+       }
+
+       return ret;
+}
+
 static int
 event_create_dir(struct dentry *parent, struct trace_event_file *file)
 {
        struct trace_event_call *call = file->event_call;
        struct trace_array *tr = file->tr;
-       struct list_head *head;
        struct dentry *d_events;
        const char *name;
        int ret;
@@ -2162,35 +2198,10 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
                                  &ftrace_event_id_fops);
 #endif
 
-       /*
-        * Other events may have the same class. Only update
-        * the fields if they are not already defined.
-        */
-       head = trace_get_fields(call);
-       if (list_empty(head)) {
-               struct trace_event_fields *field = call->class->fields_array;
-               unsigned int offset = sizeof(struct trace_entry);
-
-               for (; field->type; field++) {
-                       if (field->type == TRACE_FUNCTION_TYPE) {
-                               ret = field->define_fields(call);
-                               break;
-                       }
-
-                       offset = ALIGN(offset, field->align);
-                       ret = trace_define_field(call, field->type, field->name,
-                                                offset, field->size,
-                                                field->is_signed, field->filter_type);
-                       if (ret)
-                               break;
-
-                       offset += field->size;
-               }
-               if (ret < 0) {
-                       pr_warn("Could not initialize trace point events/%s\n",
-                               name);
-                       return -1;
-               }
+       ret = event_define_fields(call);
+       if (ret < 0) {
+               pr_warn("Could not initialize trace point events/%s\n", name);
+               return ret;
        }
 
        /*
@@ -2493,7 +2504,7 @@ __trace_early_add_new_event(struct trace_event_call *call,
        if (!file)
                return -ENOMEM;
 
-       return 0;
+       return event_define_fields(call);
 }
 
 struct ftrace_module_file_ops;
@@ -3431,6 +3442,18 @@ static __init int event_trace_enable_again(void)
 
 early_initcall(event_trace_enable_again);
 
+/* Init fields which doesn't related to the tracefs */
+static __init int event_trace_init_fields(void)
+{
+       if (trace_define_generic_fields())
+               pr_warn("tracing: Failed to allocated generic fields");
+
+       if (trace_define_common_fields())
+               pr_warn("tracing: Failed to allocate common fields");
+
+       return 0;
+}
+
 __init int event_trace_init(void)
 {
        struct trace_array *tr;
@@ -3446,12 +3469,6 @@ __init int event_trace_init(void)
        if (!entry)
                pr_warn("Could not create tracefs 'available_events' entry\n");
 
-       if (trace_define_generic_fields())
-               pr_warn("tracing: Failed to allocated generic fields");
-
-       if (trace_define_common_fields())
-               pr_warn("tracing: Failed to allocate common fields");
-
        ret = early_event_add_tracer(NULL, tr);
        if (ret)
                return ret;
@@ -3469,6 +3486,7 @@ void __init trace_event_init(void)
        event_trace_memsetup();
        init_ftrace_syscalls();
        event_trace_enable();
+       event_trace_init_fields();
 }
 
 #ifdef CONFIG_EVENT_TRACE_STARTUP_TEST