Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

user_events: Add self-test for ftrace integration

Tests basic functionality of registering/deregistering, status and
writing data out via ftrace mechanisms within user_events.

Link: https://lkml.kernel.org/r/20220118204326.2169-8-beaub@linux.microsoft.com

Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Beau Belgrave and committed by
Steven Rostedt (Google)
446640e4 2467cda1

+397
+9
tools/testing/selftests/user_events/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + CFLAGS += -Wl,-no-as-needed -Wall -I../../../../usr/include 3 + LDLIBS += -lrt -lpthread -lm 4 + 5 + TEST_GEN_PROGS = ftrace_test 6 + 7 + TEST_FILES := settings 8 + 9 + include ../lib.mk
+387
tools/testing/selftests/user_events/ftrace_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * User Events FTrace Test Program 4 + * 5 + * Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com> 6 + */ 7 + 8 + #include <errno.h> 9 + #include <linux/user_events.h> 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <fcntl.h> 13 + #include <sys/ioctl.h> 14 + #include <sys/stat.h> 15 + #include <unistd.h> 16 + 17 + #include "../kselftest_harness.h" 18 + 19 + const char *data_file = "/sys/kernel/debug/tracing/user_events_data"; 20 + const char *status_file = "/sys/kernel/debug/tracing/user_events_status"; 21 + const char *enable_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/enable"; 22 + const char *trace_file = "/sys/kernel/debug/tracing/trace"; 23 + const char *fmt_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/format"; 24 + 25 + static int trace_bytes(void) 26 + { 27 + int fd = open(trace_file, O_RDONLY); 28 + char buf[256]; 29 + int bytes = 0, got; 30 + 31 + if (fd == -1) 32 + return -1; 33 + 34 + while (true) { 35 + got = read(fd, buf, sizeof(buf)); 36 + 37 + if (got == -1) 38 + return -1; 39 + 40 + if (got == 0) 41 + break; 42 + 43 + bytes += got; 44 + } 45 + 46 + close(fd); 47 + 48 + return bytes; 49 + } 50 + 51 + static int skip_until_empty_line(FILE *fp) 52 + { 53 + int c, last = 0; 54 + 55 + while (true) { 56 + c = getc(fp); 57 + 58 + if (c == EOF) 59 + break; 60 + 61 + if (last == '\n' && c == '\n') 62 + return 0; 63 + 64 + last = c; 65 + } 66 + 67 + return -1; 68 + } 69 + 70 + static int get_print_fmt(char *buffer, int len) 71 + { 72 + FILE *fp = fopen(fmt_file, "r"); 73 + char *newline; 74 + 75 + if (!fp) 76 + return -1; 77 + 78 + /* Read until empty line (Skip Common) */ 79 + if (skip_until_empty_line(fp) < 0) 80 + goto err; 81 + 82 + /* Read until empty line (Skip Properties) */ 83 + if (skip_until_empty_line(fp) < 0) 84 + goto err; 85 + 86 + /* Read in print_fmt: */ 87 + if (fgets(buffer, len, fp) == NULL) 88 + goto err; 89 + 90 + newline = strchr(buffer, '\n'); 91 + 92 + if (newline) 93 + *newline = '\0'; 94 + 95 + fclose(fp); 96 + 97 + return 0; 98 + err: 99 + fclose(fp); 100 + 101 + return -1; 102 + } 103 + 104 + static int clear(void) 105 + { 106 + int fd = open(data_file, O_RDWR); 107 + 108 + if (fd == -1) 109 + return -1; 110 + 111 + if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1) 112 + if (errno != ENOENT) 113 + return -1; 114 + 115 + close(fd); 116 + 117 + return 0; 118 + } 119 + 120 + static int check_print_fmt(const char *event, const char *expected) 121 + { 122 + struct user_reg reg = {0}; 123 + char print_fmt[256]; 124 + int ret; 125 + int fd; 126 + 127 + /* Ensure cleared */ 128 + ret = clear(); 129 + 130 + if (ret != 0) 131 + return ret; 132 + 133 + fd = open(data_file, O_RDWR); 134 + 135 + if (fd == -1) 136 + return fd; 137 + 138 + reg.size = sizeof(reg); 139 + reg.name_args = (__u64)event; 140 + 141 + /* Register should work */ 142 + ret = ioctl(fd, DIAG_IOCSREG, &reg); 143 + 144 + close(fd); 145 + 146 + if (ret != 0) 147 + return ret; 148 + 149 + /* Ensure correct print_fmt */ 150 + ret = get_print_fmt(print_fmt, sizeof(print_fmt)); 151 + 152 + if (ret != 0) 153 + return ret; 154 + 155 + return strcmp(print_fmt, expected); 156 + } 157 + 158 + FIXTURE(user) { 159 + int status_fd; 160 + int data_fd; 161 + int enable_fd; 162 + }; 163 + 164 + FIXTURE_SETUP(user) { 165 + self->status_fd = open(status_file, O_RDONLY); 166 + ASSERT_NE(-1, self->status_fd); 167 + 168 + self->data_fd = open(data_file, O_RDWR); 169 + ASSERT_NE(-1, self->data_fd); 170 + 171 + self->enable_fd = -1; 172 + } 173 + 174 + FIXTURE_TEARDOWN(user) { 175 + close(self->status_fd); 176 + close(self->data_fd); 177 + 178 + if (self->enable_fd != -1) { 179 + write(self->enable_fd, "0", sizeof("0")); 180 + close(self->enable_fd); 181 + } 182 + 183 + ASSERT_EQ(0, clear()); 184 + } 185 + 186 + TEST_F(user, register_events) { 187 + struct user_reg reg = {0}; 188 + int page_size = sysconf(_SC_PAGESIZE); 189 + char *status_page; 190 + 191 + reg.size = sizeof(reg); 192 + reg.name_args = (__u64)"__test_event u32 field1; u32 field2"; 193 + 194 + status_page = mmap(NULL, page_size, PROT_READ, MAP_SHARED, 195 + self->status_fd, 0); 196 + 197 + /* Register should work */ 198 + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg)); 199 + ASSERT_EQ(0, reg.write_index); 200 + ASSERT_NE(0, reg.status_index); 201 + 202 + /* Multiple registers should result in same index */ 203 + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg)); 204 + ASSERT_EQ(0, reg.write_index); 205 + ASSERT_NE(0, reg.status_index); 206 + 207 + /* Ensure disabled */ 208 + self->enable_fd = open(enable_file, O_RDWR); 209 + ASSERT_NE(-1, self->enable_fd); 210 + ASSERT_NE(-1, write(self->enable_fd, "0", sizeof("0"))) 211 + 212 + /* MMAP should work and be zero'd */ 213 + ASSERT_NE(MAP_FAILED, status_page); 214 + ASSERT_NE(NULL, status_page); 215 + ASSERT_EQ(0, status_page[reg.status_index]); 216 + 217 + /* Enable event and ensure bits updated in status */ 218 + ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) 219 + ASSERT_EQ(EVENT_STATUS_FTRACE, status_page[reg.status_index]); 220 + 221 + /* Disable event and ensure bits updated in status */ 222 + ASSERT_NE(-1, write(self->enable_fd, "0", sizeof("0"))) 223 + ASSERT_EQ(0, status_page[reg.status_index]); 224 + 225 + /* File still open should return -EBUSY for delete */ 226 + ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event")); 227 + ASSERT_EQ(EBUSY, errno); 228 + 229 + /* Delete should work only after close */ 230 + close(self->data_fd); 231 + self->data_fd = open(data_file, O_RDWR); 232 + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event")); 233 + 234 + /* Unmap should work */ 235 + ASSERT_EQ(0, munmap(status_page, page_size)); 236 + } 237 + 238 + TEST_F(user, write_events) { 239 + struct user_reg reg = {0}; 240 + struct iovec io[3]; 241 + __u32 field1, field2; 242 + int before = 0, after = 0; 243 + 244 + reg.size = sizeof(reg); 245 + reg.name_args = (__u64)"__test_event u32 field1; u32 field2"; 246 + 247 + field1 = 1; 248 + field2 = 2; 249 + 250 + io[0].iov_base = &reg.write_index; 251 + io[0].iov_len = sizeof(reg.write_index); 252 + io[1].iov_base = &field1; 253 + io[1].iov_len = sizeof(field1); 254 + io[2].iov_base = &field2; 255 + io[2].iov_len = sizeof(field2); 256 + 257 + /* Register should work */ 258 + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg)); 259 + ASSERT_EQ(0, reg.write_index); 260 + ASSERT_NE(0, reg.status_index); 261 + 262 + /* Write should fail on invalid slot with ENOENT */ 263 + io[0].iov_base = &field2; 264 + io[0].iov_len = sizeof(field2); 265 + ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 266 + ASSERT_EQ(ENOENT, errno); 267 + io[0].iov_base = &reg.write_index; 268 + io[0].iov_len = sizeof(reg.write_index); 269 + 270 + /* Enable event */ 271 + self->enable_fd = open(enable_file, O_RDWR); 272 + ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) 273 + 274 + /* Write should make it out to ftrace buffers */ 275 + before = trace_bytes(); 276 + ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 3)); 277 + after = trace_bytes(); 278 + ASSERT_GT(after, before); 279 + } 280 + 281 + TEST_F(user, write_fault) { 282 + struct user_reg reg = {0}; 283 + struct iovec io[2]; 284 + int l = sizeof(__u64); 285 + void *anon; 286 + 287 + reg.size = sizeof(reg); 288 + reg.name_args = (__u64)"__test_event u64 anon"; 289 + 290 + anon = mmap(NULL, l, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 291 + ASSERT_NE(MAP_FAILED, anon); 292 + 293 + io[0].iov_base = &reg.write_index; 294 + io[0].iov_len = sizeof(reg.write_index); 295 + io[1].iov_base = anon; 296 + io[1].iov_len = l; 297 + 298 + /* Register should work */ 299 + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg)); 300 + ASSERT_EQ(0, reg.write_index); 301 + ASSERT_NE(0, reg.status_index); 302 + 303 + /* Write should work normally */ 304 + ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2)); 305 + 306 + /* Faulted data should zero fill and work */ 307 + ASSERT_EQ(0, madvise(anon, l, MADV_DONTNEED)); 308 + ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2)); 309 + ASSERT_EQ(0, munmap(anon, l)); 310 + } 311 + 312 + TEST_F(user, print_fmt) { 313 + int ret; 314 + 315 + ret = check_print_fmt("__test_event __rel_loc char[] data", 316 + "print fmt: \"data=%s\", __get_rel_str(data)"); 317 + ASSERT_EQ(0, ret); 318 + 319 + ret = check_print_fmt("__test_event __data_loc char[] data", 320 + "print fmt: \"data=%s\", __get_str(data)"); 321 + ASSERT_EQ(0, ret); 322 + 323 + ret = check_print_fmt("__test_event s64 data", 324 + "print fmt: \"data=%lld\", REC->data"); 325 + ASSERT_EQ(0, ret); 326 + 327 + ret = check_print_fmt("__test_event u64 data", 328 + "print fmt: \"data=%llu\", REC->data"); 329 + ASSERT_EQ(0, ret); 330 + 331 + ret = check_print_fmt("__test_event s32 data", 332 + "print fmt: \"data=%d\", REC->data"); 333 + ASSERT_EQ(0, ret); 334 + 335 + ret = check_print_fmt("__test_event u32 data", 336 + "print fmt: \"data=%u\", REC->data"); 337 + ASSERT_EQ(0, ret); 338 + 339 + ret = check_print_fmt("__test_event int data", 340 + "print fmt: \"data=%d\", REC->data"); 341 + ASSERT_EQ(0, ret); 342 + 343 + ret = check_print_fmt("__test_event unsigned int data", 344 + "print fmt: \"data=%u\", REC->data"); 345 + ASSERT_EQ(0, ret); 346 + 347 + ret = check_print_fmt("__test_event s16 data", 348 + "print fmt: \"data=%d\", REC->data"); 349 + ASSERT_EQ(0, ret); 350 + 351 + ret = check_print_fmt("__test_event u16 data", 352 + "print fmt: \"data=%u\", REC->data"); 353 + ASSERT_EQ(0, ret); 354 + 355 + ret = check_print_fmt("__test_event short data", 356 + "print fmt: \"data=%d\", REC->data"); 357 + ASSERT_EQ(0, ret); 358 + 359 + ret = check_print_fmt("__test_event unsigned short data", 360 + "print fmt: \"data=%u\", REC->data"); 361 + ASSERT_EQ(0, ret); 362 + 363 + ret = check_print_fmt("__test_event s8 data", 364 + "print fmt: \"data=%d\", REC->data"); 365 + ASSERT_EQ(0, ret); 366 + 367 + ret = check_print_fmt("__test_event u8 data", 368 + "print fmt: \"data=%u\", REC->data"); 369 + ASSERT_EQ(0, ret); 370 + 371 + ret = check_print_fmt("__test_event char data", 372 + "print fmt: \"data=%d\", REC->data"); 373 + ASSERT_EQ(0, ret); 374 + 375 + ret = check_print_fmt("__test_event unsigned char data", 376 + "print fmt: \"data=%u\", REC->data"); 377 + ASSERT_EQ(0, ret); 378 + 379 + ret = check_print_fmt("__test_event char[4] data", 380 + "print fmt: \"data=%s\", REC->data"); 381 + ASSERT_EQ(0, ret); 382 + } 383 + 384 + int main(int argc, char **argv) 385 + { 386 + return test_harness_run(argc, argv); 387 + }
+1
tools/testing/selftests/user_events/settings
··· 1 + timeout=90