Commit fa3889d9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'trace-user-events-v6.10' of...

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
parents 53683e40 78490b74
...@@ -1989,6 +1989,80 @@ static int user_event_set_tp_name(struct user_event *user) ...@@ -1989,6 +1989,80 @@ static int user_event_set_tp_name(struct user_event *user)
return 0; return 0;
} }
/*
* Counts how many ';' without a trailing space are in the args.
*/
static int count_semis_no_space(char *args)
{
int count = 0;
while ((args = strchr(args, ';'))) {
args++;
if (!isspace(*args))
count++;
}
return count;
}
/*
* Copies the arguments while ensuring all ';' have a trailing space.
*/
static char *insert_space_after_semis(char *args, int count)
{
char *fixed, *pos;
int len;
len = strlen(args) + count;
fixed = kmalloc(len + 1, GFP_KERNEL);
if (!fixed)
return NULL;
pos = fixed;
/* Insert a space after ';' if there is no trailing space. */
while (*args) {
*pos = *args++;
if (*pos++ == ';' && !isspace(*args))
*pos++ = ' ';
}
*pos = '\0';
return fixed;
}
static char **user_event_argv_split(char *args, int *argc)
{
char **split;
char *fixed;
int count;
/* Count how many ';' without a trailing space */
count = count_semis_no_space(args);
/* No fixup is required */
if (!count)
return argv_split(GFP_KERNEL, args, argc);
/* We must fixup 'field;field' to 'field; field' */
fixed = insert_space_after_semis(args, count);
if (!fixed)
return NULL;
/* We do a normal split afterwards */
split = argv_split(GFP_KERNEL, fixed, argc);
/* We can free since argv_split makes a copy */
kfree(fixed);
return split;
}
/* /*
* Parses the event name, arguments and flags then registers if successful. * Parses the event name, arguments and flags then registers if successful.
* The name buffer lifetime is owned by this method for success cases only. * 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, ...@@ -2012,7 +2086,7 @@ static int user_event_parse(struct user_event_group *group, char *name,
return -EPERM; return -EPERM;
if (args) { if (args) {
argv = argv_split(GFP_KERNEL, args, &argc); argv = user_event_argv_split(args, &argc);
if (!argv) if (!argv)
return -ENOMEM; return -ENOMEM;
......
...@@ -261,6 +261,12 @@ TEST_F(user, register_events) { ...@@ -261,6 +261,12 @@ TEST_F(user, register_events) {
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg)); ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
ASSERT_EQ(0, reg.write_index); ASSERT_EQ(0, reg.write_index);
/* Register without separator spacing should still match */
reg.enable_bit = 29;
reg.name_args = (__u64)"__test_event u32 field1;u32 field2";
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
ASSERT_EQ(0, reg.write_index);
/* Multiple registers to same name but different args should fail */ /* Multiple registers to same name but different args should fail */
reg.enable_bit = 29; reg.enable_bit = 29;
reg.name_args = (__u64)"__test_event u32 field1;"; reg.name_args = (__u64)"__test_event u32 field1;";
...@@ -288,6 +294,8 @@ TEST_F(user, register_events) { ...@@ -288,6 +294,8 @@ TEST_F(user, register_events) {
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
unreg.disable_bit = 30; unreg.disable_bit = 30;
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
unreg.disable_bit = 29;
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
/* Delete should have been auto-done after close and unregister */ /* Delete should have been auto-done after close and unregister */
close(self->data_fd); close(self->data_fd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment