Files
linux/tools/testing/selftests/user_events/dyn_test.c
Beau Belgrave a06023a8f7 selftests/user_events: Fix failures when user_events is not installed
When user_events is not installed the self tests currently fail. Now
that these self tests run by default we need to ensure they don't fail
when user_events was not enabled for the kernel being tested.

Add common methods to detect if tracefs and user_events is enabled. If
either is not enabled skip the test. If tracefs is enabled, but is not
mounted, mount tracefs and fail if there were any errors. Fail if not
run as root.

Fixes: 68b4d2d583 ("selftests/user_events: Reenable build")
Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org>
Link: https://lore.kernel.org/all/CA+G9fYuugZ0OMeS6HvpSS4nuf_A3s455ecipGBvER0LJHojKZg@mail.gmail.com/

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2023-09-11 17:04:11 -06:00

240 lines
5.3 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* User Events Dyn Events Test Program
*
* Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com>
*/
#include <errno.h>
#include <linux/user_events.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "../kselftest_harness.h"
#include "user_events_selftests.h"
const char *abi_file = "/sys/kernel/tracing/user_events_data";
const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
static bool wait_for_delete(void)
{
int i;
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);
return ret;
}
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 { \
bool match; \
ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
ASSERT_EQ(true, match); \
} while (0)
#define TEST_NMATCH(x, y) \
do { \
bool match; \
ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
ASSERT_EQ(false, match); \
} while (0)
#define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
#define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
FIXTURE(user) {
int check;
};
FIXTURE_SETUP(user) {
USER_EVENT_FIXTURE_SETUP(return);
}
FIXTURE_TEARDOWN(user) {
wait_for_delete();
}
TEST_F(user, basic_types) {
/* All should work */
TEST_PARSE("u:__test_event u64 a");
TEST_PARSE("u:__test_event u32 a");
TEST_PARSE("u:__test_event u16 a");
TEST_PARSE("u:__test_event u8 a");
TEST_PARSE("u:__test_event char a");
TEST_PARSE("u:__test_event unsigned char a");
TEST_PARSE("u:__test_event int a");
TEST_PARSE("u:__test_event unsigned int a");
TEST_PARSE("u:__test_event short a");
TEST_PARSE("u:__test_event unsigned short a");
TEST_PARSE("u:__test_event char[20] a");
TEST_PARSE("u:__test_event unsigned char[20] a");
TEST_PARSE("u:__test_event char[0x14] a");
TEST_PARSE("u:__test_event unsigned char[0x14] a");
/* Bad size format should fail */
TEST_NPARSE("u:__test_event char[aa] a");
/* Large size should fail */
TEST_NPARSE("u:__test_event char[9999] a");
/* Long size string should fail */
TEST_NPARSE("u:__test_event char[0x0000000000001] a");
}
TEST_F(user, loc_types) {
/* All should work */
TEST_PARSE("u:__test_event __data_loc char[] a");
TEST_PARSE("u:__test_event __data_loc unsigned char[] a");
TEST_PARSE("u:__test_event __rel_loc char[] a");
TEST_PARSE("u:__test_event __rel_loc unsigned char[] a");
}
TEST_F(user, size_types) {
/* Should work */
TEST_PARSE("u:__test_event struct custom a 20");
/* Size not specified on struct should fail */
TEST_NPARSE("u:__test_event struct custom a");
/* Size specified on non-struct should fail */
TEST_NPARSE("u:__test_event char a 20");
}
TEST_F(user, matching) {
/* Single name matches */
TEST_MATCH("__test_event u32 a",
"__test_event u32 a");
/* Multiple names match */
TEST_MATCH("__test_event u32 a; u32 b",
"__test_event u32 a; u32 b");
/* Multiple names match with dangling ; */
TEST_MATCH("__test_event u32 a; u32 b",
"__test_event u32 a; u32 b;");
/* Single name doesn't match */
TEST_NMATCH("__test_event u32 a",
"__test_event u32 b");
/* Multiple names don't match */
TEST_NMATCH("__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");
/* Struct name and size matches */
TEST_MATCH("__test_event struct my_struct a 20",
"__test_event struct my_struct a 20");
/* Struct name don't match */
TEST_NMATCH("__test_event struct my_struct a 20",
"__test_event struct my_struct b 20");
/* Struct size don't match */
TEST_NMATCH("__test_event struct my_struct a 20",
"__test_event struct my_struct a 21");
}
int main(int argc, char **argv)
{
return test_harness_run(argc, argv);
}