+++ /dev/null
-From 58954e6bb1b1066e34c6678826c6155aa17ec01f Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 5 Nov 2018 18:02:08 +0900
-Subject: tracing: Add unified dynamic event framework
-
-From: Masami Hiramatsu <mhiramat@kernel.org>
-
-[ Upstream commit 5448d44c38557fc15d1c53b608a9c9f0e1ca8f86 ]
-
-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 <tom.zanussi@linux.intel.com>
-Tested-by: Tom Zanussi <tom.zanussi@linux.intel.com>
-Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
-Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-Stable-dep-of: 4313e5a61304 ("tracing: Free buffers when a used dynamic event is removed")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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 e656d1e232da..7d7edc56eb5e 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 f81dadbc7c4a..9ff3c4fa91b6 100644
---- a/kernel/trace/Makefile
-+++ b/kernel/trace/Makefile
-@@ -78,6 +78,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 5b7a6e9b0ab6..44a0bc16a859 100644
---- a/kernel/trace/trace.c
-+++ b/kernel/trace/trace.c
-@@ -4655,6 +4655,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 000000000000..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 <mhiramat@kernel.org>
-+ */
-+
-+#include <linux/debugfs.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/mm.h>
-+#include <linux/mutex.h>
-+#include <linux/tracefs.h>
-+
-+#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(&ops->list);
-+ mutex_lock(&dyn_event_ops_mutex);
-+ list_add_tail(&ops->list, &dyn_event_ops_list);
-+ mutex_unlock(&dyn_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 = &argv[0][2];
-+ p = strchr(event, '/');
-+ if (p) {
-+ system = event;
-+ event = p + 1;
-+ *p = '\0';
-+ }
-+ if (event[0] == '\0')
-+ return -EINVAL;
-+
-+ mutex_lock(&event_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(&event_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(&dyn_event_ops_mutex);
-+ list_for_each_entry(ops, &dyn_event_ops_list, list) {
-+ ret = ops->create(argc, (const char **)argv);
-+ if (!ret || ret != -ECANCELED)
-+ break;
-+ }
-+ mutex_unlock(&dyn_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(&event_mutex);
-+ return seq_list_start(&dyn_event_list, *pos);
-+}
-+
-+void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos)
-+{
-+ return seq_list_next(v, &dyn_event_list, pos);
-+}
-+
-+void dyn_event_seq_stop(struct seq_file *m, void *v)
-+{
-+ mutex_unlock(&event_mutex);
-+}
-+
-+static int dyn_event_seq_show(struct seq_file *m, void *v)
-+{
-+ struct dyn_event *ev = v;
-+
-+ if (ev && ev->ops)
-+ return ev->ops->show(m, ev);
-+
-+ return 0;
-+}
-+
-+static const struct seq_operations dyn_event_seq_op = {
-+ .start = dyn_event_seq_start,
-+ .next = dyn_event_seq_next,
-+ .stop = dyn_event_seq_stop,
-+ .show = dyn_event_seq_show
-+};
-+
-+/*
-+ * dyn_events_release_all - Release all specific events
-+ * @type: the dyn_event_operations * which filters releasing events
-+ *
-+ * This releases all events which ->ops matches @type. If @type is NULL,
-+ * all events are released.
-+ * Return -EBUSY if any of them are in use, and return other errors when
-+ * it failed to free the given event. Except for -EBUSY, event releasing
-+ * process will be aborted at that point and there may be some other
-+ * releasable events on the list.
-+ */
-+int dyn_events_release_all(struct dyn_event_operations *type)
-+{
-+ struct dyn_event *ev, *tmp;
-+ int ret = 0;
-+
-+ mutex_lock(&event_mutex);
-+ for_each_dyn_event(ev) {
-+ if (type && ev->ops != type)
-+ continue;
-+ if (ev->ops->is_busy(ev)) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+ }
-+ for_each_dyn_event_safe(ev, tmp) {
-+ if (type && ev->ops != type)
-+ continue;
-+ ret = ev->ops->free(ev);
-+ if (ret)
-+ break;
-+ }
-+out:
-+ mutex_unlock(&event_mutex);
-+
-+ return ret;
-+}
-+
-+static int dyn_event_open(struct inode *inode, struct file *file)
-+{
-+ int ret;
-+
-+ if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
-+ ret = dyn_events_release_all(NULL);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return seq_open(file, &dyn_event_seq_op);
-+}
-+
-+static ssize_t dyn_event_write(struct file *file, const char __user *buffer,
-+ size_t count, loff_t *ppos)
-+{
-+ return trace_parse_run_command(file, buffer, count, ppos,
-+ create_dyn_event);
-+}
-+
-+static const struct file_operations dynamic_events_ops = {
-+ .owner = THIS_MODULE,
-+ .open = dyn_event_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = seq_release,
-+ .write = dyn_event_write,
-+};
-+
-+/* Make a tracefs interface for controlling dynamic events */
-+static __init int init_dynamic_event(void)
-+{
-+ struct dentry *d_tracer;
-+ struct dentry *entry;
-+
-+ d_tracer = tracing_init_dentry();
-+ if (IS_ERR(d_tracer))
-+ return 0;
-+
-+ entry = tracefs_create_file("dynamic_events", 0644, d_tracer,
-+ NULL, &dynamic_events_ops);
-+
-+ /* Event list interface */
-+ if (!entry)
-+ pr_warn("Could not create tracefs 'dynamic_events' entry\n");
-+
-+ return 0;
-+}
-+fs_initcall(init_dynamic_event);
-diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
-new file mode 100644
-index 000000000000..8c334064e4d6
---- /dev/null
-+++ b/kernel/trace/trace_dynevent.h
-@@ -0,0 +1,119 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Common header file for generic dynamic events.
-+ */
-+
-+#ifndef _TRACE_DYNEVENT_H
-+#define _TRACE_DYNEVENT_H
-+
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/mutex.h>
-+#include <linux/seq_file.h>
-+
-+#include "trace.h"
-+
-+struct dyn_event;
-+
-+/**
-+ * struct dyn_event_operations - Methods for each type of dynamic events
-+ *
-+ * These methods must be set for each type, since there is no default method.
-+ * Before using this for dyn_event_init(), it must be registered by
-+ * dyn_event_register().
-+ *
-+ * @create: Parse and create event method. This is invoked when user passes
-+ * a event definition to dynamic_events interface. This must not destruct
-+ * the arguments and return -ECANCELED if given arguments doesn't match its
-+ * command prefix.
-+ * @show: Showing method. This is invoked when user reads the event definitions
-+ * via dynamic_events interface.
-+ * @is_busy: Check whether given event is busy so that it can not be deleted.
-+ * Return true if it is busy, otherwides false.
-+ * @free: Delete the given event. Return 0 if success, otherwides error.
-+ * @match: Check whether given event and system name match this event.
-+ * Return true if it matches, otherwides false.
-+ *
-+ * Except for @create, these methods are called under holding event_mutex.
-+ */
-+struct dyn_event_operations {
-+ struct list_head list;
-+ int (*create)(int argc, const char *argv[]);
-+ int (*show)(struct seq_file *m, struct dyn_event *ev);
-+ bool (*is_busy)(struct dyn_event *ev);
-+ int (*free)(struct dyn_event *ev);
-+ bool (*match)(const char *system, const char *event,
-+ struct dyn_event *ev);
-+};
-+
-+/* Register new dyn_event type -- must be called at first */
-+int dyn_event_register(struct dyn_event_operations *ops);
-+
-+/**
-+ * struct dyn_event - Dynamic event list header
-+ *
-+ * The dyn_event structure encapsulates a list and a pointer to the operators
-+ * for making a global list of dynamic events.
-+ * User must includes this in each event structure, so that those events can
-+ * be added/removed via dynamic_events interface.
-+ */
-+struct dyn_event {
-+ struct list_head list;
-+ struct dyn_event_operations *ops;
-+};
-+
-+extern struct list_head dyn_event_list;
-+
-+static inline
-+int dyn_event_init(struct dyn_event *ev, struct dyn_event_operations *ops)
-+{
-+ if (!ev || !ops)
-+ return -EINVAL;
-+
-+ INIT_LIST_HEAD(&ev->list);
-+ ev->ops = ops;
-+ return 0;
-+}
-+
-+static inline int dyn_event_add(struct dyn_event *ev)
-+{
-+ lockdep_assert_held(&event_mutex);
-+
-+ if (!ev || !ev->ops)
-+ return -EINVAL;
-+
-+ list_add_tail(&ev->list, &dyn_event_list);
-+ return 0;
-+}
-+
-+static inline void dyn_event_remove(struct dyn_event *ev)
-+{
-+ lockdep_assert_held(&event_mutex);
-+ list_del_init(&ev->list);
-+}
-+
-+void *dyn_event_seq_start(struct seq_file *m, loff_t *pos);
-+void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos);
-+void dyn_event_seq_stop(struct seq_file *m, void *v);
-+int dyn_events_release_all(struct dyn_event_operations *type);
-+int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type);
-+
-+/*
-+ * for_each_dyn_event - iterate over the dyn_event list
-+ * @pos: the struct dyn_event * to use as a loop cursor
-+ *
-+ * This is just a basement of for_each macro. Wrap this for
-+ * each actual event structure with ops filtering.
-+ */
-+#define for_each_dyn_event(pos) \
-+ list_for_each_entry(pos, &dyn_event_list, list)
-+
-+/*
-+ * for_each_dyn_event - iterate over the dyn_event list safely
-+ * @pos: the struct dyn_event * to use as a loop cursor
-+ * @n: the struct dyn_event * to use as temporary storage
-+ */
-+#define for_each_dyn_event_safe(pos, n) \
-+ list_for_each_entry_safe(pos, n, &dyn_event_list, list)
-+
-+#endif
---
-2.35.1
-
+++ /dev/null
-From 85ebec2d5dd5264e83a4dc009833f390ce61be4e Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 23 Nov 2022 17:14:34 -0500
-Subject: tracing: Free buffers when a used dynamic event is removed
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Steven Rostedt (Google) <rostedt@goodmis.org>
-
-[ Upstream commit 4313e5a613049dfc1819a6dfb5f94cf2caff9452 ]
-
-After 65536 dynamic events have been added and removed, the "type" field
-of the event then uses the first type number that is available (not
-currently used by other events). A type number is the identifier of the
-binary blobs in the tracing ring buffer (known as events) to map them to
-logic that can parse the binary blob.
-
-The issue is that if a dynamic event (like a kprobe event) is traced and
-is in the ring buffer, and then that event is removed (because it is
-dynamic, which means it can be created and destroyed), if another dynamic
-event is created that has the same number that new event's logic on
-parsing the binary blob will be used.
-
-To show how this can be an issue, the following can crash the kernel:
-
- # cd /sys/kernel/tracing
- # for i in `seq 65536`; do
- echo 'p:kprobes/foo do_sys_openat2 $arg1:u32' > kprobe_events
- # done
-
-For every iteration of the above, the writing to the kprobe_events will
-remove the old event and create a new one (with the same format) and
-increase the type number to the next available on until the type number
-reaches over 65535 which is the max number for the 16 bit type. After it
-reaches that number, the logic to allocate a new number simply looks for
-the next available number. When an dynamic event is removed, that number
-is then available to be reused by the next dynamic event created. That is,
-once the above reaches the max number, the number assigned to the event in
-that loop will remain the same.
-
-Now that means deleting one dynamic event and created another will reuse
-the previous events type number. This is where bad things can happen.
-After the above loop finishes, the kprobes/foo event which reads the
-do_sys_openat2 function call's first parameter as an integer.
-
- # echo 1 > kprobes/foo/enable
- # cat /etc/passwd > /dev/null
- # cat trace
- cat-2211 [005] .... 2007.849603: foo: (do_sys_openat2+0x0/0x130) arg1=4294967196
- cat-2211 [005] .... 2007.849620: foo: (do_sys_openat2+0x0/0x130) arg1=4294967196
- cat-2211 [005] .... 2007.849838: foo: (do_sys_openat2+0x0/0x130) arg1=4294967196
- cat-2211 [005] .... 2007.849880: foo: (do_sys_openat2+0x0/0x130) arg1=4294967196
- # echo 0 > kprobes/foo/enable
-
-Now if we delete the kprobe and create a new one that reads a string:
-
- # echo 'p:kprobes/foo do_sys_openat2 +0($arg2):string' > kprobe_events
-
-And now we can the trace:
-
- # cat trace
- sendmail-1942 [002] ..... 530.136320: foo: (do_sys_openat2+0x0/0x240) arg1= cat-2046 [004] ..... 530.930817: foo: (do_sys_openat2+0x0/0x240) arg1="������������������������������������������������������������������������������������������������"
- cat-2046 [004] ..... 530.930961: foo: (do_sys_openat2+0x0/0x240) arg1="������������������������������������������������������������������������������������������������"
- cat-2046 [004] ..... 530.934278: foo: (do_sys_openat2+0x0/0x240) arg1="������������������������������������������������������������������������������������������������"
- cat-2046 [004] ..... 530.934563: foo: (do_sys_openat2+0x0/0x240) arg1="������������������������������������������������������������������������������������������������"
- bash-1515 [007] ..... 534.299093: foo: (do_sys_openat2+0x0/0x240) arg1="kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk���������@��4Z����;Y�����U
-
-And dmesg has:
-
-==================================================================
-BUG: KASAN: use-after-free in string+0xd4/0x1c0
-Read of size 1 at addr ffff88805fdbbfa0 by task cat/2049
-
- CPU: 0 PID: 2049 Comm: cat Not tainted 6.1.0-rc6-test+ #641
- Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v03.03 07/14/2016
- Call Trace:
- <TASK>
- dump_stack_lvl+0x5b/0x77
- print_report+0x17f/0x47b
- kasan_report+0xad/0x130
- string+0xd4/0x1c0
- vsnprintf+0x500/0x840
- seq_buf_vprintf+0x62/0xc0
- trace_seq_printf+0x10e/0x1e0
- print_type_string+0x90/0xa0
- print_kprobe_event+0x16b/0x290
- print_trace_line+0x451/0x8e0
- s_show+0x72/0x1f0
- seq_read_iter+0x58e/0x750
- seq_read+0x115/0x160
- vfs_read+0x11d/0x460
- ksys_read+0xa9/0x130
- do_syscall_64+0x3a/0x90
- entry_SYSCALL_64_after_hwframe+0x63/0xcd
- RIP: 0033:0x7fc2e972ade2
- Code: c0 e9 b2 fe ff ff 50 48 8d 3d b2 3f 0a 00 e8 05 f0 01 00 0f 1f 44 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 0f 05 <48> 3d 00 f0 ff ff 77 56 c3 0f 1f 44 00 00 48 83 ec 28 48 89 54 24
- RSP: 002b:00007ffc64e687c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
- RAX: ffffffffffffffda RBX: 0000000000020000 RCX: 00007fc2e972ade2
- RDX: 0000000000020000 RSI: 00007fc2e980d000 RDI: 0000000000000003
- RBP: 00007fc2e980d000 R08: 00007fc2e980c010 R09: 0000000000000000
- R10: 0000000000000022 R11: 0000000000000246 R12: 0000000000020f00
- R13: 0000000000000003 R14: 0000000000020000 R15: 0000000000020000
- </TASK>
-
- The buggy address belongs to the physical page:
- page:ffffea00017f6ec0 refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5fdbb
- flags: 0xfffffc0000000(node=0|zone=1|lastcpupid=0x1fffff)
- raw: 000fffffc0000000 0000000000000000 ffffea00017f6ec8 0000000000000000
- raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
- page dumped because: kasan: bad access detected
-
- Memory state around the buggy address:
- ffff88805fdbbe80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
- ffff88805fdbbf00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
- >ffff88805fdbbf80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
- ^
- ffff88805fdbc000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
- ffff88805fdbc080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
- ==================================================================
-
-This was found when Zheng Yejian sent a patch to convert the event type
-number assignment to use IDA, which gives the next available number, and
-this bug showed up in the fuzz testing by Yujie Liu and the kernel test
-robot. But after further analysis, I found that this behavior is the same
-as when the event type numbers go past the 16bit max (and the above shows
-that).
-
-As modules have a similar issue, but is dealt with by setting a
-"WAS_ENABLED" flag when a module event is enabled, and when the module is
-freed, if any of its events were enabled, the ring buffer that holds that
-event is also cleared, to prevent reading stale events. The same can be
-done for dynamic events.
-
-If any dynamic event that is being removed was enabled, then make sure the
-buffers they were enabled in are now cleared.
-
-Link: https://lkml.kernel.org/r/20221123171434.545706e3@gandalf.local.home
-Link: https://lore.kernel.org/all/20221110020319.1259291-1-zhengyejian1@huawei.com/
-
-Cc: stable@vger.kernel.org
-Cc: Andrew Morton <akpm@linux-foundation.org>
-Depends-on: e18eb8783ec49 ("tracing: Add tracing_reset_all_online_cpus_unlocked() function")
-Depends-on: 5448d44c38557 ("tracing: Add unified dynamic event framework")
-Depends-on: 6212dd29683ee ("tracing/kprobes: Use dyn_event framework for kprobe events")
-Depends-on: 065e63f951432 ("tracing: Only have rmmod clear buffers that its events were active in")
-Depends-on: 575380da8b469 ("tracing: Only clear trace buffer on module unload if event was traced")
-Fixes: 77b44d1b7c283 ("tracing/kprobes: Rename Kprobe-tracer to kprobe-event")
-Reported-by: Zheng Yejian <zhengyejian1@huawei.com>
-Reported-by: Yujie Liu <yujie.liu@intel.com>
-Reported-by: kernel test robot <yujie.liu@intel.com>
-Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
-Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- kernel/trace/trace_dynevent.c | 2 ++
- kernel/trace/trace_events.c | 11 ++++++++++-
- 2 files changed, 12 insertions(+), 1 deletion(-)
-
-diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
-index f17a887abb66..303067d38619 100644
---- a/kernel/trace/trace_dynevent.c
-+++ b/kernel/trace/trace_dynevent.c
-@@ -59,6 +59,7 @@ int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
- break;
- }
- }
-+ tracing_reset_all_online_cpus();
- mutex_unlock(&event_mutex);
-
- return ret;
-@@ -154,6 +155,7 @@ int dyn_events_release_all(struct dyn_event_operations *type)
- break;
- }
- out:
-+ tracing_reset_all_online_cpus();
- mutex_unlock(&event_mutex);
-
- return ret;
-diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
-index d2f9146d1ad7..c9aa7b4a4235 100644
---- a/kernel/trace/trace_events.c
-+++ b/kernel/trace/trace_events.c
-@@ -2369,7 +2369,10 @@ static int probe_remove_event_call(struct trace_event_call *call)
- * TRACE_REG_UNREGISTER.
- */
- if (file->flags & EVENT_FILE_FL_ENABLED)
-- return -EBUSY;
-+ goto busy;
-+
-+ if (file->flags & EVENT_FILE_FL_WAS_ENABLED)
-+ tr->clear_trace = true;
- /*
- * The do_for_each_event_file_safe() is
- * a double loop. After finding the call for this
-@@ -2382,6 +2385,12 @@ static int probe_remove_event_call(struct trace_event_call *call)
- __trace_remove_event_call(call);
-
- return 0;
-+ busy:
-+ /* No need to clear the trace now */
-+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
-+ tr->clear_trace = false;
-+ }
-+ return -EBUSY;
- }
-
- /* no event_mutex version */
---
-2.35.1
-