* [PATCH 4.19 01/18] Revert "selftests: mm: fix map_hugetlb failure on 64K page size systems"
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 02/18] dm: limit the number of targets and parameter size area Greg Kroah-Hartman
` (21 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches,
shuah@kernel.org, sashal@kernel.org, vegard.nossum@oracle.com, darren.kenny@oracle.com, Harshit Mogalapalli,
Shuah Khan, Harshit Mogalapalli
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
This reverts commit abdbd5f3e8c504d864fdc032dd5a4eb481cb12bf which is commit
91b80cc5b39f00399e8e2d17527cad2c7fa535e2 upstream.
map_hugetlb.c:18:10: fatal error: vm_util.h: No such file or directory
18 | #include "vm_util.h"
| ^~~~~~~~~~~
compilation terminated.
vm_util.h is not present in 4.19.y, as commit:642bc52aed9c ("selftests:
vm: bring common functions to a new file") is not present in stable
kernels <=6.1.y
Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
tools/testing/selftests/vm/map_hugetlb.c | 7 -------
1 file changed, 7 deletions(-)
--- a/tools/testing/selftests/vm/map_hugetlb.c
+++ b/tools/testing/selftests/vm/map_hugetlb.c
@@ -15,7 +15,6 @@
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
-#include "vm_util.h"
#define LENGTH (256UL*1024*1024)
#define PROTECTION (PROT_READ | PROT_WRITE)
@@ -71,16 +70,10 @@ int main(int argc, char **argv)
{
void *addr;
int ret;
- size_t hugepage_size;
size_t length = LENGTH;
int flags = FLAGS;
int shift = 0;
- hugepage_size = default_huge_page_size();
- /* munmap with fail if the length is not page aligned */
- if (hugepage_size > length)
- length = hugepage_size;
-
if (argc > 1)
length = atol(argv[1]) << 20;
if (argc > 2) {
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 02/18] dm: limit the number of targets and parameter size area
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 01/18] Revert "selftests: mm: fix map_hugetlb failure on 64K page size systems" Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 03/18] btrfs: add missing mutex_unlock in btrfs_relocate_sys_chunks() Greg Kroah-Hartman
` (20 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mikulas Patocka, Mike Snitzer,
Srish Srinivasan
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <mpatocka@redhat.com>
commit bd504bcfec41a503b32054da5472904b404341a4 upstream.
The kvmalloc function fails with a warning if the size is larger than
INT_MAX. The warning was triggered by a syscall testing robot.
In order to avoid the warning, this commit limits the number of targets to
1048576 and the size of the parameter area to 1073741824.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
[srish: Apply to stable branch linux-4.19.y]
Signed-off-by: Srish Srinivasan <srish.srinivasan@broadcom.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/md/dm-core.h | 2 ++
drivers/md/dm-ioctl.c | 3 ++-
drivers/md/dm-table.c | 9 +++++++--
3 files changed, 11 insertions(+), 3 deletions(-)
--- a/drivers/md/dm-core.h
+++ b/drivers/md/dm-core.h
@@ -18,6 +18,8 @@
#include "dm.h"
#define DM_RESERVED_MAX_IOS 1024
+#define DM_MAX_TARGETS 1048576
+#define DM_MAX_TARGET_PARAMS 1024
struct dm_kobject_holder {
struct kobject kobj;
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1734,7 +1734,8 @@ static int copy_params(struct dm_ioctl _
if (copy_from_user(param_kernel, user, minimum_data_size))
return -EFAULT;
- if (param_kernel->data_size < minimum_data_size)
+ if (unlikely(param_kernel->data_size < minimum_data_size) ||
+ unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS))
return -EINVAL;
secure_data = param_kernel->flags & DM_SECURE_DATA_FLAG;
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -187,7 +187,12 @@ static int alloc_targets(struct dm_table
int dm_table_create(struct dm_table **result, fmode_t mode,
unsigned num_targets, struct mapped_device *md)
{
- struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
+ struct dm_table *t;
+
+ if (num_targets > DM_MAX_TARGETS)
+ return -EOVERFLOW;
+
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
if (!t)
return -ENOMEM;
@@ -202,7 +207,7 @@ int dm_table_create(struct dm_table **re
if (!num_targets) {
kfree(t);
- return -ENOMEM;
+ return -EOVERFLOW;
}
if (alloc_targets(t, num_targets)) {
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 03/18] btrfs: add missing mutex_unlock in btrfs_relocate_sys_chunks()
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 01/18] Revert "selftests: mm: fix map_hugetlb failure on 64K page size systems" Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 02/18] dm: limit the number of targets and parameter size area Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 04/18] tracing: Simplify creation and deletion of synthetic events Greg Kroah-Hartman
` (19 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pavel Machek, Dominique Martinet,
David Sterba
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dominique Martinet <dominique.martinet@atmark-techno.com>
commit 9af503d91298c3f2945e73703f0e00995be08c30 upstream.
The previous patch that replaced BUG_ON by error handling forgot to
unlock the mutex in the error path.
Link: https://lore.kernel.org/all/Zh%2fHpAGFqa7YAFuM@duo.ucw.cz
Reported-by: Pavel Machek <pavel@denx.de>
Fixes: 7411055db5ce ("btrfs: handle chunk tree lookup error in btrfs_relocate_sys_chunks()")
CC: stable@vger.kernel.org
Reviewed-by: Pavel Machek <pavel@denx.de>
Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/btrfs/volumes.c | 1 +
1 file changed, 1 insertion(+)
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2957,6 +2957,7 @@ again:
* alignment and size).
*/
ret = -EUCLEAN;
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
goto error;
}
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 04/18] tracing: Simplify creation and deletion of synthetic events
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (2 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 03/18] btrfs: add missing mutex_unlock in btrfs_relocate_sys_chunks() Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 05/18] tracing: Add unified dynamic event framework Greg Kroah-Hartman
` (18 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Tom Zanussi, Masami Hiramatsu, Steven Rostedt (VMware),
George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu <mhiramat@kernel.org>
commit faacb361f271be4baf2d807e2eeaba87e059225f upstream.
Since the event_mutex and synth_event_mutex ordering issue
is gone, we can skip existing event check when adding or
deleting events, and some redundant code in error path.
This changes release_all_synth_events() to abort the process
when it hits any error and returns the error code. It succeeds
only if it has no error.
Link: http://lkml.kernel.org/r/154140847194.17322.17960275728005067803.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>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace_events_hist.c | 53 +++++++++++++--------------------------
1 file changed, 18 insertions(+), 35 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -1028,18 +1028,6 @@ struct hist_var_data {
struct hist_trigger_data *hist_data;
};
-static void add_or_delete_synth_event(struct synth_event *event, int delete)
-{
- if (delete)
- free_synth_event(event);
- else {
- if (!find_synth_event(event->name))
- list_add(&event->list, &synth_event_list);
- else
- free_synth_event(event);
- }
-}
-
static int create_synth_event(int argc, char **argv)
{
struct synth_field *field, *fields[SYNTH_FIELDS_MAX];
@@ -1072,15 +1060,16 @@ static int create_synth_event(int argc,
if (event) {
if (delete_event) {
if (event->ref) {
- event = NULL;
ret = -EBUSY;
goto out;
}
- list_del(&event->list);
- goto out;
- }
- event = NULL;
- ret = -EEXIST;
+ ret = unregister_synth_event(event);
+ if (!ret) {
+ list_del(&event->list);
+ free_synth_event(event);
+ }
+ } else
+ ret = -EEXIST;
goto out;
} else if (delete_event) {
ret = -ENOENT;
@@ -1120,29 +1109,21 @@ static int create_synth_event(int argc,
event = NULL;
goto err;
}
+ ret = register_synth_event(event);
+ if (!ret)
+ list_add(&event->list, &synth_event_list);
+ else
+ free_synth_event(event);
out:
- if (event) {
- if (delete_event) {
- ret = unregister_synth_event(event);
- add_or_delete_synth_event(event, !ret);
- } else {
- ret = register_synth_event(event);
- add_or_delete_synth_event(event, ret);
- }
- }
mutex_unlock(&synth_event_mutex);
mutex_unlock(&event_mutex);
return ret;
err:
- mutex_unlock(&synth_event_mutex);
- mutex_unlock(&event_mutex);
-
for (i = 0; i < n_fields; i++)
free_synth_field(fields[i]);
- free_synth_event(event);
- return ret;
+ goto out;
}
static int release_all_synth_events(void)
@@ -1161,10 +1142,12 @@ static int release_all_synth_events(void
}
list_for_each_entry_safe(event, e, &synth_event_list, list) {
- list_del(&event->list);
-
ret = unregister_synth_event(event);
- add_or_delete_synth_event(event, !ret);
+ if (!ret) {
+ list_del(&event->list);
+ free_synth_event(event);
+ } else
+ break;
}
mutex_unlock(&synth_event_mutex);
mutex_unlock(&event_mutex);
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 05/18] tracing: Add unified dynamic event framework
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (3 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 04/18] tracing: Simplify creation and deletion of synthetic events Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 06/18] tracing: Use dyn_event framework for synthetic events Greg Kroah-Hartman
` (17 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Tom Zanussi, Masami Hiramatsu, Steven Rostedt (VMware),
George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu <mhiramat@kernel.org>
commit 5448d44c38557fc15d1c53b608a9c9f0e1ca8f86 upstream.
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>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.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
--- 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
--- 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
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4665,6 +4665,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"
--- /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);
--- /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
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 06/18] tracing: Use dyn_event framework for synthetic events
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (4 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 05/18] tracing: Add unified dynamic event framework Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 07/18] tracing: Remove unneeded synth_event_mutex Greg Kroah-Hartman
` (16 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Tom Zanussi, Masami Hiramatsu, Steven Rostedt (VMware),
George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu <mhiramat@kernel.org>
commit 7bbab38d07f3185fddf6fce126e2239010efdfce upstream.
Use dyn_event framework for synthetic events. This shows
synthetic events on "tracing/dynamic_events" file in addition
to tracing/synthetic_events interface.
User can also define new events via tracing/dynamic_events
with "s:" prefix. So, the new syntax is below;
s:[synthetic/]EVENT_NAME TYPE ARG; [TYPE ARG;]...
To remove events via tracing/dynamic_events, you can use
"-:" prefix as same as other events.
Link: http://lkml.kernel.org/r/154140861301.17322.15454611233735614508.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>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/Kconfig | 1
kernel/trace/trace.c | 8 +
kernel/trace/trace_events_hist.c | 265 ++++++++++++++++++++++++---------------
3 files changed, 176 insertions(+), 98 deletions(-)
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -633,6 +633,7 @@ config HIST_TRIGGERS
depends on ARCH_HAVE_NMI_SAFE_CMPXCHG
select TRACING_MAP
select TRACING
+ select DYNAMIC_EVENTS
default n
help
Hist triggers allow one or more arbitrary trace event fields
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4681,6 +4681,9 @@ static const char readme_msg[] =
"\t accepts: event-definitions (one definition per line)\n"
"\t Format: p[:[<group>/]<event>] <place> [<args>]\n"
"\t r[maxactive][:[<group>/]<event>] <place> [<args>]\n"
+#ifdef CONFIG_HIST_TRIGGERS
+ "\t s:[synthetic/]<event> <field> [<field>]\n"
+#endif
"\t -:[<group>/]<event>\n"
#ifdef CONFIG_KPROBE_EVENTS
"\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
@@ -4694,6 +4697,11 @@ static const char readme_msg[] =
"\t $stack<index>, $stack, $retval, $comm\n"
"\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string,\n"
"\t b<bit-width>@<bit-offset>/<container-size>\n"
+#ifdef CONFIG_HIST_TRIGGERS
+ "\t field: <stype> <name>;\n"
+ "\t stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
+ "\t [unsigned] char/int/long\n"
+#endif
#endif
" events/\t\t- Directory containing all trace event subsystems:\n"
" enable\t\t- Write 0/1 to enable/disable tracing of all events\n"
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -15,6 +15,7 @@
#include "tracing_map.h"
#include "trace.h"
+#include "trace_dynevent.h"
#define SYNTH_SYSTEM "synthetic"
#define SYNTH_FIELDS_MAX 16
@@ -291,6 +292,21 @@ struct hist_trigger_data {
unsigned int n_max_var_str;
};
+static int synth_event_create(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);
+static bool synth_event_is_busy(struct dyn_event *ev);
+static bool synth_event_match(const char *system, const char *event,
+ struct dyn_event *ev);
+
+static struct dyn_event_operations synth_event_ops = {
+ .create = synth_event_create,
+ .show = synth_event_show,
+ .is_busy = synth_event_is_busy,
+ .free = synth_event_release,
+ .match = synth_event_match,
+};
+
struct synth_field {
char *type;
char *name;
@@ -300,7 +316,7 @@ struct synth_field {
};
struct synth_event {
- struct list_head list;
+ struct dyn_event devent;
int ref;
char *name;
struct synth_field **fields;
@@ -311,6 +327,32 @@ struct synth_event {
struct tracepoint *tp;
};
+static bool is_synth_event(struct dyn_event *ev)
+{
+ return ev->ops == &synth_event_ops;
+}
+
+static struct synth_event *to_synth_event(struct dyn_event *ev)
+{
+ return container_of(ev, struct synth_event, devent);
+}
+
+static bool synth_event_is_busy(struct dyn_event *ev)
+{
+ struct synth_event *event = to_synth_event(ev);
+
+ return event->ref != 0;
+}
+
+static bool synth_event_match(const char *system, const char *event,
+ struct dyn_event *ev)
+{
+ struct synth_event *sev = to_synth_event(ev);
+
+ return strcmp(sev->name, event) == 0 &&
+ (!system || strcmp(system, SYNTH_SYSTEM) == 0);
+}
+
struct action_data;
typedef void (*action_fn_t) (struct hist_trigger_data *hist_data,
@@ -401,7 +443,6 @@ static bool have_hist_err(void)
return false;
}
-static LIST_HEAD(synth_event_list);
static DEFINE_MUTEX(synth_event_mutex);
struct synth_trace_event {
@@ -758,14 +799,12 @@ static void free_synth_field(struct synt
kfree(field);
}
-static struct synth_field *parse_synth_field(int argc, char **argv,
+static struct synth_field *parse_synth_field(int argc, const char **argv,
int *consumed)
{
struct synth_field *field;
- const char *prefix = NULL;
- char *field_type = argv[0], *field_name;
+ const char *prefix = NULL, *field_type = argv[0], *field_name, *array;
int len, ret = 0;
- char *array;
if (field_type[0] == ';')
field_type++;
@@ -782,20 +821,31 @@ static struct synth_field *parse_synth_f
*consumed = 2;
}
- len = strlen(field_name);
- if (field_name[len - 1] == ';')
- field_name[len - 1] = '\0';
-
field = kzalloc(sizeof(*field), GFP_KERNEL);
if (!field)
return ERR_PTR(-ENOMEM);
- len = strlen(field_type) + 1;
+ len = strlen(field_name);
array = strchr(field_name, '[');
if (array)
+ len -= strlen(array);
+ else if (field_name[len - 1] == ';')
+ len--;
+
+ field->name = kmemdup_nul(field_name, len, GFP_KERNEL);
+ if (!field->name) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ if (field_type[0] == ';')
+ field_type++;
+ len = strlen(field_type) + 1;
+ if (array)
len += strlen(array);
if (prefix)
len += strlen(prefix);
+
field->type = kzalloc(len, GFP_KERNEL);
if (!field->type) {
ret = -ENOMEM;
@@ -806,7 +856,8 @@ static struct synth_field *parse_synth_f
strcat(field->type, field_type);
if (array) {
strcat(field->type, array);
- *array = '\0';
+ if (field->type[len - 1] == ';')
+ field->type[len - 1] = '\0';
}
field->size = synth_field_size(field->type);
@@ -820,11 +871,6 @@ static struct synth_field *parse_synth_f
field->is_signed = synth_field_signed(field->type);
- field->name = kstrdup(field_name, GFP_KERNEL);
- if (!field->name) {
- ret = -ENOMEM;
- goto free;
- }
out:
return field;
free:
@@ -888,9 +934,13 @@ static inline void trace_synth(struct sy
static struct synth_event *find_synth_event(const char *name)
{
+ struct dyn_event *pos;
struct synth_event *event;
- list_for_each_entry(event, &synth_event_list, list) {
+ for_each_dyn_event(pos) {
+ if (!is_synth_event(pos))
+ continue;
+ event = to_synth_event(pos);
if (strcmp(event->name, name) == 0)
return event;
}
@@ -941,7 +991,7 @@ static int register_synth_event(struct s
ret = set_synth_event_print_fmt(call);
if (ret < 0) {
- trace_remove_event_call(call);
+ trace_remove_event_call_nolock(call);
goto err;
}
out:
@@ -979,7 +1029,7 @@ static void free_synth_event(struct synt
kfree(event);
}
-static struct synth_event *alloc_synth_event(char *event_name, int n_fields,
+static struct synth_event *alloc_synth_event(const char *name, int n_fields,
struct synth_field **fields)
{
struct synth_event *event;
@@ -991,7 +1041,7 @@ static struct synth_event *alloc_synth_e
goto out;
}
- event->name = kstrdup(event_name, GFP_KERNEL);
+ event->name = kstrdup(name, GFP_KERNEL);
if (!event->name) {
kfree(event);
event = ERR_PTR(-ENOMEM);
@@ -1005,6 +1055,8 @@ static struct synth_event *alloc_synth_e
goto out;
}
+ dyn_event_init(&event->devent, &synth_event_ops);
+
for (i = 0; i < n_fields; i++)
event->fields[i] = fields[i];
@@ -1028,16 +1080,11 @@ struct hist_var_data {
struct hist_trigger_data *hist_data;
};
-static int create_synth_event(int argc, char **argv)
+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;
- bool delete_event = false;
int i, consumed = 0, n_fields = 0, ret = 0;
- char *name;
-
- mutex_lock(&event_mutex);
- mutex_lock(&synth_event_mutex);
/*
* Argument syntax:
@@ -1045,43 +1092,20 @@ static int create_synth_event(int argc,
* - Remove synthetic event: !<event_name> field[;field] ...
* where 'field' = type field_name
*/
- if (argc < 1) {
- ret = -EINVAL;
- goto out;
- }
- name = argv[0];
- if (name[0] == '!') {
- delete_event = true;
- name++;
- }
+ if (name[0] == '\0' || argc < 1)
+ return -EINVAL;
+
+ mutex_lock(&event_mutex);
+ mutex_lock(&synth_event_mutex);
event = find_synth_event(name);
if (event) {
- if (delete_event) {
- if (event->ref) {
- ret = -EBUSY;
- goto out;
- }
- ret = unregister_synth_event(event);
- if (!ret) {
- list_del(&event->list);
- free_synth_event(event);
- }
- } else
- ret = -EEXIST;
- goto out;
- } else if (delete_event) {
- ret = -ENOENT;
+ ret = -EEXIST;
goto out;
}
- if (argc < 2) {
- ret = -EINVAL;
- goto out;
- }
-
- for (i = 1; i < argc - 1; i++) {
+ for (i = 0; i < argc - 1; i++) {
if (strcmp(argv[i], ";") == 0)
continue;
if (n_fields == SYNTH_FIELDS_MAX) {
@@ -1111,7 +1135,7 @@ static int create_synth_event(int argc,
}
ret = register_synth_event(event);
if (!ret)
- list_add(&event->list, &synth_event_list);
+ dyn_event_add(&event->devent);
else
free_synth_event(event);
out:
@@ -1126,57 +1150,77 @@ static int create_synth_event(int argc,
goto out;
}
-static int release_all_synth_events(void)
+static int create_or_delete_synth_event(int argc, char **argv)
{
- struct synth_event *event, *e;
- int ret = 0;
-
- mutex_lock(&event_mutex);
- mutex_lock(&synth_event_mutex);
-
- list_for_each_entry(event, &synth_event_list, list) {
- if (event->ref) {
- mutex_unlock(&synth_event_mutex);
- return -EBUSY;
- }
- }
+ const char *name = argv[0];
+ struct synth_event *event = NULL;
+ int ret;
- list_for_each_entry_safe(event, e, &synth_event_list, list) {
- ret = unregister_synth_event(event);
- if (!ret) {
- list_del(&event->list);
- free_synth_event(event);
+ /* trace_run_command() ensures argc != 0 */
+ if (name[0] == '!') {
+ mutex_lock(&event_mutex);
+ mutex_lock(&synth_event_mutex);
+ event = find_synth_event(name + 1);
+ if (event) {
+ if (event->ref)
+ ret = -EBUSY;
+ else {
+ ret = unregister_synth_event(event);
+ if (!ret) {
+ dyn_event_remove(&event->devent);
+ free_synth_event(event);
+ }
+ }
} else
- break;
+ ret = -ENOENT;
+ mutex_unlock(&synth_event_mutex);
+ mutex_unlock(&event_mutex);
+ return ret;
}
- mutex_unlock(&synth_event_mutex);
- mutex_unlock(&event_mutex);
- return ret;
+ ret = __create_synth_event(argc - 1, name, (const char **)argv + 1);
+ return ret == -ECANCELED ? -EINVAL : ret;
}
-
-static void *synth_events_seq_start(struct seq_file *m, loff_t *pos)
+static int synth_event_create(int argc, const char **argv)
{
- mutex_lock(&synth_event_mutex);
+ const char *name = argv[0];
+ int len;
- return seq_list_start(&synth_event_list, *pos);
+ if (name[0] != 's' || name[1] != ':')
+ return -ECANCELED;
+ name += 2;
+
+ /* This interface accepts group name prefix */
+ if (strchr(name, '/')) {
+ len = sizeof(SYNTH_SYSTEM "/") - 1;
+ if (strncmp(name, SYNTH_SYSTEM "/", len))
+ return -EINVAL;
+ name += len;
+ }
+ return __create_synth_event(argc - 1, name, argv + 1);
}
-static void *synth_events_seq_next(struct seq_file *m, void *v, loff_t *pos)
+static int synth_event_release(struct dyn_event *ev)
{
- return seq_list_next(v, &synth_event_list, pos);
-}
+ struct synth_event *event = to_synth_event(ev);
+ int ret;
-static void synth_events_seq_stop(struct seq_file *m, void *v)
-{
- mutex_unlock(&synth_event_mutex);
+ if (event->ref)
+ return -EBUSY;
+
+ ret = unregister_synth_event(event);
+ if (ret)
+ return ret;
+
+ dyn_event_remove(ev);
+ free_synth_event(event);
+ return 0;
}
-static int synth_events_seq_show(struct seq_file *m, void *v)
+static int __synth_event_show(struct seq_file *m, struct synth_event *event)
{
struct synth_field *field;
- struct synth_event *event = v;
unsigned int i;
seq_printf(m, "%s\t", event->name);
@@ -1194,11 +1238,30 @@ static int synth_events_seq_show(struct
return 0;
}
+static int synth_event_show(struct seq_file *m, struct dyn_event *ev)
+{
+ struct synth_event *event = to_synth_event(ev);
+
+ seq_printf(m, "s:%s/", event->class.system);
+
+ return __synth_event_show(m, event);
+}
+
+static int synth_events_seq_show(struct seq_file *m, void *v)
+{
+ struct dyn_event *ev = v;
+
+ if (!is_synth_event(ev))
+ return 0;
+
+ return __synth_event_show(m, to_synth_event(ev));
+}
+
static const struct seq_operations synth_events_seq_op = {
- .start = synth_events_seq_start,
- .next = synth_events_seq_next,
- .stop = synth_events_seq_stop,
- .show = synth_events_seq_show
+ .start = dyn_event_seq_start,
+ .next = dyn_event_seq_next,
+ .stop = dyn_event_seq_stop,
+ .show = synth_events_seq_show,
};
static int synth_events_open(struct inode *inode, struct file *file)
@@ -1206,7 +1269,7 @@ static int synth_events_open(struct inod
int ret;
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
- ret = release_all_synth_events();
+ ret = dyn_events_release_all(&synth_event_ops);
if (ret < 0)
return ret;
}
@@ -1219,7 +1282,7 @@ static ssize_t synth_events_write(struct
size_t count, loff_t *ppos)
{
return trace_parse_run_command(file, buffer, count, ppos,
- create_synth_event);
+ create_or_delete_synth_event);
}
static const struct file_operations synth_events_fops = {
@@ -5913,6 +5976,12 @@ static __init int trace_events_hist_init
struct dentry *d_tracer;
int err = 0;
+ err = dyn_event_register(&synth_event_ops);
+ if (err) {
+ pr_warn("Could not register synth_event_ops\n");
+ return err;
+ }
+
d_tracer = tracing_init_dentry();
if (IS_ERR(d_tracer)) {
err = PTR_ERR(d_tracer);
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 07/18] tracing: Remove unneeded synth_event_mutex
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (5 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 06/18] tracing: Use dyn_event framework for synthetic events Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 08/18] tracing: Consolidate trace_add/remove_event_call back to the nolock functions Greg Kroah-Hartman
` (15 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Tom Zanussi, Masami Hiramatsu, Steven Rostedt (VMware),
George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu <mhiramat@kernel.org>
commit 0e2b81f7b52a1c1a8c46986f9ca01eb7b3c421f8 upstream.
Rmove unneeded synth_event_mutex. This mutex protects the reference
count in synth_event, however, those operational points are already
protected by event_mutex.
1. In __create_synth_event() and create_or_delete_synth_event(),
those synth_event_mutex clearly obtained right after event_mutex.
2. event_hist_trigger_func() is trigger_hist_cmd.func() which is
called by trigger_process_regex(), which is a part of
event_trigger_regex_write() and this function takes event_mutex.
3. hist_unreg_all() is trigger_hist_cmd.unreg_all() which is called
by event_trigger_regex_open() and it takes event_mutex.
4. onmatch_destroy() and onmatch_create() have long call tree,
but both are finally invoked from event_trigger_regex_write()
and event_trace_del_tracer(), former takes event_mutex, and latter
ensures called under event_mutex locked.
Finally, I ensured there is no resource conflict. For safety,
I added lockdep_assert_held(&event_mutex) for each function.
Link: http://lkml.kernel.org/r/154140864134.17322.4796059721306031894.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>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace_events_hist.c | 30 +++++++-----------------------
1 file changed, 7 insertions(+), 23 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -443,8 +443,6 @@ static bool have_hist_err(void)
return false;
}
-static DEFINE_MUTEX(synth_event_mutex);
-
struct synth_trace_event {
struct trace_entry ent;
u64 fields[];
@@ -1097,7 +1095,6 @@ static int __create_synth_event(int argc
return -EINVAL;
mutex_lock(&event_mutex);
- mutex_lock(&synth_event_mutex);
event = find_synth_event(name);
if (event) {
@@ -1139,7 +1136,6 @@ static int __create_synth_event(int argc
else
free_synth_event(event);
out:
- mutex_unlock(&synth_event_mutex);
mutex_unlock(&event_mutex);
return ret;
@@ -1159,7 +1155,6 @@ static int create_or_delete_synth_event(
/* trace_run_command() ensures argc != 0 */
if (name[0] == '!') {
mutex_lock(&event_mutex);
- mutex_lock(&synth_event_mutex);
event = find_synth_event(name + 1);
if (event) {
if (event->ref)
@@ -1173,7 +1168,6 @@ static int create_or_delete_synth_event(
}
} else
ret = -ENOENT;
- mutex_unlock(&synth_event_mutex);
mutex_unlock(&event_mutex);
return ret;
}
@@ -3660,7 +3654,7 @@ static void onmatch_destroy(struct actio
{
unsigned int i;
- mutex_lock(&synth_event_mutex);
+ lockdep_assert_held(&event_mutex);
kfree(data->onmatch.match_event);
kfree(data->onmatch.match_event_system);
@@ -3673,8 +3667,6 @@ static void onmatch_destroy(struct actio
data->onmatch.synth_event->ref--;
kfree(data);
-
- mutex_unlock(&synth_event_mutex);
}
static void destroy_field_var(struct field_var *field_var)
@@ -3810,15 +3802,14 @@ static int onmatch_create(struct hist_tr
struct synth_event *event;
int ret = 0;
- mutex_lock(&synth_event_mutex);
+ lockdep_assert_held(&event_mutex);
+
event = find_synth_event(data->onmatch.synth_event_name);
if (!event) {
hist_err("onmatch: Couldn't find synthetic event: ", data->onmatch.synth_event_name);
- mutex_unlock(&synth_event_mutex);
return -EINVAL;
}
event->ref++;
- mutex_unlock(&synth_event_mutex);
var_ref_idx = hist_data->n_var_refs;
@@ -3892,9 +3883,7 @@ static int onmatch_create(struct hist_tr
out:
return ret;
err:
- mutex_lock(&synth_event_mutex);
event->ref--;
- mutex_unlock(&synth_event_mutex);
goto out;
}
@@ -5611,6 +5600,8 @@ static void hist_unreg_all(struct trace_
struct synth_event *se;
const char *se_name;
+ lockdep_assert_held(&event_mutex);
+
if (hist_file_check_refs(file))
return;
@@ -5620,12 +5611,10 @@ static void hist_unreg_all(struct trace_
list_del_rcu(&test->list);
trace_event_trigger_enable_disable(file, 0);
- mutex_lock(&synth_event_mutex);
se_name = trace_event_name(file->event_call);
se = find_synth_event(se_name);
if (se)
se->ref--;
- mutex_unlock(&synth_event_mutex);
update_cond_flag(file);
if (hist_data->enable_timestamps)
@@ -5651,6 +5640,8 @@ static int event_hist_trigger_func(struc
char *trigger, *p;
int ret = 0;
+ lockdep_assert_held(&event_mutex);
+
if (glob && strlen(glob)) {
last_cmd_set(param);
hist_err_clear();
@@ -5741,14 +5732,10 @@ static int event_hist_trigger_func(struc
}
cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
-
- mutex_lock(&synth_event_mutex);
se_name = trace_event_name(file->event_call);
se = find_synth_event(se_name);
if (se)
se->ref--;
- mutex_unlock(&synth_event_mutex);
-
ret = 0;
goto out_free;
}
@@ -5787,13 +5774,10 @@ enable:
if (ret)
goto out_unreg;
- mutex_lock(&synth_event_mutex);
se_name = trace_event_name(file->event_call);
se = find_synth_event(se_name);
if (se)
se->ref++;
- mutex_unlock(&synth_event_mutex);
-
/* Just return zero, not the number of registered triggers */
ret = 0;
out:
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 08/18] tracing: Consolidate trace_add/remove_event_call back to the nolock functions
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (6 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 07/18] tracing: Remove unneeded synth_event_mutex Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 09/18] string.h: Add str_has_prefix() helper function Greg Kroah-Hartman
` (14 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Masami Hiramatsu, Steven Rostedt (VMware), George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
commit 7e1413edd6194a9807aa5f3ac0378b9b4b9da879 upstream.
The trace_add/remove_event_call_nolock() functions were added to allow
the tace_add/remove_event_call() code be called when the event_mutex
lock was already taken. Now that all callers are done within the
event_mutex, there's no reason to have two different interfaces.
Remove the current wrapper trace_add/remove_event_call()s and rename the
_nolock versions back to the original names.
Link: http://lkml.kernel.org/r/154140866955.17322.2081425494660638846.stgit@devbox
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/trace_events.h | 2 --
kernel/trace/trace_events.c | 30 ++++--------------------------
kernel/trace/trace_events_hist.c | 6 +++---
3 files changed, 7 insertions(+), 31 deletions(-)
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -529,8 +529,6 @@ extern int trace_event_raw_init(struct t
extern int trace_define_field(struct trace_event_call *call, const char *type,
const char *name, int offset, int size,
int is_signed, int filter_type);
-extern int trace_add_event_call_nolock(struct trace_event_call *call);
-extern int trace_remove_event_call_nolock(struct trace_event_call *call);
extern int trace_add_event_call(struct trace_event_call *call);
extern int trace_remove_event_call(struct trace_event_call *call);
extern int trace_event_get_offsets(struct trace_event_call *call);
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2312,7 +2312,8 @@ __trace_early_add_new_event(struct trace
struct ftrace_module_file_ops;
static void __add_event_to_tracers(struct trace_event_call *call);
-int trace_add_event_call_nolock(struct trace_event_call *call)
+/* Add an additional event_call dynamically */
+int trace_add_event_call(struct trace_event_call *call)
{
int ret;
lockdep_assert_held(&event_mutex);
@@ -2327,17 +2328,6 @@ int trace_add_event_call_nolock(struct t
return ret;
}
-/* Add an additional event_call dynamically */
-int trace_add_event_call(struct trace_event_call *call)
-{
- int ret;
-
- mutex_lock(&event_mutex);
- ret = trace_add_event_call_nolock(call);
- mutex_unlock(&event_mutex);
- return ret;
-}
-
/*
* Must be called under locking of trace_types_lock, event_mutex and
* trace_event_sem.
@@ -2383,8 +2373,8 @@ static int probe_remove_event_call(struc
return 0;
}
-/* no event_mutex version */
-int trace_remove_event_call_nolock(struct trace_event_call *call)
+/* Remove an event_call */
+int trace_remove_event_call(struct trace_event_call *call)
{
int ret;
@@ -2398,18 +2388,6 @@ int trace_remove_event_call_nolock(struc
return ret;
}
-
-/* Remove an event_call */
-int trace_remove_event_call(struct trace_event_call *call)
-{
- int ret;
-
- mutex_lock(&event_mutex);
- ret = trace_remove_event_call_nolock(call);
- mutex_unlock(&event_mutex);
-
- return ret;
-}
#define for_each_event(event, start, end) \
for (event = start; \
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -980,7 +980,7 @@ static int register_synth_event(struct s
call->data = event;
call->tp = event->tp;
- ret = trace_add_event_call_nolock(call);
+ ret = trace_add_event_call(call);
if (ret) {
pr_warn("Failed to register synthetic event: %s\n",
trace_event_name(call));
@@ -989,7 +989,7 @@ static int register_synth_event(struct s
ret = set_synth_event_print_fmt(call);
if (ret < 0) {
- trace_remove_event_call_nolock(call);
+ trace_remove_event_call(call);
goto err;
}
out:
@@ -1004,7 +1004,7 @@ static int unregister_synth_event(struct
struct trace_event_call *call = &event->call;
int ret;
- ret = trace_remove_event_call_nolock(call);
+ ret = trace_remove_event_call(call);
return ret;
}
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 09/18] string.h: Add str_has_prefix() helper function
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (7 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 08/18] tracing: Consolidate trace_add/remove_event_call back to the nolock functions Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 10/18] tracing: Use str_has_prefix() helper for histogram code Greg Kroah-Hartman
` (13 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tom Zanussi, Namhyung Kim,
Steven Rostedt (VMware), George Guo, Linus Torvalds, Joe Perches,
Andreas Schwab
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
commit 72921427d46bf9731a1ab7864adc64c43dfae29f upstream.
A discussion came up in the trace triggers thread about converting a
bunch of:
strncmp(str, "const", sizeof("const") - 1)
use cases into a helper macro. It started with:
strncmp(str, const, sizeof(const) - 1)
But then Joe Perches mentioned that if a const is not used, the
sizeof() will be the size of a pointer, which can be bad. And that
gcc will optimize strlen("const") into "sizeof("const") - 1".
Thinking about this more, a quick grep in the kernel tree found several
(thousands!) of cases that use this construct. A quick grep also
revealed that there's probably several bugs in that use case. Some are
that people forgot the "- 1" (which I found) and others could be that
the constant for the sizeof is different than the constant (although, I
haven't found any of those, but I also didn't look hard).
I figured the best thing to do is to create a helper macro and place it
into include/linux/string.h. And go around and fix all the open coded
versions of it later.
Note, gcc appears to optimize this when we make it into an always_inline
static function, which removes a lot of issues that a macro produces.
Link: http://lkml.kernel.org/r/e3e754f2bd18e56eaa8baf79bee619316ebf4cfc.1545161087.git.tom.zanussi@linux.intel.com
Link: http://lkml.kernel.org/r/20181219211615.2298e781@gandalf.local.home
Link: http://lkml.kernel.org/r/CAHk-=wg_sR-UEC1ggmkZpypOUYanL5CMX4R7ceuaV4QMf5jBtg@mail.gmail.com
Cc: Tom Zanussi <zanussi@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Suggestions-by: Linus Torvalds <torvalds@linux-foundation.org>
Suggestions-by: Joe Perches <joe@perches.com>
Suggestions-by: Andreas Schwab <schwab@linux-m68k.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/string.h | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -492,4 +492,24 @@ static inline void memcpy_and_pad(void *
memcpy(dest, src, dest_len);
}
+/**
+ * str_has_prefix - Test if a string has a given prefix
+ * @str: The string to test
+ * @prefix: The string to see if @str starts with
+ *
+ * A common way to test a prefix of a string is to do:
+ * strncmp(str, prefix, sizeof(prefix) - 1)
+ *
+ * But this can lead to bugs due to typos, or if prefix is a pointer
+ * and not a constant. Instead use str_has_prefix().
+ *
+ * Returns: 0 if @str does not start with @prefix
+ strlen(@prefix) if @str does start with @prefix
+ */
+static __always_inline size_t str_has_prefix(const char *str, const char *prefix)
+{
+ size_t len = strlen(prefix);
+ return strncmp(str, prefix, len) == 0 ? len : 0;
+}
+
#endif /* _LINUX_STRING_H_ */
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 10/18] tracing: Use str_has_prefix() helper for histogram code
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (8 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 09/18] string.h: Add str_has_prefix() helper function Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 11/18] tracing: Use str_has_prefix() instead of using fixed sizes Greg Kroah-Hartman
` (12 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tom Zanussi, Namhyung Kim,
Steven Rostedt (VMware), George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
commit 754481e6954cbef53f8bc4412ad48dde611e21d3 upstream.
The tracing histogram code contains a lot of instances of the construct:
strncmp(str, "const", sizeof("const") - 1)
This can be prone to bugs due to typos or bad cut and paste. Use the
str_has_prefix() helper macro instead that removes the need for having two
copies of the constant string.
Cc: Tom Zanussi <tom.zanussi@linux.intel.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace_events_hist.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -1878,8 +1878,8 @@ static int parse_action(char *str, struc
if (attrs->n_actions >= HIST_ACTIONS_MAX)
return ret;
- if ((strncmp(str, "onmatch(", strlen("onmatch(")) == 0) ||
- (strncmp(str, "onmax(", strlen("onmax(")) == 0)) {
+ if ((str_has_prefix(str, "onmatch(")) ||
+ (str_has_prefix(str, "onmax("))) {
attrs->action_str[attrs->n_actions] = kstrdup(str, GFP_KERNEL);
if (!attrs->action_str[attrs->n_actions]) {
ret = -ENOMEM;
@@ -1896,34 +1896,34 @@ static int parse_assignment(char *str, s
{
int ret = 0;
- if ((strncmp(str, "key=", strlen("key=")) == 0) ||
- (strncmp(str, "keys=", strlen("keys=")) == 0)) {
+ if ((str_has_prefix(str, "key=")) ||
+ (str_has_prefix(str, "keys="))) {
attrs->keys_str = kstrdup(str, GFP_KERNEL);
if (!attrs->keys_str) {
ret = -ENOMEM;
goto out;
}
- } else if ((strncmp(str, "val=", strlen("val=")) == 0) ||
- (strncmp(str, "vals=", strlen("vals=")) == 0) ||
- (strncmp(str, "values=", strlen("values=")) == 0)) {
+ } else if ((str_has_prefix(str, "val=")) ||
+ (str_has_prefix(str, "vals=")) ||
+ (str_has_prefix(str, "values="))) {
attrs->vals_str = kstrdup(str, GFP_KERNEL);
if (!attrs->vals_str) {
ret = -ENOMEM;
goto out;
}
- } else if (strncmp(str, "sort=", strlen("sort=")) == 0) {
+ } else if (str_has_prefix(str, "sort=")) {
attrs->sort_key_str = kstrdup(str, GFP_KERNEL);
if (!attrs->sort_key_str) {
ret = -ENOMEM;
goto out;
}
- } else if (strncmp(str, "name=", strlen("name=")) == 0) {
+ } else if (str_has_prefix(str, "name=")) {
attrs->name = kstrdup(str, GFP_KERNEL);
if (!attrs->name) {
ret = -ENOMEM;
goto out;
}
- } else if (strncmp(str, "clock=", strlen("clock=")) == 0) {
+ } else if (str_has_prefix(str, "clock=")) {
strsep(&str, "=");
if (!str) {
ret = -EINVAL;
@@ -1936,7 +1936,7 @@ static int parse_assignment(char *str, s
ret = -ENOMEM;
goto out;
}
- } else if (strncmp(str, "size=", strlen("size=")) == 0) {
+ } else if (str_has_prefix(str, "size=")) {
int map_bits = parse_map_size(str);
if (map_bits < 0) {
@@ -3623,7 +3623,7 @@ static struct action_data *onmax_parse(c
if (!onmax_fn_name || !str)
goto free;
- if (strncmp(onmax_fn_name, "save", strlen("save")) == 0) {
+ if (str_has_prefix(onmax_fn_name, "save")) {
char *params = strsep(&str, ")");
if (!params) {
@@ -4414,8 +4414,8 @@ static int parse_actions(struct hist_tri
for (i = 0; i < hist_data->attrs->n_actions; i++) {
str = hist_data->attrs->action_str[i];
- if (strncmp(str, "onmatch(", strlen("onmatch(")) == 0) {
- char *action_str = str + strlen("onmatch(");
+ if (str_has_prefix(str, "onmatch(")) {
+ char *action_str = str + sizeof("onmatch(") - 1;
data = onmatch_parse(tr, action_str);
if (IS_ERR(data)) {
@@ -4423,8 +4423,8 @@ static int parse_actions(struct hist_tri
break;
}
data->fn = action_trace;
- } else if (strncmp(str, "onmax(", strlen("onmax(")) == 0) {
- char *action_str = str + strlen("onmax(");
+ } else if (str_has_prefix(str, "onmax(")) {
+ char *action_str = str + sizeof("onmax(") - 1;
data = onmax_parse(action_str);
if (IS_ERR(data)) {
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 11/18] tracing: Use str_has_prefix() instead of using fixed sizes
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (9 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 10/18] tracing: Use str_has_prefix() helper for histogram code Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 12/18] tracing: Have the historgram use the result of str_has_prefix() for len of prefix Greg Kroah-Hartman
` (11 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Namhyung Kim,
Steven Rostedt (VMware), George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
commit b6b2735514bcd70ad1556a33892a636b20ece671 upstream.
There are several instances of strncmp(str, "const", 123), where 123 is the
strlen of the const string to check if "const" is the prefix of str. But
this can be error prone. Use str_has_prefix() instead.
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace.c | 2 +-
kernel/trace/trace_events.c | 2 +-
kernel/trace/trace_events_hist.c | 2 +-
kernel/trace/trace_probe.c | 2 +-
kernel/trace/trace_stack.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4470,7 +4470,7 @@ static int trace_set_options(struct trac
cmp = strstrip(option);
- if (strncmp(cmp, "no", 2) == 0) {
+ if (str_has_prefix(cmp, "no")) {
neg = 1;
cmp += 2;
}
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1249,7 +1249,7 @@ static int f_show(struct seq_file *m, vo
*/
array_descriptor = strchr(field->type, '[');
- if (!strncmp(field->type, "__data_loc", 10))
+ if (str_has_prefix(field->type, "__data_loc"))
array_descriptor = NULL;
if (!array_descriptor)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -484,7 +484,7 @@ static int synth_event_define_fields(str
static bool synth_field_signed(char *type)
{
- if (strncmp(type, "u", 1) == 0)
+ if (str_has_prefix(type, "u"))
return false;
if (strcmp(type, "gfp_t") == 0)
return false;
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -342,7 +342,7 @@ static int parse_probe_vars(char *arg, c
f->fn = t->fetch[FETCH_MTD_retval];
else
ret = -EINVAL;
- } else if (strncmp(arg, "stack", 5) == 0) {
+ } else if (str_has_prefix(arg, "stack")) {
if (arg[5] == '\0') {
if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR))
return -EINVAL;
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -453,7 +453,7 @@ static char stack_trace_filter_buf[COMMA
static __init int enable_stacktrace(char *str)
{
- if (strncmp(str, "_filter=", 8) == 0)
+ if (str_has_prefix(str, "_filter="))
strncpy(stack_trace_filter_buf, str+8, COMMAND_LINE_SIZE);
stack_tracer_enabled = 1;
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 12/18] tracing: Have the historgram use the result of str_has_prefix() for len of prefix
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (10 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 11/18] tracing: Use str_has_prefix() instead of using fixed sizes Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 13/18] tracing: Refactor hist trigger action code Greg Kroah-Hartman
` (10 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tom Zanussi, Namhyung Kim,
Steven Rostedt (VMware), George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
commit 036876fa56204ae0fa59045bd6bbb2691a060633 upstream.
As str_has_prefix() returns the length on match, we can use that for the
updating of the string pointer instead of recalculating the prefix size.
Cc: Tom Zanussi <zanussi@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace_events_hist.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -4410,12 +4410,13 @@ static int parse_actions(struct hist_tri
unsigned int i;
int ret = 0;
char *str;
+ int len;
for (i = 0; i < hist_data->attrs->n_actions; i++) {
str = hist_data->attrs->action_str[i];
- if (str_has_prefix(str, "onmatch(")) {
- char *action_str = str + sizeof("onmatch(") - 1;
+ if ((len = str_has_prefix(str, "onmatch("))) {
+ char *action_str = str + len;
data = onmatch_parse(tr, action_str);
if (IS_ERR(data)) {
@@ -4423,8 +4424,8 @@ static int parse_actions(struct hist_tri
break;
}
data->fn = action_trace;
- } else if (str_has_prefix(str, "onmax(")) {
- char *action_str = str + sizeof("onmax(") - 1;
+ } else if ((len = str_has_prefix(str, "onmax("))) {
+ char *action_str = str + len;
data = onmax_parse(action_str);
if (IS_ERR(data)) {
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 13/18] tracing: Refactor hist trigger action code
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (11 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 12/18] tracing: Have the historgram use the result of str_has_prefix() for len of prefix Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 14/18] tracing: Split up onmatch action data Greg Kroah-Hartman
` (9 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Tom Zanussi, Steven Rostedt (VMware), George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tom Zanussi <tom.zanussi@linux.intel.com>
commit 7d18a10c316783357fb1b2b649cfcf97c70a7bee upstream.
The hist trigger action code currently implements two essentially
hard-coded pairs of 'actions' - onmax(), which tracks a variable and
saves some event fields when a max is hit, and onmatch(), which is
hard-coded to generate a synthetic event.
These hardcoded pairs (track max/save fields and detect match/generate
synthetic event) should really be decoupled into separate components
that can then be arbitrarily combined. The first component of each
pair (track max/detect match) is called a 'handler' in the new code,
while the second component (save fields/generate synthetic event) is
called an 'action' in this scheme.
This change refactors the action code to reflect this split by adding
two handlers, HANDLER_ONMATCH and HANDLER_ONMAX, along with two
actions, ACTION_SAVE and ACTION_TRACE.
The new code combines them to produce the existing ONMATCH/TRACE and
ONMAX/SAVE functionality, but doesn't implement the other combinations
now possible. Future patches will expand these to further useful
cases, such as ONMAX/TRACE, as well as add additional handlers and
actions such as ONCHANGE and SNAPSHOT.
Also, add abbreviated documentation for handlers and actions to
README.
Link: http://lkml.kernel.org/r/98bfdd48c1b4ff29fc5766442f99f5bc3c34b76b.1550100284.git.tom.zanussi@linux.intel.com
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace_events_hist.c | 407 ++++++++++++++++++++++-----------------
1 file changed, 238 insertions(+), 169 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -287,9 +287,9 @@ struct hist_trigger_data {
struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX];
unsigned int n_field_var_hists;
- struct field_var *max_vars[SYNTH_FIELDS_MAX];
- unsigned int n_max_vars;
- unsigned int n_max_var_str;
+ struct field_var *save_vars[SYNTH_FIELDS_MAX];
+ unsigned int n_save_vars;
+ unsigned int n_save_var_str;
};
static int synth_event_create(int argc, const char **argv);
@@ -357,11 +357,25 @@ struct action_data;
typedef void (*action_fn_t) (struct hist_trigger_data *hist_data,
struct tracing_map_elt *elt, void *rec,
- struct ring_buffer_event *rbe,
+ struct ring_buffer_event *rbe, void *key,
struct action_data *data, u64 *var_ref_vals);
+enum handler_id {
+ HANDLER_ONMATCH = 1,
+ HANDLER_ONMAX,
+};
+
+enum action_id {
+ ACTION_SAVE = 1,
+ ACTION_TRACE,
+};
+
struct action_data {
+ enum handler_id handler;
+ enum action_id action;
+ char *action_name;
action_fn_t fn;
+
unsigned int n_params;
char *params[SYNTH_FIELDS_MAX];
@@ -370,13 +384,11 @@ struct action_data {
unsigned int var_ref_idx;
char *match_event;
char *match_event_system;
- char *synth_event_name;
struct synth_event *synth_event;
} onmatch;
struct {
char *var_str;
- char *fn_name;
unsigned int max_var_ref_idx;
struct hist_field *max_var;
struct hist_field *var;
@@ -1065,7 +1077,7 @@ static struct synth_event *alloc_synth_e
static void action_trace(struct hist_trigger_data *hist_data,
struct tracing_map_elt *elt, void *rec,
- struct ring_buffer_event *rbe,
+ struct ring_buffer_event *rbe, void *key,
struct action_data *data, u64 *var_ref_vals)
{
struct synth_event *event = data->onmatch.synth_event;
@@ -1635,7 +1647,7 @@ find_match_var(struct hist_trigger_data
for (i = 0; i < hist_data->n_actions; i++) {
struct action_data *data = hist_data->actions[i];
- if (data->fn == action_trace) {
+ if (data->handler == HANDLER_ONMATCH) {
char *system = data->onmatch.match_event_system;
char *event_name = data->onmatch.match_event;
@@ -2073,7 +2085,7 @@ static int hist_trigger_elt_data_alloc(s
}
}
- n_str = hist_data->n_field_var_str + hist_data->n_max_var_str;
+ n_str = hist_data->n_field_var_str + hist_data->n_save_var_str;
size = STR_VAR_LEN_MAX;
@@ -3115,7 +3127,7 @@ create_field_var_hist(struct hist_trigge
int ret;
if (target_hist_data->n_field_var_hists >= SYNTH_FIELDS_MAX) {
- hist_err_event("onmatch: Too many field variables defined: ",
+ hist_err_event("trace action: Too many field variables defined: ",
subsys_name, event_name, field_name);
return ERR_PTR(-EINVAL);
}
@@ -3123,7 +3135,7 @@ create_field_var_hist(struct hist_trigge
file = event_file(tr, subsys_name, event_name);
if (IS_ERR(file)) {
- hist_err_event("onmatch: Event file not found: ",
+ hist_err_event("trace action: Event file not found: ",
subsys_name, event_name, field_name);
ret = PTR_ERR(file);
return ERR_PTR(ret);
@@ -3137,7 +3149,7 @@ create_field_var_hist(struct hist_trigge
*/
hist_data = find_compatible_hist(target_hist_data, file);
if (!hist_data) {
- hist_err_event("onmatch: Matching event histogram not found: ",
+ hist_err_event("trace action: Matching event histogram not found: ",
subsys_name, event_name, field_name);
return ERR_PTR(-EINVAL);
}
@@ -3199,7 +3211,7 @@ create_field_var_hist(struct hist_trigge
kfree(cmd);
kfree(var_hist->cmd);
kfree(var_hist);
- hist_err_event("onmatch: Couldn't create histogram for field: ",
+ hist_err_event("trace action: Couldn't create histogram for field: ",
subsys_name, event_name, field_name);
return ERR_PTR(ret);
}
@@ -3212,7 +3224,7 @@ create_field_var_hist(struct hist_trigge
if (IS_ERR_OR_NULL(event_var)) {
kfree(var_hist->cmd);
kfree(var_hist);
- hist_err_event("onmatch: Couldn't find synthetic variable: ",
+ hist_err_event("trace action: Couldn't find synthetic variable: ",
subsys_name, event_name, field_name);
return ERR_PTR(-EINVAL);
}
@@ -3295,8 +3307,8 @@ static void update_max_vars(struct hist_
struct ring_buffer_event *rbe,
void *rec)
{
- __update_field_vars(elt, rbe, rec, hist_data->max_vars,
- hist_data->n_max_vars, hist_data->n_field_var_str);
+ __update_field_vars(elt, rbe, rec, hist_data->save_vars,
+ hist_data->n_save_vars, hist_data->n_field_var_str);
}
static struct hist_field *create_var(struct hist_trigger_data *hist_data,
@@ -3440,9 +3452,9 @@ static void onmax_print(struct seq_file
seq_printf(m, "\n\tmax: %10llu", tracing_map_read_var(elt, max_idx));
- for (i = 0; i < hist_data->n_max_vars; i++) {
- struct hist_field *save_val = hist_data->max_vars[i]->val;
- struct hist_field *save_var = hist_data->max_vars[i]->var;
+ for (i = 0; i < hist_data->n_save_vars; i++) {
+ struct hist_field *save_val = hist_data->save_vars[i]->val;
+ struct hist_field *save_var = hist_data->save_vars[i]->var;
u64 val;
save_var_idx = save_var->var.idx;
@@ -3459,7 +3471,7 @@ static void onmax_print(struct seq_file
static void onmax_save(struct hist_trigger_data *hist_data,
struct tracing_map_elt *elt, void *rec,
- struct ring_buffer_event *rbe,
+ struct ring_buffer_event *rbe, void *key,
struct action_data *data, u64 *var_ref_vals)
{
unsigned int max_idx = data->onmax.max_var->var.idx;
@@ -3486,7 +3498,7 @@ static void onmax_destroy(struct action_
destroy_hist_field(data->onmax.var, 0);
kfree(data->onmax.var_str);
- kfree(data->onmax.fn_name);
+ kfree(data->action_name);
for (i = 0; i < data->n_params; i++)
kfree(data->params[i]);
@@ -3494,15 +3506,16 @@ static void onmax_destroy(struct action_
kfree(data);
}
+static int action_create(struct hist_trigger_data *hist_data,
+ struct action_data *data);
+
static int onmax_create(struct hist_trigger_data *hist_data,
struct action_data *data)
{
+ struct hist_field *var_field, *ref_field, *max_var = NULL;
struct trace_event_file *file = hist_data->event_file;
- struct hist_field *var_field, *ref_field, *max_var;
unsigned int var_ref_idx = hist_data->n_var_refs;
- struct field_var *field_var;
- char *onmax_var_str, *param;
- unsigned int i;
+ char *onmax_var_str;
int ret = 0;
onmax_var_str = data->onmax.var_str;
@@ -3524,8 +3537,8 @@ static int onmax_create(struct hist_trig
data->onmax.var = ref_field;
- data->fn = onmax_save;
data->onmax.max_var_ref_idx = var_ref_idx;
+
max_var = create_var(hist_data, file, "max", sizeof(u64), "u64");
if (IS_ERR(max_var)) {
hist_err("onmax: Couldn't create onmax variable: ", "max");
@@ -3534,27 +3547,7 @@ static int onmax_create(struct hist_trig
}
data->onmax.max_var = max_var;
- for (i = 0; i < data->n_params; i++) {
- param = kstrdup(data->params[i], GFP_KERNEL);
- if (!param) {
- ret = -ENOMEM;
- goto out;
- }
-
- field_var = create_target_field_var(hist_data, NULL, NULL, param);
- if (IS_ERR(field_var)) {
- hist_err("onmax: Couldn't create field variable: ", param);
- ret = PTR_ERR(field_var);
- kfree(param);
- goto out;
- }
-
- hist_data->max_vars[hist_data->n_max_vars++] = field_var;
- if (field_var->val->flags & HIST_FIELD_FL_STRING)
- hist_data->n_max_var_str++;
-
- kfree(param);
- }
+ ret = action_create(hist_data, data);
out:
return ret;
}
@@ -3565,11 +3558,14 @@ static int parse_action_params(char *par
int ret = 0;
while (params) {
- if (data->n_params >= SYNTH_FIELDS_MAX)
+ if (data->n_params >= SYNTH_FIELDS_MAX) {
+ hist_err("Too many action params", "");
goto out;
+ }
param = strsep(¶ms, ",");
if (!param) {
+ hist_err("No action param found", "");
ret = -EINVAL;
goto out;
}
@@ -3593,10 +3589,71 @@ static int parse_action_params(char *par
return ret;
}
-static struct action_data *onmax_parse(char *str)
+static int action_parse(char *str, struct action_data *data,
+ enum handler_id handler)
+{
+ char *action_name;
+ int ret = 0;
+
+ strsep(&str, ".");
+ if (!str) {
+ hist_err("action parsing: No action found", "");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ action_name = strsep(&str, "(");
+ if (!action_name || !str) {
+ hist_err("action parsing: No action found", "");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (str_has_prefix(action_name, "save")) {
+ char *params = strsep(&str, ")");
+
+ if (!params) {
+ hist_err("action parsing: No params found for %s", "save");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = parse_action_params(params, data);
+ if (ret)
+ goto out;
+
+ if (handler == HANDLER_ONMAX)
+ data->fn = onmax_save;
+
+ data->action = ACTION_SAVE;
+ } else {
+ char *params = strsep(&str, ")");
+
+ if (params) {
+ ret = parse_action_params(params, data);
+ if (ret)
+ goto out;
+ }
+
+ data->fn = action_trace;
+ data->action = ACTION_TRACE;
+ }
+
+ data->action_name = kstrdup(action_name, GFP_KERNEL);
+ if (!data->action_name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ data->handler = handler;
+ out:
+ return ret;
+}
+
+static struct action_data *onmax_parse(char *str, enum handler_id handler)
{
- char *onmax_fn_name, *onmax_var_str;
struct action_data *data;
+ char *onmax_var_str;
int ret = -EINVAL;
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -3615,33 +3672,9 @@ static struct action_data *onmax_parse(c
goto free;
}
- strsep(&str, ".");
- if (!str)
- goto free;
-
- onmax_fn_name = strsep(&str, "(");
- if (!onmax_fn_name || !str)
- goto free;
-
- if (str_has_prefix(onmax_fn_name, "save")) {
- char *params = strsep(&str, ")");
-
- if (!params) {
- ret = -EINVAL;
- goto free;
- }
-
- ret = parse_action_params(params, data);
- if (ret)
- goto free;
- } else
- goto free;
-
- data->onmax.fn_name = kstrdup(onmax_fn_name, GFP_KERNEL);
- if (!data->onmax.fn_name) {
- ret = -ENOMEM;
+ ret = action_parse(str, data, handler);
+ if (ret)
goto free;
- }
out:
return data;
free:
@@ -3658,7 +3691,7 @@ static void onmatch_destroy(struct actio
kfree(data->onmatch.match_event);
kfree(data->onmatch.match_event_system);
- kfree(data->onmatch.synth_event_name);
+ kfree(data->action_name);
for (i = 0; i < data->n_params; i++)
kfree(data->params[i]);
@@ -3716,8 +3749,9 @@ static int check_synth_field(struct synt
}
static struct hist_field *
-onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data,
- char *system, char *event, char *var)
+trace_action_find_var(struct hist_trigger_data *hist_data,
+ struct action_data *data,
+ char *system, char *event, char *var)
{
struct hist_field *hist_field;
@@ -3725,7 +3759,7 @@ onmatch_find_var(struct hist_trigger_dat
hist_field = find_target_event_var(hist_data, system, event, var);
if (!hist_field) {
- if (!system) {
+ if (!system && data->handler == HANDLER_ONMATCH) {
system = data->onmatch.match_event_system;
event = data->onmatch.match_event;
}
@@ -3734,15 +3768,15 @@ onmatch_find_var(struct hist_trigger_dat
}
if (!hist_field)
- hist_err_event("onmatch: Couldn't find onmatch param: $", system, event, var);
+ hist_err_event("trace action: Couldn't find param: $", system, event, var);
return hist_field;
}
static struct hist_field *
-onmatch_create_field_var(struct hist_trigger_data *hist_data,
- struct action_data *data, char *system,
- char *event, char *var)
+trace_action_create_field_var(struct hist_trigger_data *hist_data,
+ struct action_data *data, char *system,
+ char *event, char *var)
{
struct hist_field *hist_field = NULL;
struct field_var *field_var;
@@ -3765,7 +3799,7 @@ onmatch_create_field_var(struct hist_tri
* looking for fields on the onmatch(system.event.xxx)
* event.
*/
- if (!system) {
+ if (!system && data->handler == HANDLER_ONMATCH) {
system = data->onmatch.match_event_system;
event = data->onmatch.match_event;
}
@@ -3791,9 +3825,8 @@ onmatch_create_field_var(struct hist_tri
goto out;
}
-static int onmatch_create(struct hist_trigger_data *hist_data,
- struct trace_event_file *file,
- struct action_data *data)
+static int trace_action_create(struct hist_trigger_data *hist_data,
+ struct action_data *data)
{
char *event_name, *param, *system = NULL;
struct hist_field *hist_field, *var_ref;
@@ -3804,11 +3837,12 @@ static int onmatch_create(struct hist_tr
lockdep_assert_held(&event_mutex);
- event = find_synth_event(data->onmatch.synth_event_name);
+ event = find_synth_event(data->action_name);
if (!event) {
- hist_err("onmatch: Couldn't find synthetic event: ", data->onmatch.synth_event_name);
+ hist_err("trace action: Couldn't find synthetic event: ", data->action_name);
return -EINVAL;
}
+
event->ref++;
var_ref_idx = hist_data->n_var_refs;
@@ -3836,13 +3870,15 @@ static int onmatch_create(struct hist_tr
}
if (param[0] == '$')
- hist_field = onmatch_find_var(hist_data, data, system,
- event_name, param);
+ hist_field = trace_action_find_var(hist_data, data,
+ system, event_name,
+ param);
else
- hist_field = onmatch_create_field_var(hist_data, data,
- system,
- event_name,
- param);
+ hist_field = trace_action_create_field_var(hist_data,
+ data,
+ system,
+ event_name,
+ param);
if (!hist_field) {
kfree(p);
@@ -3864,7 +3900,7 @@ static int onmatch_create(struct hist_tr
continue;
}
- hist_err_event("onmatch: Param type doesn't match synthetic event field type: ",
+ hist_err_event("trace action: Param type doesn't match synthetic event field type: ",
system, event_name, param);
kfree(p);
ret = -EINVAL;
@@ -3872,12 +3908,11 @@ static int onmatch_create(struct hist_tr
}
if (field_pos != event->n_fields) {
- hist_err("onmatch: Param count doesn't match synthetic event field count: ", event->name);
+ hist_err("trace action: Param count doesn't match synthetic event field count: ", event->name);
ret = -EINVAL;
goto err;
}
- data->fn = action_trace;
data->onmatch.synth_event = event;
data->onmatch.var_ref_idx = var_ref_idx;
out:
@@ -3888,10 +3923,58 @@ static int onmatch_create(struct hist_tr
goto out;
}
+static int action_create(struct hist_trigger_data *hist_data,
+ struct action_data *data)
+{
+ struct field_var *field_var;
+ unsigned int i;
+ char *param;
+ int ret = 0;
+
+ if (data->action == ACTION_TRACE)
+ return trace_action_create(hist_data, data);
+
+ if (data->action == ACTION_SAVE) {
+ if (hist_data->n_save_vars) {
+ ret = -EEXIST;
+ hist_err("save action: Can't have more than one save() action per hist", "");
+ goto out;
+ }
+
+ for (i = 0; i < data->n_params; i++) {
+ param = kstrdup(data->params[i], GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ field_var = create_target_field_var(hist_data, NULL, NULL, param);
+ if (IS_ERR(field_var)) {
+ hist_err("save action: Couldn't create field variable: ", param);
+ ret = PTR_ERR(field_var);
+ kfree(param);
+ goto out;
+ }
+
+ hist_data->save_vars[hist_data->n_save_vars++] = field_var;
+ if (field_var->val->flags & HIST_FIELD_FL_STRING)
+ hist_data->n_save_var_str++;
+ kfree(param);
+ }
+ }
+ out:
+ return ret;
+}
+
+static int onmatch_create(struct hist_trigger_data *hist_data,
+ struct action_data *data)
+{
+ return action_create(hist_data, data);
+}
+
static struct action_data *onmatch_parse(struct trace_array *tr, char *str)
{
char *match_event, *match_event_system;
- char *synth_event_name, *params;
struct action_data *data;
int ret = -EINVAL;
@@ -3929,31 +4012,7 @@ static struct action_data *onmatch_parse
goto free;
}
- strsep(&str, ".");
- if (!str) {
- hist_err("onmatch: Missing . after onmatch(): ", str);
- goto free;
- }
-
- synth_event_name = strsep(&str, "(");
- if (!synth_event_name || !str) {
- hist_err("onmatch: Missing opening paramlist paren: ", synth_event_name);
- goto free;
- }
-
- data->onmatch.synth_event_name = kstrdup(synth_event_name, GFP_KERNEL);
- if (!data->onmatch.synth_event_name) {
- ret = -ENOMEM;
- goto free;
- }
-
- params = strsep(&str, ")");
- if (!params || !str || (str && strlen(str))) {
- hist_err("onmatch: Missing closing paramlist paren: ", params);
- goto free;
- }
-
- ret = parse_action_params(params, data);
+ ret = action_parse(str, data, HANDLER_ONMATCH);
if (ret)
goto free;
out:
@@ -4394,9 +4453,9 @@ static void destroy_actions(struct hist_
for (i = 0; i < hist_data->n_actions; i++) {
struct action_data *data = hist_data->actions[i];
- if (data->fn == action_trace)
+ if (data->handler == HANDLER_ONMATCH)
onmatch_destroy(data);
- else if (data->fn == onmax_save)
+ else if (data->handler == HANDLER_ONMAX)
onmax_destroy(data);
else
kfree(data);
@@ -4423,16 +4482,14 @@ static int parse_actions(struct hist_tri
ret = PTR_ERR(data);
break;
}
- data->fn = action_trace;
} else if ((len = str_has_prefix(str, "onmax("))) {
char *action_str = str + len;
- data = onmax_parse(action_str);
+ data = onmax_parse(action_str, HANDLER_ONMAX);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
}
- data->fn = onmax_save;
} else {
ret = -EINVAL;
break;
@@ -4444,8 +4501,7 @@ static int parse_actions(struct hist_tri
return ret;
}
-static int create_actions(struct hist_trigger_data *hist_data,
- struct trace_event_file *file)
+static int create_actions(struct hist_trigger_data *hist_data)
{
struct action_data *data;
unsigned int i;
@@ -4454,14 +4510,17 @@ static int create_actions(struct hist_tr
for (i = 0; i < hist_data->attrs->n_actions; i++) {
data = hist_data->actions[i];
- if (data->fn == action_trace) {
- ret = onmatch_create(hist_data, file, data);
+ if (data->handler == HANDLER_ONMATCH) {
+ ret = onmatch_create(hist_data, data);
if (ret)
- return ret;
- } else if (data->fn == onmax_save) {
+ break;
+ } else if (data->handler == HANDLER_ONMAX) {
ret = onmax_create(hist_data, data);
if (ret)
- return ret;
+ break;
+ } else {
+ ret = -EINVAL;
+ break;
}
}
@@ -4477,26 +4536,42 @@ static void print_actions(struct seq_fil
for (i = 0; i < hist_data->n_actions; i++) {
struct action_data *data = hist_data->actions[i];
- if (data->fn == onmax_save)
+ if (data->handler == HANDLER_ONMAX)
onmax_print(m, hist_data, elt, data);
}
}
+static void print_action_spec(struct seq_file *m,
+ struct hist_trigger_data *hist_data,
+ struct action_data *data)
+{
+ unsigned int i;
+
+ if (data->action == ACTION_SAVE) {
+ for (i = 0; i < hist_data->n_save_vars; i++) {
+ seq_printf(m, "%s", hist_data->save_vars[i]->var->var.name);
+ if (i < hist_data->n_save_vars - 1)
+ seq_puts(m, ",");
+ }
+ } else if (data->action == ACTION_TRACE) {
+ for (i = 0; i < data->n_params; i++) {
+ if (i)
+ seq_puts(m, ",");
+ seq_printf(m, "%s", data->params[i]);
+ }
+ }
+}
+
static void print_onmax_spec(struct seq_file *m,
struct hist_trigger_data *hist_data,
struct action_data *data)
{
- unsigned int i;
-
seq_puts(m, ":onmax(");
seq_printf(m, "%s", data->onmax.var_str);
- seq_printf(m, ").%s(", data->onmax.fn_name);
+ seq_printf(m, ").%s(", data->action_name);
+
+ print_action_spec(m, hist_data, data);
- for (i = 0; i < hist_data->n_max_vars; i++) {
- seq_printf(m, "%s", hist_data->max_vars[i]->var->var.name);
- if (i < hist_data->n_max_vars - 1)
- seq_puts(m, ",");
- }
seq_puts(m, ")");
}
@@ -4504,18 +4579,12 @@ static void print_onmatch_spec(struct se
struct hist_trigger_data *hist_data,
struct action_data *data)
{
- unsigned int i;
-
seq_printf(m, ":onmatch(%s.%s).", data->onmatch.match_event_system,
data->onmatch.match_event);
- seq_printf(m, "%s(", data->onmatch.synth_event->name);
+ seq_printf(m, "%s(", data->action_name);
- for (i = 0; i < data->n_params; i++) {
- if (i)
- seq_puts(m, ",");
- seq_printf(m, "%s", data->params[i]);
- }
+ print_action_spec(m, hist_data, data);
seq_puts(m, ")");
}
@@ -4532,7 +4601,9 @@ static bool actions_match(struct hist_tr
struct action_data *data = hist_data->actions[i];
struct action_data *data_test = hist_data_test->actions[i];
- if (data->fn != data_test->fn)
+ if (data->handler != data_test->handler)
+ return false;
+ if (data->action != data_test->action)
return false;
if (data->n_params != data_test->n_params)
@@ -4543,23 +4614,20 @@ static bool actions_match(struct hist_tr
return false;
}
- if (data->fn == action_trace) {
- if (strcmp(data->onmatch.synth_event_name,
- data_test->onmatch.synth_event_name) != 0)
- return false;
+ if (strcmp(data->action_name, data_test->action_name) != 0)
+ return false;
+
+ if (data->handler == HANDLER_ONMATCH) {
if (strcmp(data->onmatch.match_event_system,
data_test->onmatch.match_event_system) != 0)
return false;
if (strcmp(data->onmatch.match_event,
data_test->onmatch.match_event) != 0)
return false;
- } else if (data->fn == onmax_save) {
+ } else if (data->handler == HANDLER_ONMAX) {
if (strcmp(data->onmax.var_str,
data_test->onmax.var_str) != 0)
return false;
- if (strcmp(data->onmax.fn_name,
- data_test->onmax.fn_name) != 0)
- return false;
}
}
@@ -4575,9 +4643,9 @@ static void print_actions_spec(struct se
for (i = 0; i < hist_data->n_actions; i++) {
struct action_data *data = hist_data->actions[i];
- if (data->fn == action_trace)
+ if (data->handler == HANDLER_ONMATCH)
print_onmatch_spec(m, hist_data, data);
- else if (data->fn == onmax_save)
+ else if (data->handler == HANDLER_ONMAX)
print_onmax_spec(m, hist_data, data);
}
}
@@ -4770,14 +4838,15 @@ static inline void add_to_key(char *comp
static void
hist_trigger_actions(struct hist_trigger_data *hist_data,
struct tracing_map_elt *elt, void *rec,
- struct ring_buffer_event *rbe, u64 *var_ref_vals)
+ struct ring_buffer_event *rbe, void *key,
+ u64 *var_ref_vals)
{
struct action_data *data;
unsigned int i;
for (i = 0; i < hist_data->n_actions; i++) {
data = hist_data->actions[i];
- data->fn(hist_data, elt, rec, rbe, data, var_ref_vals);
+ data->fn(hist_data, elt, rec, rbe, key, data, var_ref_vals);
}
}
@@ -4838,7 +4907,7 @@ static void event_hist_trigger(struct ev
hist_trigger_elt_update(hist_data, elt, rec, rbe, var_ref_vals);
if (resolve_var_refs(hist_data, key, var_ref_vals, true))
- hist_trigger_actions(hist_data, elt, rec, rbe, var_ref_vals);
+ hist_trigger_actions(hist_data, elt, rec, rbe, key, var_ref_vals);
}
static void hist_trigger_stacktrace_print(struct seq_file *m,
@@ -5757,7 +5826,7 @@ static int event_hist_trigger_func(struc
if (get_named_trigger_data(trigger_data))
goto enable;
- ret = create_actions(hist_data, file);
+ ret = create_actions(hist_data);
if (ret)
goto out_unreg;
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 14/18] tracing: Split up onmatch action data
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (12 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 13/18] tracing: Refactor hist trigger action code Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 15/18] tracing: Generalize hist trigger onmax and save action Greg Kroah-Hartman
` (8 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Tom Zanussi, Steven Rostedt (VMware), George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tom Zanussi <tom.zanussi@linux.intel.com>
commit c3e49506a0f426a850675e39419879214060ca8b upstream.
Currently, the onmatch action data binds the onmatch action to data
related to synthetic event generation. Since we want to allow the
onmatch handler to potentially invoke a different action, and because
we expect other handlers to generate synthetic events, we need to
separate the data related to these two functions.
Also rename the onmatch data to something more descriptive, and create
and use common action data destroy function.
Link: http://lkml.kernel.org/r/b9abbf9aae69fe3920cdc8ddbcaad544dd258d78.1550100284.git.tom.zanussi@linux.intel.com
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace.c | 12 ++++
kernel/trace/trace_events_hist.c | 95 +++++++++++++++++++++------------------
2 files changed, 63 insertions(+), 44 deletions(-)
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4754,6 +4754,7 @@ static const char readme_msg[] =
"\t [:size=#entries]\n"
"\t [:pause][:continue][:clear]\n"
"\t [:name=histname1]\n"
+ "\t [:<handler>.<action>]\n"
"\t [if <filter>]\n\n"
"\t Note, special fields can be used as well:\n"
"\t common_timestamp - to record current timestamp\n"
@@ -4799,7 +4800,16 @@ static const char readme_msg[] =
"\t The enable_hist and disable_hist triggers can be used to\n"
"\t have one event conditionally start and stop another event's\n"
"\t already-attached hist trigger. The syntax is analagous to\n"
- "\t the enable_event and disable_event triggers.\n"
+ "\t the enable_event and disable_event triggers.\n\n"
+ "\t Hist trigger handlers and actions are executed whenever a\n"
+ "\t a histogram entry is added or updated. They take the form:\n\n"
+ "\t <handler>.<action>\n\n"
+ "\t The available handlers are:\n\n"
+ "\t onmatch(matching.event) - invoke on addition or update\n"
+ "\t onmax(var) - invoke if var exceeds current max\n\n"
+ "\t The available actions are:\n\n"
+ "\t <synthetic_event>(param list) - generate synthetic event\n"
+ "\t save(field,...) - save current event fields\n"
#endif
;
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -379,13 +379,22 @@ struct action_data {
unsigned int n_params;
char *params[SYNTH_FIELDS_MAX];
+ /*
+ * When a histogram trigger is hit, the values of any
+ * references to variables, including variables being passed
+ * as parameters to synthetic events, are collected into a
+ * var_ref_vals array. This var_ref_idx is the index of the
+ * first param in the array to be passed to the synthetic
+ * event invocation.
+ */
+ unsigned int var_ref_idx;
+ struct synth_event *synth_event;
+
union {
struct {
- unsigned int var_ref_idx;
- char *match_event;
- char *match_event_system;
- struct synth_event *synth_event;
- } onmatch;
+ char *event;
+ char *event_system;
+ } match_data;
struct {
char *var_str;
@@ -1080,9 +1089,9 @@ static void action_trace(struct hist_tri
struct ring_buffer_event *rbe, void *key,
struct action_data *data, u64 *var_ref_vals)
{
- struct synth_event *event = data->onmatch.synth_event;
+ struct synth_event *event = data->synth_event;
- trace_synth(event, var_ref_vals, data->onmatch.var_ref_idx);
+ trace_synth(event, var_ref_vals, data->var_ref_idx);
}
struct hist_var_data {
@@ -1648,8 +1657,8 @@ find_match_var(struct hist_trigger_data
struct action_data *data = hist_data->actions[i];
if (data->handler == HANDLER_ONMATCH) {
- char *system = data->onmatch.match_event_system;
- char *event_name = data->onmatch.match_event;
+ char *system = data->match_data.event_system;
+ char *event_name = data->match_data.event;
file = find_var_file(tr, system, event_name, var_name);
if (!file)
@@ -3490,22 +3499,33 @@ static void onmax_save(struct hist_trigg
update_max_vars(hist_data, elt, rbe, rec);
}
-static void onmax_destroy(struct action_data *data)
+static void action_data_destroy(struct action_data *data)
{
unsigned int i;
- destroy_hist_field(data->onmax.max_var, 0);
- destroy_hist_field(data->onmax.var, 0);
+ lockdep_assert_held(&event_mutex);
- kfree(data->onmax.var_str);
kfree(data->action_name);
for (i = 0; i < data->n_params; i++)
kfree(data->params[i]);
+ if (data->synth_event)
+ data->synth_event->ref--;
+
kfree(data);
}
+static void onmax_destroy(struct action_data *data)
+{
+ destroy_hist_field(data->onmax.max_var, 0);
+ destroy_hist_field(data->onmax.var, 0);
+
+ kfree(data->onmax.var_str);
+
+ action_data_destroy(data);
+}
+
static int action_create(struct hist_trigger_data *hist_data,
struct action_data *data);
@@ -3685,21 +3705,10 @@ static struct action_data *onmax_parse(c
static void onmatch_destroy(struct action_data *data)
{
- unsigned int i;
-
- lockdep_assert_held(&event_mutex);
+ kfree(data->match_data.event);
+ kfree(data->match_data.event_system);
- kfree(data->onmatch.match_event);
- kfree(data->onmatch.match_event_system);
- kfree(data->action_name);
-
- for (i = 0; i < data->n_params; i++)
- kfree(data->params[i]);
-
- if (data->onmatch.synth_event)
- data->onmatch.synth_event->ref--;
-
- kfree(data);
+ action_data_destroy(data);
}
static void destroy_field_var(struct field_var *field_var)
@@ -3760,8 +3769,8 @@ trace_action_find_var(struct hist_trigge
hist_field = find_target_event_var(hist_data, system, event, var);
if (!hist_field) {
if (!system && data->handler == HANDLER_ONMATCH) {
- system = data->onmatch.match_event_system;
- event = data->onmatch.match_event;
+ system = data->match_data.event_system;
+ event = data->match_data.event;
}
hist_field = find_event_var(hist_data, system, event, var);
@@ -3800,8 +3809,8 @@ trace_action_create_field_var(struct his
* event.
*/
if (!system && data->handler == HANDLER_ONMATCH) {
- system = data->onmatch.match_event_system;
- event = data->onmatch.match_event;
+ system = data->match_data.event_system;
+ event = data->match_data.event;
}
if (!event)
@@ -3913,8 +3922,8 @@ static int trace_action_create(struct hi
goto err;
}
- data->onmatch.synth_event = event;
- data->onmatch.var_ref_idx = var_ref_idx;
+ data->synth_event = event;
+ data->var_ref_idx = var_ref_idx;
out:
return ret;
err:
@@ -4000,14 +4009,14 @@ static struct action_data *onmatch_parse
goto free;
}
- data->onmatch.match_event = kstrdup(match_event, GFP_KERNEL);
- if (!data->onmatch.match_event) {
+ data->match_data.event = kstrdup(match_event, GFP_KERNEL);
+ if (!data->match_data.event) {
ret = -ENOMEM;
goto free;
}
- data->onmatch.match_event_system = kstrdup(match_event_system, GFP_KERNEL);
- if (!data->onmatch.match_event_system) {
+ data->match_data.event_system = kstrdup(match_event_system, GFP_KERNEL);
+ if (!data->match_data.event_system) {
ret = -ENOMEM;
goto free;
}
@@ -4579,8 +4588,8 @@ static void print_onmatch_spec(struct se
struct hist_trigger_data *hist_data,
struct action_data *data)
{
- seq_printf(m, ":onmatch(%s.%s).", data->onmatch.match_event_system,
- data->onmatch.match_event);
+ seq_printf(m, ":onmatch(%s.%s).", data->match_data.event_system,
+ data->match_data.event);
seq_printf(m, "%s(", data->action_name);
@@ -4618,11 +4627,11 @@ static bool actions_match(struct hist_tr
return false;
if (data->handler == HANDLER_ONMATCH) {
- if (strcmp(data->onmatch.match_event_system,
- data_test->onmatch.match_event_system) != 0)
+ if (strcmp(data->match_data.event_system,
+ data_test->match_data.event_system) != 0)
return false;
- if (strcmp(data->onmatch.match_event,
- data_test->onmatch.match_event) != 0)
+ if (strcmp(data->match_data.event,
+ data_test->match_data.event) != 0)
return false;
} else if (data->handler == HANDLER_ONMAX) {
if (strcmp(data->onmax.var_str,
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 15/18] tracing: Generalize hist trigger onmax and save action
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (13 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 14/18] tracing: Split up onmatch action data Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 16/18] tracing: Remove unnecessary var_ref destroy in track_data_destroy() Greg Kroah-Hartman
` (7 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Tom Zanussi, Steven Rostedt (VMware), George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tom Zanussi <tom.zanussi@linux.intel.com>
commit 466f4528fbc692ea56deca278fa6aeb79e6e8b21 upstream.
The action refactor code allowed actions and handlers to be separated,
but the existing onmax handler and save action code is still not
flexible enough to handle arbitrary coupling. This change generalizes
them and in the process makes additional handlers and actions easier
to implement.
The onmax action can be broken up and thought of as two separate
components - a variable to be tracked (the parameter given to the
onmax($var_to_track) function) and an invisible variable created to
save the ongoing result of doing something with that variable, such as
saving the max value of that variable so far seen.
Separating it out like this and renaming it appropriately allows us to
use the same code for similar tracking functions such as
onchange($var_to_track), which would just track the last value seen
rather than the max seen so far, which is useful in some situations.
Additionally, because different handlers and actions may want to save
and access data differently e.g. save and retrieve tracking values as
local variables vs something more global, save_val() and get_val()
interface functions are introduced and max-specific implementations
are used instead.
The same goes for the code that checks whether a maximum has been hit
- a generic check_val() interface and max-checking implementation is
used instead, which allows future patches to make use of he same code
using their own implemetations of similar functionality.
Link: http://lkml.kernel.org/r/980ea73dd8e3f36db3d646f99652f8fed42b77d4.1550100284.git.tom.zanussi@linux.intel.com
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace_events_hist.c | 242 ++++++++++++++++++++++++++-------------
1 file changed, 163 insertions(+), 79 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -360,6 +360,8 @@ typedef void (*action_fn_t) (struct hist
struct ring_buffer_event *rbe, void *key,
struct action_data *data, u64 *var_ref_vals);
+typedef bool (*check_track_val_fn_t) (u64 track_val, u64 var_val);
+
enum handler_id {
HANDLER_ONMATCH = 1,
HANDLER_ONMAX,
@@ -397,15 +399,35 @@ struct action_data {
} match_data;
struct {
+ /*
+ * var_str contains the $-unstripped variable
+ * name referenced by var_ref, and used when
+ * printing the action. Because var_ref
+ * creation is deferred to create_actions(),
+ * we need a per-action way to save it until
+ * then, thus var_str.
+ */
char *var_str;
- unsigned int max_var_ref_idx;
- struct hist_field *max_var;
- struct hist_field *var;
- } onmax;
+
+ /*
+ * var_ref refers to the variable being
+ * tracked e.g onmax($var).
+ */
+ struct hist_field *var_ref;
+
+ /*
+ * track_var contains the 'invisible' tracking
+ * variable created to keep the current
+ * e.g. max value.
+ */
+ struct hist_field *track_var;
+
+ check_track_val_fn_t check_val;
+ action_fn_t save_data;
+ } track_data;
};
};
-
static char last_hist_cmd[MAX_FILTER_STR_VAL];
static char hist_err_str[MAX_FILTER_STR_VAL];
@@ -3311,10 +3333,10 @@ static void update_field_vars(struct his
hist_data->n_field_vars, 0);
}
-static void update_max_vars(struct hist_trigger_data *hist_data,
- struct tracing_map_elt *elt,
- struct ring_buffer_event *rbe,
- void *rec)
+static void save_track_data_vars(struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt, void *rec,
+ struct ring_buffer_event *rbe, void *key,
+ struct action_data *data, u64 *var_ref_vals)
{
__update_field_vars(elt, rbe, rec, hist_data->save_vars,
hist_data->n_save_vars, hist_data->n_field_var_str);
@@ -3452,14 +3474,67 @@ create_target_field_var(struct hist_trig
return create_field_var(target_hist_data, file, var_name);
}
-static void onmax_print(struct seq_file *m,
- struct hist_trigger_data *hist_data,
- struct tracing_map_elt *elt,
- struct action_data *data)
+static bool check_track_val_max(u64 track_val, u64 var_val)
+{
+ if (var_val <= track_val)
+ return false;
+
+ return true;
+}
+
+static u64 get_track_val(struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt,
+ struct action_data *data)
+{
+ unsigned int track_var_idx = data->track_data.track_var->var.idx;
+ u64 track_val;
+
+ track_val = tracing_map_read_var(elt, track_var_idx);
+
+ return track_val;
+}
+
+static void save_track_val(struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt,
+ struct action_data *data, u64 var_val)
+{
+ unsigned int track_var_idx = data->track_data.track_var->var.idx;
+
+ tracing_map_set_var(elt, track_var_idx, var_val);
+}
+
+static void save_track_data(struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt, void *rec,
+ struct ring_buffer_event *rbe, void *key,
+ struct action_data *data, u64 *var_ref_vals)
+{
+ if (data->track_data.save_data)
+ data->track_data.save_data(hist_data, elt, rec, rbe, key, data, var_ref_vals);
+}
+
+static bool check_track_val(struct tracing_map_elt *elt,
+ struct action_data *data,
+ u64 var_val)
{
- unsigned int i, save_var_idx, max_idx = data->onmax.max_var->var.idx;
+ struct hist_trigger_data *hist_data;
+ u64 track_val;
+
+ hist_data = data->track_data.track_var->hist_data;
+ track_val = get_track_val(hist_data, elt, data);
+
+ return data->track_data.check_val(track_val, var_val);
+}
+
+static void track_data_print(struct seq_file *m,
+ struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt,
+ struct action_data *data)
+{
+ u64 track_val = get_track_val(hist_data, elt, data);
+ unsigned int i, save_var_idx;
- seq_printf(m, "\n\tmax: %10llu", tracing_map_read_var(elt, max_idx));
+ if (data->handler == HANDLER_ONMAX)
+ seq_printf(m, "\n\tmax: %10llu", track_val);
for (i = 0; i < hist_data->n_save_vars; i++) {
struct hist_field *save_val = hist_data->save_vars[i]->val;
@@ -3478,25 +3553,17 @@ static void onmax_print(struct seq_file
}
}
-static void onmax_save(struct hist_trigger_data *hist_data,
- struct tracing_map_elt *elt, void *rec,
- struct ring_buffer_event *rbe, void *key,
- struct action_data *data, u64 *var_ref_vals)
-{
- unsigned int max_idx = data->onmax.max_var->var.idx;
- unsigned int max_var_ref_idx = data->onmax.max_var_ref_idx;
-
- u64 var_val, max_val;
-
- var_val = var_ref_vals[max_var_ref_idx];
- max_val = tracing_map_read_var(elt, max_idx);
-
- if (var_val <= max_val)
- return;
-
- tracing_map_set_var(elt, max_idx, var_val);
-
- update_max_vars(hist_data, elt, rbe, rec);
+static void ontrack_action(struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt, void *rec,
+ struct ring_buffer_event *rbe, void *key,
+ struct action_data *data, u64 *var_ref_vals)
+{
+ u64 var_val = var_ref_vals[data->track_data.var_ref->var_ref_idx];
+
+ if (check_track_val(elt, data, var_val)) {
+ save_track_val(hist_data, elt, data, var_val);
+ save_track_data(hist_data, elt, rec, rbe, key, data, var_ref_vals);
+ }
}
static void action_data_destroy(struct action_data *data)
@@ -3516,12 +3583,13 @@ static void action_data_destroy(struct a
kfree(data);
}
-static void onmax_destroy(struct action_data *data)
+static void track_data_destroy(struct hist_trigger_data *hist_data,
+ struct action_data *data)
{
- destroy_hist_field(data->onmax.max_var, 0);
- destroy_hist_field(data->onmax.var, 0);
+ destroy_hist_field(data->track_data.track_var, 0);
+ destroy_hist_field(data->track_data.var_ref, 0);
- kfree(data->onmax.var_str);
+ kfree(data->track_data.var_str);
action_data_destroy(data);
}
@@ -3529,25 +3597,24 @@ static void onmax_destroy(struct action_
static int action_create(struct hist_trigger_data *hist_data,
struct action_data *data);
-static int onmax_create(struct hist_trigger_data *hist_data,
- struct action_data *data)
+static int track_data_create(struct hist_trigger_data *hist_data,
+ struct action_data *data)
{
- struct hist_field *var_field, *ref_field, *max_var = NULL;
+ struct hist_field *var_field, *ref_field, *track_var = NULL;
struct trace_event_file *file = hist_data->event_file;
- unsigned int var_ref_idx = hist_data->n_var_refs;
- char *onmax_var_str;
+ char *track_data_var_str;
int ret = 0;
- onmax_var_str = data->onmax.var_str;
- if (onmax_var_str[0] != '$') {
- hist_err("onmax: For onmax(x), x must be a variable: ", onmax_var_str);
+ track_data_var_str = data->track_data.var_str;
+ if (track_data_var_str[0] != '$') {
+ hist_err("For onmax(x), x must be a variable: ", track_data_var_str);
return -EINVAL;
}
- onmax_var_str++;
+ track_data_var_str++;
- var_field = find_target_event_var(hist_data, NULL, NULL, onmax_var_str);
+ var_field = find_target_event_var(hist_data, NULL, NULL, track_data_var_str);
if (!var_field) {
- hist_err("onmax: Couldn't find onmax variable: ", onmax_var_str);
+ hist_err("Couldn't find onmax variable: ", track_data_var_str);
return -EINVAL;
}
@@ -3555,17 +3622,16 @@ static int onmax_create(struct hist_trig
if (!ref_field)
return -ENOMEM;
- data->onmax.var = ref_field;
-
- data->onmax.max_var_ref_idx = var_ref_idx;
+ data->track_data.var_ref = ref_field;
- max_var = create_var(hist_data, file, "max", sizeof(u64), "u64");
- if (IS_ERR(max_var)) {
- hist_err("onmax: Couldn't create onmax variable: ", "max");
- ret = PTR_ERR(max_var);
+ if (data->handler == HANDLER_ONMAX)
+ track_var = create_var(hist_data, file, "__max", sizeof(u64), "u64");
+ if (IS_ERR(track_var)) {
+ hist_err("Couldn't create onmax variable: ", "__max");
+ ret = PTR_ERR(track_var);
goto out;
}
- data->onmax.max_var = max_var;
+ data->track_data.track_var = track_var;
ret = action_create(hist_data, data);
out:
@@ -3643,8 +3709,15 @@ static int action_parse(char *str, struc
goto out;
if (handler == HANDLER_ONMAX)
- data->fn = onmax_save;
+ data->track_data.check_val = check_track_val_max;
+ else {
+ hist_err("action parsing: Handler doesn't support action: ", action_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ data->track_data.save_data = save_track_data_vars;
+ data->fn = ontrack_action;
data->action = ACTION_SAVE;
} else {
char *params = strsep(&str, ")");
@@ -3655,7 +3728,15 @@ static int action_parse(char *str, struc
goto out;
}
- data->fn = action_trace;
+ if (handler == HANDLER_ONMAX)
+ data->track_data.check_val = check_track_val_max;
+
+ if (handler != HANDLER_ONMATCH) {
+ data->track_data.save_data = action_trace;
+ data->fn = ontrack_action;
+ } else
+ data->fn = action_trace;
+
data->action = ACTION_TRACE;
}
@@ -3670,24 +3751,25 @@ static int action_parse(char *str, struc
return ret;
}
-static struct action_data *onmax_parse(char *str, enum handler_id handler)
+static struct action_data *track_data_parse(struct hist_trigger_data *hist_data,
+ char *str, enum handler_id handler)
{
struct action_data *data;
- char *onmax_var_str;
int ret = -EINVAL;
+ char *var_str;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
- onmax_var_str = strsep(&str, ")");
- if (!onmax_var_str || !str) {
+ var_str = strsep(&str, ")");
+ if (!var_str || !str) {
ret = -EINVAL;
goto free;
}
- data->onmax.var_str = kstrdup(onmax_var_str, GFP_KERNEL);
- if (!data->onmax.var_str) {
+ data->track_data.var_str = kstrdup(var_str, GFP_KERNEL);
+ if (!data->track_data.var_str) {
ret = -ENOMEM;
goto free;
}
@@ -3698,7 +3780,7 @@ static struct action_data *onmax_parse(c
out:
return data;
free:
- onmax_destroy(data);
+ track_data_destroy(hist_data, data);
data = ERR_PTR(ret);
goto out;
}
@@ -4465,7 +4547,7 @@ static void destroy_actions(struct hist_
if (data->handler == HANDLER_ONMATCH)
onmatch_destroy(data);
else if (data->handler == HANDLER_ONMAX)
- onmax_destroy(data);
+ track_data_destroy(hist_data, data);
else
kfree(data);
}
@@ -4494,7 +4576,8 @@ static int parse_actions(struct hist_tri
} else if ((len = str_has_prefix(str, "onmax("))) {
char *action_str = str + len;
- data = onmax_parse(action_str, HANDLER_ONMAX);
+ data = track_data_parse(hist_data, action_str,
+ HANDLER_ONMAX);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
@@ -4524,7 +4607,7 @@ static int create_actions(struct hist_tr
if (ret)
break;
} else if (data->handler == HANDLER_ONMAX) {
- ret = onmax_create(hist_data, data);
+ ret = track_data_create(hist_data, data);
if (ret)
break;
} else {
@@ -4546,7 +4629,7 @@ static void print_actions(struct seq_fil
struct action_data *data = hist_data->actions[i];
if (data->handler == HANDLER_ONMAX)
- onmax_print(m, hist_data, elt, data);
+ track_data_print(m, hist_data, elt, data);
}
}
@@ -4571,12 +4654,13 @@ static void print_action_spec(struct seq
}
}
-static void print_onmax_spec(struct seq_file *m,
- struct hist_trigger_data *hist_data,
- struct action_data *data)
-{
- seq_puts(m, ":onmax(");
- seq_printf(m, "%s", data->onmax.var_str);
+static void print_track_data_spec(struct seq_file *m,
+ struct hist_trigger_data *hist_data,
+ struct action_data *data)
+{
+ if (data->handler == HANDLER_ONMAX)
+ seq_puts(m, ":onmax(");
+ seq_printf(m, "%s", data->track_data.var_str);
seq_printf(m, ").%s(", data->action_name);
print_action_spec(m, hist_data, data);
@@ -4634,8 +4718,8 @@ static bool actions_match(struct hist_tr
data_test->match_data.event) != 0)
return false;
} else if (data->handler == HANDLER_ONMAX) {
- if (strcmp(data->onmax.var_str,
- data_test->onmax.var_str) != 0)
+ if (strcmp(data->track_data.var_str,
+ data_test->track_data.var_str) != 0)
return false;
}
}
@@ -4655,7 +4739,7 @@ static void print_actions_spec(struct se
if (data->handler == HANDLER_ONMATCH)
print_onmatch_spec(m, hist_data, data);
else if (data->handler == HANDLER_ONMAX)
- print_onmax_spec(m, hist_data, data);
+ print_track_data_spec(m, hist_data, data);
}
}
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 16/18] tracing: Remove unnecessary var_ref destroy in track_data_destroy()
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (14 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 15/18] tracing: Generalize hist trigger onmax and save action Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 17/18] serial: kgdboc: Fix NMI-safety problems from keyboard reset code Greg Kroah-Hartman
` (6 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable@vger.kernel.org, George Guo,
Steven Rostedt (VMware), Tom Zanussi, George Guo
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tom Zanussi <tom.zanussi@linux.intel.com>
commit ff9d31d0d46672e201fc9ff59c42f1eef5f00c77 upstream.
Commit 656fe2ba85e8 (tracing: Use hist trigger's var_ref array to
destroy var_refs) centralized the destruction of all the var_refs
in one place so that other code didn't have to do it.
The track_data_destroy() added later ignored that and also destroyed
the track_data var_ref, causing a double-free error flagged by KASAN.
==================================================================
BUG: KASAN: use-after-free in destroy_hist_field+0x30/0x70
Read of size 8 at addr ffff888086df2210 by task bash/1694
CPU: 6 PID: 1694 Comm: bash Not tainted 5.1.0-rc1-test+ #15
Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v03.03
07/14/2016
Call Trace:
dump_stack+0x71/0xa0
? destroy_hist_field+0x30/0x70
print_address_description.cold.3+0x9/0x1fb
? destroy_hist_field+0x30/0x70
? destroy_hist_field+0x30/0x70
kasan_report.cold.4+0x1a/0x33
? __kasan_slab_free+0x100/0x150
? destroy_hist_field+0x30/0x70
destroy_hist_field+0x30/0x70
track_data_destroy+0x55/0xe0
destroy_hist_data+0x1f0/0x350
hist_unreg_all+0x203/0x220
event_trigger_open+0xbb/0x130
do_dentry_open+0x296/0x700
? stacktrace_count_trigger+0x30/0x30
? generic_permission+0x56/0x200
? __x64_sys_fchdir+0xd0/0xd0
? inode_permission+0x55/0x200
? security_inode_permission+0x18/0x60
path_openat+0x633/0x22b0
? path_lookupat.isra.50+0x420/0x420
? __kasan_kmalloc.constprop.12+0xc1/0xd0
? kmem_cache_alloc+0xe5/0x260
? getname_flags+0x6c/0x2a0
? do_sys_open+0x149/0x2b0
? do_syscall_64+0x73/0x1b0
? entry_SYSCALL_64_after_hwframe+0x44/0xa9
? _raw_write_lock_bh+0xe0/0xe0
? __kernel_text_address+0xe/0x30
? unwind_get_return_address+0x2f/0x50
? __list_add_valid+0x2d/0x70
? deactivate_slab.isra.62+0x1f4/0x5a0
? getname_flags+0x6c/0x2a0
? set_track+0x76/0x120
do_filp_open+0x11a/0x1a0
? may_open_dev+0x50/0x50
? _raw_spin_lock+0x7a/0xd0
? _raw_write_lock_bh+0xe0/0xe0
? __alloc_fd+0x10f/0x200
do_sys_open+0x1db/0x2b0
? filp_open+0x50/0x50
do_syscall_64+0x73/0x1b0
entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x7fa7b24a4ca2
Code: 25 00 00 41 00 3d 00 00 41 00 74 4c 48 8d 05 85 7a 0d 00 8b 00 85 c0
75 6d 89 f2 b8 01 01 00 00 48 89 fe bf 9c ff ff ff 0f 05 <48> 3d 00 f0 ff ff
0f 87 a2 00 00 00 48 8b 4c 24 28 64 48 33 0c 25
RSP: 002b:00007fffbafb3af0 EFLAGS: 00000246 ORIG_RAX: 0000000000000101
RAX: ffffffffffffffda RBX: 000055d3648ade30 RCX: 00007fa7b24a4ca2
RDX: 0000000000000241 RSI: 000055d364a55240 RDI: 00000000ffffff9c
RBP: 00007fffbafb3bf0 R08: 0000000000000020 R09: 0000000000000002
R10: 00000000000001b6 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000003 R14: 0000000000000001 R15: 000055d364a55240
==================================================================
So remove the track_data_destroy() destroy_hist_field() call for that
var_ref.
Link: http://lkml.kernel.org/r/1deffec420f6a16d11dd8647318d34a66d1989a9.camel@linux.intel.com
Fixes: 466f4528fbc69 ("tracing: Generalize hist trigger onmax and save action")
Reported-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/trace/trace_events_hist.c | 1 -
1 file changed, 1 deletion(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -3587,7 +3587,6 @@ static void track_data_destroy(struct hi
struct action_data *data)
{
destroy_hist_field(data->track_data.track_var, 0);
- destroy_hist_field(data->track_data.var_ref, 0);
kfree(data->track_data.var_str);
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 17/18] serial: kgdboc: Fix NMI-safety problems from keyboard reset code
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (15 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 16/18] tracing: Remove unnecessary var_ref destroy in track_data_destroy() Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-23 13:12 ` [PATCH 4.19 18/18] docs: kernel_include.py: Cope with docutils 0.21 Greg Kroah-Hartman
` (5 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Liuye, Douglas Anderson,
Daniel Thompson
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Thompson <daniel.thompson@linaro.org>
commit b2aba15ad6f908d1a620fd97f6af5620c3639742 upstream.
Currently, when kdb is compiled with keyboard support, then we will use
schedule_work() to provoke reset of the keyboard status. Unfortunately
schedule_work() gets called from the kgdboc post-debug-exception
handler. That risks deadlock since schedule_work() is not NMI-safe and,
even on platforms where the NMI is not directly used for debugging, the
debug trap can have NMI-like behaviour depending on where breakpoints
are placed.
Fix this by using the irq work system, which is NMI-safe, to defer the
call to schedule_work() to a point when it is safe to call.
Reported-by: Liuye <liu.yeC@h3c.com>
Closes: https://lore.kernel.org/all/20240228025602.3087748-1-liu.yeC@h3c.com/
Cc: stable@vger.kernel.org
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20240424-kgdboc_fix_schedule_work-v2-1-50f5a490aec5@linaro.org
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/kgdboc.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -16,6 +16,7 @@
#include <linux/console.h>
#include <linux/vt_kern.h>
#include <linux/input.h>
+#include <linux/irq_work.h>
#include <linux/module.h>
#define MAX_CONFIG_LEN 40
@@ -35,6 +36,25 @@ static int kgdboc_use_kms; /* 1 if we u
static struct tty_driver *kgdb_tty_driver;
static int kgdb_tty_line;
+/*
+ * When we leave the debug trap handler we need to reset the keyboard status
+ * (since the original keyboard state gets partially clobbered by kdb use of
+ * the keyboard).
+ *
+ * The path to deliver the reset is somewhat circuitous.
+ *
+ * To deliver the reset we register an input handler, reset the keyboard and
+ * then deregister the input handler. However, to get this done right, we do
+ * have to carefully manage the calling context because we can only register
+ * input handlers from task context.
+ *
+ * In particular we need to trigger the action from the debug trap handler with
+ * all its NMI and/or NMI-like oddities. To solve this the kgdboc trap exit code
+ * (the "post_exception" callback) uses irq_work_queue(), which is NMI-safe, to
+ * schedule a callback from a hardirq context. From there we have to defer the
+ * work again, this time using schedule_work(), to get a callback using the
+ * system workqueue, which runs in task context.
+ */
#ifdef CONFIG_KDB_KEYBOARD
static int kgdboc_reset_connect(struct input_handler *handler,
struct input_dev *dev,
@@ -86,10 +106,17 @@ static void kgdboc_restore_input_helper(
static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+static void kgdboc_queue_restore_input_helper(struct irq_work *unused)
+{
+ schedule_work(&kgdboc_restore_input_work);
+}
+
+static DEFINE_IRQ_WORK(kgdboc_restore_input_irq_work, kgdboc_queue_restore_input_helper);
+
static void kgdboc_restore_input(void)
{
if (likely(system_state == SYSTEM_RUNNING))
- schedule_work(&kgdboc_restore_input_work);
+ irq_work_queue(&kgdboc_restore_input_irq_work);
}
static int kgdboc_register_kbd(char **cptr)
@@ -120,6 +147,7 @@ static void kgdboc_unregister_kbd(void)
i--;
}
}
+ irq_work_sync(&kgdboc_restore_input_irq_work);
flush_work(&kgdboc_restore_input_work);
}
#else /* ! CONFIG_KDB_KEYBOARD */
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 4.19 18/18] docs: kernel_include.py: Cope with docutils 0.21
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (16 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 17/18] serial: kgdboc: Fix NMI-safety problems from keyboard reset code Greg Kroah-Hartman
@ 2024-05-23 13:12 ` Greg Kroah-Hartman
2024-05-24 6:55 ` [PATCH 4.19 00/18] 4.19.315-rc1 review Harshit Mogalapalli
` (4 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2024-05-23 13:12 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Akira Yokosawa, Jonathan Corbet
4.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akira Yokosawa <akiyks@gmail.com>
commit d43ddd5c91802a46354fa4c4381416ef760676e2 upstream.
Running "make htmldocs" on a newly installed Sphinx 7.3.7 ends up in
a build error:
Sphinx parallel build error:
AttributeError: module 'docutils.nodes' has no attribute 'reprunicode'
docutils 0.21 has removed nodes.reprunicode, quote from release note [1]:
* Removed objects:
docutils.nodes.reprunicode, docutils.nodes.ensure_str()
Python 2 compatibility hacks
Sphinx 7.3.0 supports docutils 0.21 [2]:
kernel_include.py, whose origin is misc.py of docutils, uses reprunicode.
Upstream docutils removed the offending line from the corresponding file
(docutils/docutils/parsers/rst/directives/misc.py) in January 2022.
Quoting the changelog [3]:
Deprecate `nodes.reprunicode` and `nodes.ensure_str()`.
Drop uses of the deprecated constructs (not required with Python 3).
Do the same for kernel_include.py.
Tested against:
- Sphinx 2.4.5 (docutils 0.17.1)
- Sphinx 3.4.3 (docutils 0.17.1)
- Sphinx 5.3.0 (docutils 0.18.1)
- Sphinx 6.2.1 (docutils 0.19)
- Sphinx 7.2.6 (docutils 0.20.1)
- Sphinx 7.3.7 (docutils 0.21.2)
Link: http://www.docutils.org/RELEASE-NOTES.html#release-0-21-2024-04-09 [1]
Link: https://www.sphinx-doc.org/en/master/changes.html#release-7-3-0-released-apr-16-2024 [2]
Link: https://github.com/docutils/docutils/commit/c8471ce47a24 [3]
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Link: https://lore.kernel.org/r/faf5fa45-2a9d-4573-9d2e-3930bdc1ed65@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
Documentation/sphinx/kernel_include.py | 1 -
1 file changed, 1 deletion(-)
--- a/Documentation/sphinx/kernel_include.py
+++ b/Documentation/sphinx/kernel_include.py
@@ -94,7 +94,6 @@ class KernelInclude(Include):
# HINT: this is the only line I had to change / commented out:
#path = utils.relative_path(None, path)
- path = nodes.reprunicode(path)
encoding = self.options.get(
'encoding', self.state.document.settings.input_encoding)
e_handler=self.state.document.settings.input_encoding_error_handler
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH 4.19 00/18] 4.19.315-rc1 review
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (17 preceding siblings ...)
2024-05-23 13:12 ` [PATCH 4.19 18/18] docs: kernel_include.py: Cope with docutils 0.21 Greg Kroah-Hartman
@ 2024-05-24 6:55 ` Harshit Mogalapalli
2024-05-24 11:23 ` Pavel Machek
` (3 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Harshit Mogalapalli @ 2024-05-24 6:55 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: patches, linux-kernel, torvalds, akpm, linux, shuah, patches,
lkft-triage, pavel, jonathanh, f.fainelli, sudipm.mukherjee, srw,
rwarsow, conor, allen.lkml, broonie, Vegard Nossum, Darren Kenny
Hi Greg,
On 23/05/24 18:42, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 4.19.315 release.
> There are 18 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Sat, 25 May 2024 13:03:15 +0000.
> Anything received after that time might be too late.
>
No problems seen on x86_64 and aarch64 with our testing.
Tested-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Thanks,
Harshit
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.315-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.19.y
> and the diffstat can be found below.
>
> thanks,
>
> greg k-h
>
> -------------
> Pseudo-Shortlog of commits:
>
> Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Linux 4.19.315-rc1
>
> Akira Yokosawa <akiyks@gmail.com>
> docs: kernel_include.py: Cope with docutils 0.21
>
> Daniel Thompson <daniel.thompson@linaro.org>
> serial: kgdboc: Fix NMI-safety problems from keyboard reset code
>
> Tom Zanussi <tom.zanussi@linux.intel.com>
> tracing: Remove unnecessary var_ref destroy in track_data_destroy()
>
> Tom Zanussi <tom.zanussi@linux.intel.com>
> tracing: Generalize hist trigger onmax and save action
>
> Tom Zanussi <tom.zanussi@linux.intel.com>
> tracing: Split up onmatch action data
>
> Tom Zanussi <tom.zanussi@linux.intel.com>
> tracing: Refactor hist trigger action code
>
> Steven Rostedt (VMware) <rostedt@goodmis.org>
> tracing: Have the historgram use the result of str_has_prefix() for len of prefix
>
> Steven Rostedt (VMware) <rostedt@goodmis.org>
> tracing: Use str_has_prefix() instead of using fixed sizes
>
> Steven Rostedt (VMware) <rostedt@goodmis.org>
> tracing: Use str_has_prefix() helper for histogram code
>
> Steven Rostedt (VMware) <rostedt@goodmis.org>
> string.h: Add str_has_prefix() helper function
>
> Steven Rostedt (VMware) <rostedt@goodmis.org>
> tracing: Consolidate trace_add/remove_event_call back to the nolock functions
>
> Masami Hiramatsu <mhiramat@kernel.org>
> tracing: Remove unneeded synth_event_mutex
>
> Masami Hiramatsu <mhiramat@kernel.org>
> tracing: Use dyn_event framework for synthetic events
>
> Masami Hiramatsu <mhiramat@kernel.org>
> tracing: Add unified dynamic event framework
>
> Masami Hiramatsu <mhiramat@kernel.org>
> tracing: Simplify creation and deletion of synthetic events
>
> Dominique Martinet <dominique.martinet@atmark-techno.com>
> btrfs: add missing mutex_unlock in btrfs_relocate_sys_chunks()
>
> Mikulas Patocka <mpatocka@redhat.com>
> dm: limit the number of targets and parameter size area
>
> Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
> Revert "selftests: mm: fix map_hugetlb failure on 64K page size systems"
>
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH 4.19 00/18] 4.19.315-rc1 review
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (18 preceding siblings ...)
2024-05-24 6:55 ` [PATCH 4.19 00/18] 4.19.315-rc1 review Harshit Mogalapalli
@ 2024-05-24 11:23 ` Pavel Machek
2024-05-24 13:46 ` Anders Roxell
` (2 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Pavel Machek @ 2024-05-24 11:23 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: stable, patches, linux-kernel, torvalds, akpm, linux, shuah,
patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, srw, rwarsow, conor, allen.lkml, broonie
[-- Attachment #1: Type: text/plain, Size: 661 bytes --]
Hi!
> This is the start of the stable review cycle for the 4.19.315 release.
> There are 18 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-4.19.y
Tested-by: Pavel Machek (CIP) <pavel@denx.de>
Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH 4.19 00/18] 4.19.315-rc1 review
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (19 preceding siblings ...)
2024-05-24 11:23 ` Pavel Machek
@ 2024-05-24 13:46 ` Anders Roxell
2024-05-24 15:19 ` Jon Hunter
2024-05-24 16:26 ` Shuah Khan
22 siblings, 0 replies; 24+ messages in thread
From: Anders Roxell @ 2024-05-24 13:46 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: stable, patches, linux-kernel, torvalds, akpm, linux, shuah,
patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, srw, rwarsow, conor, allen.lkml, broonie
On Thu, 23 May 2024 at 15:15, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> This is the start of the stable review cycle for the 4.19.315 release.
> There are 18 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Sat, 25 May 2024 13:03:15 +0000.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.315-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.19.y
> and the diffstat can be found below.
Results from Linaro’s test farm.
No regressions on arm64, arm, x86_64, and i386.
Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
## Build Summary
* arc: 10 total, 10 passed, 0 failed
* arm: 103 total, 97 passed, 6 failed
* arm64: 28 total, 23 passed, 5 failed
* i386: 16 total, 13 passed, 3 failed
* mips: 20 total, 20 passed, 0 failed
* parisc: 3 total, 0 passed, 3 failed
* powerpc: 24 total, 24 passed, 0 failed
* s390: 6 total, 6 passed, 0 failed
* sh: 10 total, 10 passed, 0 failed
* sparc: 6 total, 6 passed, 0 failed
* x86_64: 24 total, 19 passed, 5 failed
## Test suites summary
* boot
* kselftest-mm
* kselftest-net-forwarding
* kselftest-timens
* kselftest-user
* kselftest-zram
* kunit
* log-parser-boot
* log-parser-test
* ltp-cap_bounds
* ltp-commands
* ltp-containers
* ltp-controllers
* ltp-crypto
* ltp-cve
* ltp-fcntl-locktests
* ltp-filecaps
* ltp-fs
* ltp-fs_bind
* ltp-fs_perms_simple
* ltp-hugetlb
* ltp-io
* ltp-ipc
* ltp-math
* ltp-mm
* ltp-nptl
* ltp-pty
* ltp-sched
* ltp-securebits
* ltp-smoke
* ltp-smoketest
* ltp-syscalls
* ltp-tracing
* rcutorture
--
Linaro LKFT
https://lkft.linaro.org
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH 4.19 00/18] 4.19.315-rc1 review
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (20 preceding siblings ...)
2024-05-24 13:46 ` Anders Roxell
@ 2024-05-24 15:19 ` Jon Hunter
2024-05-24 16:26 ` Shuah Khan
22 siblings, 0 replies; 24+ messages in thread
From: Jon Hunter @ 2024-05-24 15:19 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Greg Kroah-Hartman, patches, linux-kernel, torvalds, akpm, linux,
shuah, patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, srw, rwarsow, conor, allen.lkml, broonie,
linux-tegra, stable
On Thu, 23 May 2024 15:12:23 +0200, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 4.19.315 release.
> There are 18 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Sat, 25 May 2024 13:03:15 +0000.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.315-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.19.y
> and the diffstat can be found below.
>
> thanks,
>
> greg k-h
All tests passing for Tegra ...
Test results for stable-v4.19:
10 builds: 10 pass, 0 fail
20 boots: 20 pass, 0 fail
37 tests: 37 pass, 0 fail
Linux version: 4.19.315-rc1-g35248f5e8353
Boards tested: tegra124-jetson-tk1, tegra186-p2771-0000,
tegra194-p2972-0000, tegra20-ventana,
tegra210-p2371-2180, tegra30-cardhu-a04
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Jon
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH 4.19 00/18] 4.19.315-rc1 review
2024-05-23 13:12 [PATCH 4.19 00/18] 4.19.315-rc1 review Greg Kroah-Hartman
` (21 preceding siblings ...)
2024-05-24 15:19 ` Jon Hunter
@ 2024-05-24 16:26 ` Shuah Khan
22 siblings, 0 replies; 24+ messages in thread
From: Shuah Khan @ 2024-05-24 16:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: patches, linux-kernel, torvalds, akpm, linux, shuah, patches,
lkft-triage, pavel, jonathanh, f.fainelli, sudipm.mukherjee, srw,
rwarsow, conor, allen.lkml, broonie, Shuah Khan
On 5/23/24 07:12, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 4.19.315 release.
> There are 18 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Sat, 25 May 2024 13:03:15 +0000.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.315-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.19.y
> and the diffstat can be found below.
>
> thanks,
>
> greg k-h
>
Compiled and booted on my test system. No dmesg regressions.
Tested-by: Shuah Khan <skhan@linuxfoundation.org>
thanks,
-- Shuah
^ permalink raw reply [flat|nested] 24+ messages in thread