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

selftests/bpf: Add read_trace_pipe_iter function

We have two printk tests reading trace_pipe in non blocking way,
with the very same code. Moving that in new read_trace_pipe_iter
function.

Current read_trace_pipe is used from samples/bpf and needs to
do blocking read and printf of the trace_pipe data, using new
read_trace_pipe_iter to implement that.

Both printk tests do early checks for the number of found messages
and can bail earlier, but I did not find any speed difference w/o
that condition, so I did not complicate the change more for that.

Some of the samples/bpf programs use read_trace_pipe function,
so I kept that interface untouched. I did not see any issues with
affected samples/bpf programs other than there's slight change in
read_trace_pipe output. The current code uses puts that adds new
line after the printed string, so we would occasionally see extra
new line. With this patch we read output per lines, so there's no
need to use puts and we can use just printf instead without extra
new line.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/bpf/20240410140952.292261-1-jolsa@kernel.org

authored by

Jiri Olsa and committed by
Daniel Borkmann
4d4992ff 23cc4fe4

+60 -77
+9 -27
tools/testing/selftests/bpf/prog_tests/trace_printk.c
··· 5 5 6 6 #include "trace_printk.lskel.h" 7 7 8 - #define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe" 9 - #define DEBUGFS_PIPE "/sys/kernel/debug/tracing/trace_pipe" 10 8 #define SEARCHMSG "testing,testing" 9 + 10 + static void trace_pipe_cb(const char *str, void *data) 11 + { 12 + if (strstr(str, SEARCHMSG) != NULL) 13 + (*(int *)data)++; 14 + } 11 15 12 16 void serial_test_trace_printk(void) 13 17 { 14 18 struct trace_printk_lskel__bss *bss; 15 - int err = 0, iter = 0, found = 0; 16 19 struct trace_printk_lskel *skel; 17 - char *buf = NULL; 18 - FILE *fp = NULL; 19 - size_t buflen; 20 + int err = 0, found = 0; 20 21 21 22 skel = trace_printk_lskel__open(); 22 23 if (!ASSERT_OK_PTR(skel, "trace_printk__open")) ··· 36 35 if (!ASSERT_OK(err, "trace_printk__attach")) 37 36 goto cleanup; 38 37 39 - if (access(TRACEFS_PIPE, F_OK) == 0) 40 - fp = fopen(TRACEFS_PIPE, "r"); 41 - else 42 - fp = fopen(DEBUGFS_PIPE, "r"); 43 - if (!ASSERT_OK_PTR(fp, "fopen(TRACE_PIPE)")) 44 - goto cleanup; 45 - 46 - /* We do not want to wait forever if this test fails... */ 47 - fcntl(fileno(fp), F_SETFL, O_NONBLOCK); 48 - 49 38 /* wait for tracepoint to trigger */ 50 39 usleep(1); 51 40 trace_printk_lskel__detach(skel); ··· 47 56 goto cleanup; 48 57 49 58 /* verify our search string is in the trace buffer */ 50 - while (getline(&buf, &buflen, fp) >= 0 || errno == EAGAIN) { 51 - if (strstr(buf, SEARCHMSG) != NULL) 52 - found++; 53 - if (found == bss->trace_printk_ran) 54 - break; 55 - if (++iter > 1000) 56 - break; 57 - } 59 + ASSERT_OK(read_trace_pipe_iter(trace_pipe_cb, &found, 1000), 60 + "read_trace_pipe_iter"); 58 61 59 62 if (!ASSERT_EQ(found, bss->trace_printk_ran, "found")) 60 63 goto cleanup; 61 64 62 65 cleanup: 63 66 trace_printk_lskel__destroy(skel); 64 - free(buf); 65 - if (fp) 66 - fclose(fp); 67 67 }
+9 -27
tools/testing/selftests/bpf/prog_tests/trace_vprintk.c
··· 5 5 6 6 #include "trace_vprintk.lskel.h" 7 7 8 - #define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe" 9 - #define DEBUGFS_PIPE "/sys/kernel/debug/tracing/trace_pipe" 10 8 #define SEARCHMSG "1,2,3,4,5,6,7,8,9,10" 9 + 10 + static void trace_pipe_cb(const char *str, void *data) 11 + { 12 + if (strstr(str, SEARCHMSG) != NULL) 13 + (*(int *)data)++; 14 + } 11 15 12 16 void serial_test_trace_vprintk(void) 13 17 { 14 18 struct trace_vprintk_lskel__bss *bss; 15 - int err = 0, iter = 0, found = 0; 16 19 struct trace_vprintk_lskel *skel; 17 - char *buf = NULL; 18 - FILE *fp = NULL; 19 - size_t buflen; 20 + int err = 0, found = 0; 20 21 21 22 skel = trace_vprintk_lskel__open_and_load(); 22 23 if (!ASSERT_OK_PTR(skel, "trace_vprintk__open_and_load")) ··· 28 27 err = trace_vprintk_lskel__attach(skel); 29 28 if (!ASSERT_OK(err, "trace_vprintk__attach")) 30 29 goto cleanup; 31 - 32 - if (access(TRACEFS_PIPE, F_OK) == 0) 33 - fp = fopen(TRACEFS_PIPE, "r"); 34 - else 35 - fp = fopen(DEBUGFS_PIPE, "r"); 36 - if (!ASSERT_OK_PTR(fp, "fopen(TRACE_PIPE)")) 37 - goto cleanup; 38 - 39 - /* We do not want to wait forever if this test fails... */ 40 - fcntl(fileno(fp), F_SETFL, O_NONBLOCK); 41 30 42 31 /* wait for tracepoint to trigger */ 43 32 usleep(1); ··· 40 49 goto cleanup; 41 50 42 51 /* verify our search string is in the trace buffer */ 43 - while (getline(&buf, &buflen, fp) >= 0 || errno == EAGAIN) { 44 - if (strstr(buf, SEARCHMSG) != NULL) 45 - found++; 46 - if (found == bss->trace_vprintk_ran) 47 - break; 48 - if (++iter > 1000) 49 - break; 50 - } 52 + ASSERT_OK(read_trace_pipe_iter(trace_pipe_cb, &found, 1000), 53 + "read_trace_pipe_iter"); 51 54 52 55 if (!ASSERT_EQ(found, bss->trace_vprintk_ran, "found")) 53 56 goto cleanup; ··· 51 66 52 67 cleanup: 53 68 trace_vprintk_lskel__destroy(skel); 54 - free(buf); 55 - if (fp) 56 - fclose(fp); 57 69 }
+40 -23
tools/testing/selftests/bpf/trace_helpers.c
··· 233 233 return err; 234 234 } 235 235 236 - void read_trace_pipe(void) 237 - { 238 - int trace_fd; 239 - 240 - if (access(TRACEFS_PIPE, F_OK) == 0) 241 - trace_fd = open(TRACEFS_PIPE, O_RDONLY, 0); 242 - else 243 - trace_fd = open(DEBUGFS_PIPE, O_RDONLY, 0); 244 - if (trace_fd < 0) 245 - return; 246 - 247 - while (1) { 248 - static char buf[4096]; 249 - ssize_t sz; 250 - 251 - sz = read(trace_fd, buf, sizeof(buf) - 1); 252 - if (sz > 0) { 253 - buf[sz] = 0; 254 - puts(buf); 255 - } 256 - } 257 - } 258 - 259 236 ssize_t get_uprobe_offset(const void *addr) 260 237 { 261 238 size_t start, end, base; ··· 389 412 elf_end(elf); 390 413 close(fd); 391 414 return err; 415 + } 416 + 417 + int read_trace_pipe_iter(void (*cb)(const char *str, void *data), void *data, int iter) 418 + { 419 + size_t buflen, n; 420 + char *buf = NULL; 421 + FILE *fp = NULL; 422 + 423 + if (access(TRACEFS_PIPE, F_OK) == 0) 424 + fp = fopen(TRACEFS_PIPE, "r"); 425 + else 426 + fp = fopen(DEBUGFS_PIPE, "r"); 427 + if (!fp) 428 + return -1; 429 + 430 + /* We do not want to wait forever when iter is specified. */ 431 + if (iter) 432 + fcntl(fileno(fp), F_SETFL, O_NONBLOCK); 433 + 434 + while ((n = getline(&buf, &buflen, fp) >= 0) || errno == EAGAIN) { 435 + if (n > 0) 436 + cb(buf, data); 437 + if (iter && !(--iter)) 438 + break; 439 + } 440 + 441 + free(buf); 442 + if (fp) 443 + fclose(fp); 444 + return 0; 445 + } 446 + 447 + static void trace_pipe_cb(const char *str, void *data) 448 + { 449 + printf("%s", str); 450 + } 451 + 452 + void read_trace_pipe(void) 453 + { 454 + read_trace_pipe_iter(trace_pipe_cb, NULL, 0); 392 455 }
+2
tools/testing/selftests/bpf/trace_helpers.h
··· 33 33 int kallsyms_find(const char *sym, unsigned long long *addr); 34 34 35 35 void read_trace_pipe(void); 36 + int read_trace_pipe_iter(void (*cb)(const char *str, void *data), 37 + void *data, int iter); 36 38 37 39 ssize_t get_uprobe_offset(const void *addr); 38 40 ssize_t get_rel_offset(uintptr_t addr);