selftests/user_events: Adapt dyn_test to non-persist events

Now that user_events does not honor persist events the dynamic_events
file cannot be easily used to test parsing and matching cases.

Update dyn_test to use the direct ABI file instead of dynamic_events so
that we still have testing coverage until persist events and
dynamic_events file integration has been decided.

Link: https://lkml.kernel.org/r/20230614163336.5797-6-beaub@linux.microsoft.com

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
Beau Belgrave 2023-06-14 09:33:35 -07:00 committed by Steven Rostedt (Google)
parent 216a137e3e
commit 61701242e8
1 changed files with 136 additions and 41 deletions

View File

@ -16,42 +16,140 @@
#include "../kselftest_harness.h" #include "../kselftest_harness.h"
const char *dyn_file = "/sys/kernel/tracing/dynamic_events"; const char *abi_file = "/sys/kernel/tracing/user_events_data";
const char *clear = "!u:__test_event"; const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
static int Append(const char *value) static bool wait_for_delete(void)
{ {
int fd = open(dyn_file, O_RDWR | O_APPEND); int i;
int ret = write(fd, value, strlen(value));
for (i = 0; i < 1000; ++i) {
int fd = open(enable_file, O_RDONLY);
if (fd == -1)
return true;
close(fd);
usleep(1000);
}
return false;
}
static int reg_event(int fd, int *check, int bit, const char *value)
{
struct user_reg reg = {0};
reg.size = sizeof(reg);
reg.name_args = (__u64)value;
reg.enable_bit = bit;
reg.enable_addr = (__u64)check;
reg.enable_size = sizeof(*check);
if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
return -1;
return 0;
}
static int unreg_event(int fd, int *check, int bit)
{
struct user_unreg unreg = {0};
unreg.size = sizeof(unreg);
unreg.disable_bit = bit;
unreg.disable_addr = (__u64)check;
return ioctl(fd, DIAG_IOCSUNREG, &unreg);
}
static int parse(int *check, const char *value)
{
int fd = open(abi_file, O_RDWR);
int ret;
if (fd == -1)
return -1;
/* Until we have persist flags via dynamic events, use the base name */
if (value[0] != 'u' || value[1] != ':') {
close(fd);
return -1;
}
ret = reg_event(fd, check, 31, value + 2);
if (ret != -1) {
if (unreg_event(fd, check, 31) == -1)
printf("WARN: Couldn't unreg event\n");
}
close(fd); close(fd);
return ret; return ret;
} }
#define CLEAR() \ static int check_match(int *check, const char *first, const char *second, bool *match)
{
int fd = open(abi_file, O_RDWR);
int ret = -1;
if (fd == -1)
return -1;
if (reg_event(fd, check, 31, first) == -1)
goto cleanup;
if (reg_event(fd, check, 30, second) == -1) {
if (errno == EADDRINUSE) {
/* Name is in use, with different fields */
*match = false;
ret = 0;
}
goto cleanup;
}
*match = true;
ret = 0;
cleanup:
unreg_event(fd, check, 31);
unreg_event(fd, check, 30);
close(fd);
wait_for_delete();
return ret;
}
#define TEST_MATCH(x, y) \
do { \ do { \
int ret = Append(clear); \ bool match; \
if (ret == -1) \ ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
ASSERT_EQ(ENOENT, errno); \ ASSERT_EQ(true, match); \
} while (0) } while (0)
#define TEST_PARSE(x) \ #define TEST_NMATCH(x, y) \
do { \ do { \
ASSERT_NE(-1, Append(x)); \ bool match; \
CLEAR(); \ ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
ASSERT_EQ(false, match); \
} while (0) } while (0)
#define TEST_NPARSE(x) ASSERT_EQ(-1, Append(x)) #define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
#define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
FIXTURE(user) { FIXTURE(user) {
int check;
}; };
FIXTURE_SETUP(user) { FIXTURE_SETUP(user) {
CLEAR();
} }
FIXTURE_TEARDOWN(user) { FIXTURE_TEARDOWN(user) {
CLEAR(); wait_for_delete();
} }
TEST_F(user, basic_types) { TEST_F(user, basic_types) {
@ -95,33 +193,30 @@ TEST_F(user, size_types) {
TEST_NPARSE("u:__test_event char a 20"); TEST_NPARSE("u:__test_event char a 20");
} }
TEST_F(user, flags) {
/* Should work */
TEST_PARSE("u:__test_event:BPF_ITER u32 a");
/* Forward compat */
TEST_PARSE("u:__test_event:BPF_ITER,FLAG_FUTURE u32 a");
}
TEST_F(user, matching) { TEST_F(user, matching) {
/* Register */ /* Single name matches */
ASSERT_NE(-1, Append("u:__test_event struct custom a 20")); TEST_MATCH("__test_event u32 a",
/* Should not match */ "__test_event u32 a");
TEST_NPARSE("!u:__test_event struct custom b");
/* Should match */ /* Multiple names match */
TEST_PARSE("!u:__test_event struct custom a"); TEST_MATCH("__test_event u32 a; u32 b",
/* Multi field reg */ "__test_event u32 a; u32 b");
ASSERT_NE(-1, Append("u:__test_event u32 a; u32 b"));
/* Non matching cases */ /* Multiple names match with dangling ; */
TEST_NPARSE("!u:__test_event u32 a"); TEST_MATCH("__test_event u32 a; u32 b",
TEST_NPARSE("!u:__test_event u32 b"); "__test_event u32 a; u32 b;");
TEST_NPARSE("!u:__test_event u32 a; u32 ");
TEST_NPARSE("!u:__test_event u32 a; u32 a"); /* Single name doesn't match */
/* Matching case */ TEST_NMATCH("__test_event u32 a",
TEST_PARSE("!u:__test_event u32 a; u32 b"); "__test_event u32 b");
/* Register */
ASSERT_NE(-1, Append("u:__test_event u32 a; u32 b")); /* Multiple names don't match */
/* Ensure trailing semi-colon case */ TEST_NMATCH("__test_event u32 a; u32 b",
TEST_PARSE("!u:__test_event u32 a; u32 b;"); "__test_event u32 b; u32 a");
/* Types don't match */
TEST_NMATCH("__test_event u64 a; u64 b",
"__test_event u32 a; u32 b");
} }
int main(int argc, char **argv) int main(int argc, char **argv)