[for-next][PATCH 23/30] tracing: Add unified dynamic event framework

2018-12-05 Thread Steven Rostedt
From: Masami Hiramatsu 

Add unified dynamic event framework for ftrace kprobes, uprobes
and synthetic events. Those dynamic events can be co-exist on
same file because those syntax doesn't overlap.

This introduces a framework part which provides a unified tracefs
interface and operations.

Link: 
http://lkml.kernel.org/r/154140852824.17322.12250362185969352095.stgit@devbox

Reviewed-by: Tom Zanussi 
Tested-by: Tom Zanussi 
Signed-off-by: Masami Hiramatsu 
Signed-off-by: Steven Rostedt (VMware) 
---
 kernel/trace/Kconfig  |   3 +
 kernel/trace/Makefile |   1 +
 kernel/trace/trace.c  |   4 +
 kernel/trace/trace_dynevent.c | 210 ++
 kernel/trace/trace_dynevent.h | 119 +++
 5 files changed, 337 insertions(+)
 create mode 100644 kernel/trace/trace_dynevent.c
 create mode 100644 kernel/trace/trace_dynevent.h

diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 5e3de28c7677..bf2e8a5a91f1 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -518,6 +518,9 @@ config BPF_EVENTS
help
  This allows the user to attach BPF programs to kprobe events.
 
+config DYNAMIC_EVENTS
+   def_bool n
+
 config PROBE_EVENTS
def_bool n
 
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index c7ade7965464..c2b2148bb1d2 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -79,6 +79,7 @@ endif
 ifeq ($(CONFIG_TRACING),y)
 obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
 endif
+obj-$(CONFIG_DYNAMIC_EVENTS) += trace_dynevent.o
 obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
 obj-$(CONFIG_UPROBE_EVENTS) += trace_uprobe.o
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 194c01838e3f..7e0332f90ed4 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4604,6 +4604,10 @@ static const char readme_msg[] =
"\t\t\t  traces\n"
 #endif
 #endif /* CONFIG_STACK_TRACER */
+#ifdef CONFIG_DYNAMIC_EVENTS
+   "  dynamic_events\t\t- Add/remove/show the generic dynamic events\n"
+   "\t\t\t  Write into this file to define/undefine new trace events.\n"
+#endif
 #ifdef CONFIG_KPROBE_EVENTS
"  kprobe_events\t\t- Add/remove/show the kernel dynamic events\n"
"\t\t\t  Write into this file to define/undefine new trace events.\n"
diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
new file mode 100644
index ..f17a887abb66
--- /dev/null
+++ b/kernel/trace/trace_dynevent.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic dynamic event control interface
+ *
+ * Copyright (C) 2018 Masami Hiramatsu 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "trace.h"
+#include "trace_dynevent.h"
+
+static DEFINE_MUTEX(dyn_event_ops_mutex);
+static LIST_HEAD(dyn_event_ops_list);
+
+int dyn_event_register(struct dyn_event_operations *ops)
+{
+   if (!ops || !ops->create || !ops->show || !ops->is_busy ||
+   !ops->free || !ops->match)
+   return -EINVAL;
+
+   INIT_LIST_HEAD(>list);
+   mutex_lock(_event_ops_mutex);
+   list_add_tail(>list, _event_ops_list);
+   mutex_unlock(_event_ops_mutex);
+   return 0;
+}
+
+int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
+{
+   struct dyn_event *pos, *n;
+   char *system = NULL, *event, *p;
+   int ret = -ENOENT;
+
+   if (argv[0][1] != ':')
+   return -EINVAL;
+
+   event = [0][2];
+   p = strchr(event, '/');
+   if (p) {
+   system = event;
+   event = p + 1;
+   *p = '\0';
+   }
+   if (event[0] == '\0')
+   return -EINVAL;
+
+   mutex_lock(_mutex);
+   for_each_dyn_event_safe(pos, n) {
+   if (type && type != pos->ops)
+   continue;
+   if (pos->ops->match(system, event, pos)) {
+   ret = pos->ops->free(pos);
+   break;
+   }
+   }
+   mutex_unlock(_mutex);
+
+   return ret;
+}
+
+static int create_dyn_event(int argc, char **argv)
+{
+   struct dyn_event_operations *ops;
+   int ret;
+
+   if (argv[0][0] == '-')
+   return dyn_event_release(argc, argv, NULL);
+
+   mutex_lock(_event_ops_mutex);
+   list_for_each_entry(ops, _event_ops_list, list) {
+   ret = ops->create(argc, (const char **)argv);
+   if (!ret || ret != -ECANCELED)
+   break;
+   }
+   mutex_unlock(_event_ops_mutex);
+   if (ret == -ECANCELED)
+   ret = -EINVAL;
+
+   return ret;
+}
+
+/* Protected by event_mutex */
+LIST_HEAD(dyn_event_list);
+
+void *dyn_event_seq_start(struct seq_file *m, loff_t *pos)
+{
+   mutex_lock(_mutex);
+   return seq_list_start(_event_list, *pos);
+}
+
+void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+   return seq_list_next(v, _event_list, pos);

[for-next][PATCH 23/30] tracing: Add unified dynamic event framework

2018-12-05 Thread Steven Rostedt
From: Masami Hiramatsu 

Add unified dynamic event framework for ftrace kprobes, uprobes
and synthetic events. Those dynamic events can be co-exist on
same file because those syntax doesn't overlap.

This introduces a framework part which provides a unified tracefs
interface and operations.

Link: 
http://lkml.kernel.org/r/154140852824.17322.12250362185969352095.stgit@devbox

Reviewed-by: Tom Zanussi 
Tested-by: Tom Zanussi 
Signed-off-by: Masami Hiramatsu 
Signed-off-by: Steven Rostedt (VMware) 
---
 kernel/trace/Kconfig  |   3 +
 kernel/trace/Makefile |   1 +
 kernel/trace/trace.c  |   4 +
 kernel/trace/trace_dynevent.c | 210 ++
 kernel/trace/trace_dynevent.h | 119 +++
 5 files changed, 337 insertions(+)
 create mode 100644 kernel/trace/trace_dynevent.c
 create mode 100644 kernel/trace/trace_dynevent.h

diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 5e3de28c7677..bf2e8a5a91f1 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -518,6 +518,9 @@ config BPF_EVENTS
help
  This allows the user to attach BPF programs to kprobe events.
 
+config DYNAMIC_EVENTS
+   def_bool n
+
 config PROBE_EVENTS
def_bool n
 
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index c7ade7965464..c2b2148bb1d2 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -79,6 +79,7 @@ endif
 ifeq ($(CONFIG_TRACING),y)
 obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
 endif
+obj-$(CONFIG_DYNAMIC_EVENTS) += trace_dynevent.o
 obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
 obj-$(CONFIG_UPROBE_EVENTS) += trace_uprobe.o
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 194c01838e3f..7e0332f90ed4 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4604,6 +4604,10 @@ static const char readme_msg[] =
"\t\t\t  traces\n"
 #endif
 #endif /* CONFIG_STACK_TRACER */
+#ifdef CONFIG_DYNAMIC_EVENTS
+   "  dynamic_events\t\t- Add/remove/show the generic dynamic events\n"
+   "\t\t\t  Write into this file to define/undefine new trace events.\n"
+#endif
 #ifdef CONFIG_KPROBE_EVENTS
"  kprobe_events\t\t- Add/remove/show the kernel dynamic events\n"
"\t\t\t  Write into this file to define/undefine new trace events.\n"
diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
new file mode 100644
index ..f17a887abb66
--- /dev/null
+++ b/kernel/trace/trace_dynevent.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic dynamic event control interface
+ *
+ * Copyright (C) 2018 Masami Hiramatsu 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "trace.h"
+#include "trace_dynevent.h"
+
+static DEFINE_MUTEX(dyn_event_ops_mutex);
+static LIST_HEAD(dyn_event_ops_list);
+
+int dyn_event_register(struct dyn_event_operations *ops)
+{
+   if (!ops || !ops->create || !ops->show || !ops->is_busy ||
+   !ops->free || !ops->match)
+   return -EINVAL;
+
+   INIT_LIST_HEAD(>list);
+   mutex_lock(_event_ops_mutex);
+   list_add_tail(>list, _event_ops_list);
+   mutex_unlock(_event_ops_mutex);
+   return 0;
+}
+
+int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
+{
+   struct dyn_event *pos, *n;
+   char *system = NULL, *event, *p;
+   int ret = -ENOENT;
+
+   if (argv[0][1] != ':')
+   return -EINVAL;
+
+   event = [0][2];
+   p = strchr(event, '/');
+   if (p) {
+   system = event;
+   event = p + 1;
+   *p = '\0';
+   }
+   if (event[0] == '\0')
+   return -EINVAL;
+
+   mutex_lock(_mutex);
+   for_each_dyn_event_safe(pos, n) {
+   if (type && type != pos->ops)
+   continue;
+   if (pos->ops->match(system, event, pos)) {
+   ret = pos->ops->free(pos);
+   break;
+   }
+   }
+   mutex_unlock(_mutex);
+
+   return ret;
+}
+
+static int create_dyn_event(int argc, char **argv)
+{
+   struct dyn_event_operations *ops;
+   int ret;
+
+   if (argv[0][0] == '-')
+   return dyn_event_release(argc, argv, NULL);
+
+   mutex_lock(_event_ops_mutex);
+   list_for_each_entry(ops, _event_ops_list, list) {
+   ret = ops->create(argc, (const char **)argv);
+   if (!ret || ret != -ECANCELED)
+   break;
+   }
+   mutex_unlock(_event_ops_mutex);
+   if (ret == -ECANCELED)
+   ret = -EINVAL;
+
+   return ret;
+}
+
+/* Protected by event_mutex */
+LIST_HEAD(dyn_event_list);
+
+void *dyn_event_seq_start(struct seq_file *m, loff_t *pos)
+{
+   mutex_lock(_mutex);
+   return seq_list_start(_event_list, *pos);
+}
+
+void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+   return seq_list_next(v, _event_list, pos);