Skip to content

Commit fa3889d

Browse files
committed
Merge tag 'trace-user-events-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull tracing user-event updates from Steven Rostedt: - Minor update to the user_events interface The ABI of creating a user event states that the fields are separated by semicolons, and spaces should be ignored. But the parsing expected at least one space to be there (which was incorrect). Fix the reading of the string to handle fields separated by semicolons but no space between them. This does extend the API sightly as now "field;field" will now be parsed and not cause an error. But it should not cause any regressions as no logic should expect it to fail. Note, that the logic that parses the event fields to create the trace_event works with no spaces after the semi-colon. It is the logic that tests against existing events that is inconsistent. This causes registering an event without using spaces to succeed if it doesn't exist, but makes the same call that tries to register to the same event, but doesn't use spaces, fail. * tag 'trace-user-events-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: selftests/user_events: Add non-spacing separator check tracing/user_events: Fix non-spaced field matching
2 parents 53683e4 + 78490b7 commit fa3889d

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

kernel/trace/trace_events_user.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,80 @@ static int user_event_set_tp_name(struct user_event *user)
19891989
return 0;
19901990
}
19911991

1992+
/*
1993+
* Counts how many ';' without a trailing space are in the args.
1994+
*/
1995+
static int count_semis_no_space(char *args)
1996+
{
1997+
int count = 0;
1998+
1999+
while ((args = strchr(args, ';'))) {
2000+
args++;
2001+
2002+
if (!isspace(*args))
2003+
count++;
2004+
}
2005+
2006+
return count;
2007+
}
2008+
2009+
/*
2010+
* Copies the arguments while ensuring all ';' have a trailing space.
2011+
*/
2012+
static char *insert_space_after_semis(char *args, int count)
2013+
{
2014+
char *fixed, *pos;
2015+
int len;
2016+
2017+
len = strlen(args) + count;
2018+
fixed = kmalloc(len + 1, GFP_KERNEL);
2019+
2020+
if (!fixed)
2021+
return NULL;
2022+
2023+
pos = fixed;
2024+
2025+
/* Insert a space after ';' if there is no trailing space. */
2026+
while (*args) {
2027+
*pos = *args++;
2028+
2029+
if (*pos++ == ';' && !isspace(*args))
2030+
*pos++ = ' ';
2031+
}
2032+
2033+
*pos = '\0';
2034+
2035+
return fixed;
2036+
}
2037+
2038+
static char **user_event_argv_split(char *args, int *argc)
2039+
{
2040+
char **split;
2041+
char *fixed;
2042+
int count;
2043+
2044+
/* Count how many ';' without a trailing space */
2045+
count = count_semis_no_space(args);
2046+
2047+
/* No fixup is required */
2048+
if (!count)
2049+
return argv_split(GFP_KERNEL, args, argc);
2050+
2051+
/* We must fixup 'field;field' to 'field; field' */
2052+
fixed = insert_space_after_semis(args, count);
2053+
2054+
if (!fixed)
2055+
return NULL;
2056+
2057+
/* We do a normal split afterwards */
2058+
split = argv_split(GFP_KERNEL, fixed, argc);
2059+
2060+
/* We can free since argv_split makes a copy */
2061+
kfree(fixed);
2062+
2063+
return split;
2064+
}
2065+
19922066
/*
19932067
* Parses the event name, arguments and flags then registers if successful.
19942068
* The name buffer lifetime is owned by this method for success cases only.
@@ -2012,7 +2086,7 @@ static int user_event_parse(struct user_event_group *group, char *name,
20122086
return -EPERM;
20132087

20142088
if (args) {
2015-
argv = argv_split(GFP_KERNEL, args, &argc);
2089+
argv = user_event_argv_split(args, &argc);
20162090

20172091
if (!argv)
20182092
return -ENOMEM;

tools/testing/selftests/user_events/ftrace_test.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,12 @@ TEST_F(user, register_events) {
261261
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
262262
ASSERT_EQ(0, reg.write_index);
263263

264+
/* Register without separator spacing should still match */
265+
reg.enable_bit = 29;
266+
reg.name_args = (__u64)"__test_event u32 field1;u32 field2";
267+
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
268+
ASSERT_EQ(0, reg.write_index);
269+
264270
/* Multiple registers to same name but different args should fail */
265271
reg.enable_bit = 29;
266272
reg.name_args = (__u64)"__test_event u32 field1;";
@@ -288,6 +294,8 @@ TEST_F(user, register_events) {
288294
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
289295
unreg.disable_bit = 30;
290296
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
297+
unreg.disable_bit = 29;
298+
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
291299

292300
/* Delete should have been auto-done after close and unregister */
293301
close(self->data_fd);

0 commit comments

Comments
 (0)