| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Ring-buffer memory mapping tests
- *
- * Copyright (c) 2024 Vincent Donnefort <vdonnefort@google.com>
- */
- #include <fcntl.h>
- #include <sched.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <linux/trace_mmap.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- #include "../user_events/user_events_selftests.h" /* share tracefs setup */
- #include "../kselftest_harness.h"
- #define TRACEFS_ROOT "/sys/kernel/tracing"
- static int __tracefs_write(const char *path, const char *value)
- {
- int fd, ret;
- fd = open(path, O_WRONLY | O_TRUNC);
- if (fd < 0)
- return fd;
- ret = write(fd, value, strlen(value));
- close(fd);
- return ret == -1 ? -errno : 0;
- }
- static int __tracefs_write_int(const char *path, int value)
- {
- char *str;
- int ret;
- if (asprintf(&str, "%d", value) < 0)
- return -1;
- ret = __tracefs_write(path, str);
- free(str);
- return ret;
- }
- #define tracefs_write_int(path, value) \
- ASSERT_EQ(__tracefs_write_int((path), (value)), 0)
- #define tracefs_write(path, value) \
- ASSERT_EQ(__tracefs_write((path), (value)), 0)
- static int tracefs_reset(void)
- {
- if (__tracefs_write_int(TRACEFS_ROOT"/tracing_on", 0))
- return -1;
- if (__tracefs_write(TRACEFS_ROOT"/trace", ""))
- return -1;
- if (__tracefs_write(TRACEFS_ROOT"/set_event", ""))
- return -1;
- if (__tracefs_write(TRACEFS_ROOT"/current_tracer", "nop"))
- return -1;
- return 0;
- }
- struct tracefs_cpu_map_desc {
- struct trace_buffer_meta *meta;
- int cpu_fd;
- };
- int tracefs_cpu_map(struct tracefs_cpu_map_desc *desc, int cpu)
- {
- int page_size = getpagesize();
- char *cpu_path;
- void *map;
- if (asprintf(&cpu_path,
- TRACEFS_ROOT"/per_cpu/cpu%d/trace_pipe_raw",
- cpu) < 0)
- return -ENOMEM;
- desc->cpu_fd = open(cpu_path, O_RDONLY | O_NONBLOCK);
- free(cpu_path);
- if (desc->cpu_fd < 0)
- return -ENODEV;
- again:
- map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, desc->cpu_fd, 0);
- if (map == MAP_FAILED)
- return -errno;
- desc->meta = (struct trace_buffer_meta *)map;
- /* the meta-page is bigger than the original mapping */
- if (page_size < desc->meta->meta_struct_len) {
- int meta_page_size = desc->meta->meta_page_size;
- munmap(desc->meta, page_size);
- page_size = meta_page_size;
- goto again;
- }
- return 0;
- }
- void tracefs_cpu_unmap(struct tracefs_cpu_map_desc *desc)
- {
- munmap(desc->meta, desc->meta->meta_page_size);
- close(desc->cpu_fd);
- }
- FIXTURE(map) {
- struct tracefs_cpu_map_desc map_desc;
- bool umount;
- };
- FIXTURE_VARIANT(map) {
- int subbuf_size;
- };
- FIXTURE_VARIANT_ADD(map, subbuf_size_4k) {
- .subbuf_size = 4,
- };
- FIXTURE_VARIANT_ADD(map, subbuf_size_8k) {
- .subbuf_size = 8,
- };
- FIXTURE_SETUP(map)
- {
- int cpu = sched_getcpu();
- cpu_set_t cpu_mask;
- bool fail, umount;
- char *message;
- if (getuid() != 0)
- SKIP(return, "Skipping: %s", "Please run the test as root");
- if (!tracefs_enabled(&message, &fail, &umount)) {
- if (fail) {
- TH_LOG("Tracefs setup failed: %s", message);
- ASSERT_FALSE(fail);
- }
- SKIP(return, "Skipping: %s", message);
- }
- self->umount = umount;
- ASSERT_GE(cpu, 0);
- ASSERT_EQ(tracefs_reset(), 0);
- tracefs_write_int(TRACEFS_ROOT"/buffer_subbuf_size_kb", variant->subbuf_size);
- ASSERT_EQ(tracefs_cpu_map(&self->map_desc, cpu), 0);
- /*
- * Ensure generated events will be found on this very same ring-buffer.
- */
- CPU_ZERO(&cpu_mask);
- CPU_SET(cpu, &cpu_mask);
- ASSERT_EQ(sched_setaffinity(0, sizeof(cpu_mask), &cpu_mask), 0);
- }
- FIXTURE_TEARDOWN(map)
- {
- tracefs_reset();
- if (self->umount)
- tracefs_unmount();
- tracefs_cpu_unmap(&self->map_desc);
- }
- TEST_F(map, meta_page_check)
- {
- struct tracefs_cpu_map_desc *desc = &self->map_desc;
- int cnt = 0;
- ASSERT_EQ(desc->meta->entries, 0);
- ASSERT_EQ(desc->meta->overrun, 0);
- ASSERT_EQ(desc->meta->read, 0);
- ASSERT_EQ(desc->meta->reader.id, 0);
- ASSERT_EQ(desc->meta->reader.read, 0);
- ASSERT_EQ(ioctl(desc->cpu_fd, TRACE_MMAP_IOCTL_GET_READER), 0);
- ASSERT_EQ(desc->meta->reader.id, 0);
- tracefs_write_int(TRACEFS_ROOT"/tracing_on", 1);
- for (int i = 0; i < 16; i++)
- tracefs_write_int(TRACEFS_ROOT"/trace_marker", i);
- again:
- ASSERT_EQ(ioctl(desc->cpu_fd, TRACE_MMAP_IOCTL_GET_READER), 0);
- ASSERT_EQ(desc->meta->entries, 16);
- ASSERT_EQ(desc->meta->overrun, 0);
- ASSERT_EQ(desc->meta->read, 16);
- ASSERT_EQ(desc->meta->reader.id, 1);
- if (!(cnt++))
- goto again;
- }
- TEST_F(map, data_mmap)
- {
- struct tracefs_cpu_map_desc *desc = &self->map_desc;
- unsigned long meta_len, data_len;
- void *data;
- meta_len = desc->meta->meta_page_size;
- data_len = desc->meta->subbuf_size * desc->meta->nr_subbufs;
- /* Map all the available subbufs */
- data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
- desc->cpu_fd, meta_len);
- ASSERT_NE(data, MAP_FAILED);
- munmap(data, data_len);
- /* Map all the available subbufs - 1 */
- data_len -= desc->meta->subbuf_size;
- data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
- desc->cpu_fd, meta_len);
- ASSERT_NE(data, MAP_FAILED);
- munmap(data, data_len);
- /* Overflow the available subbufs by 1 */
- meta_len += desc->meta->subbuf_size * 2;
- data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
- desc->cpu_fd, meta_len);
- ASSERT_EQ(data, MAP_FAILED);
- /* Verify meta-page padding */
- if (desc->meta->meta_page_size > getpagesize()) {
- data_len = desc->meta->meta_page_size;
- data = mmap(NULL, data_len,
- PROT_READ, MAP_SHARED, desc->cpu_fd, 0);
- ASSERT_NE(data, MAP_FAILED);
- for (int i = desc->meta->meta_struct_len;
- i < desc->meta->meta_page_size; i += sizeof(int))
- ASSERT_EQ(*(int *)(data + i), 0);
- munmap(data, data_len);
- }
- }
- FIXTURE(snapshot) {
- bool umount;
- };
- FIXTURE_SETUP(snapshot)
- {
- bool fail, umount;
- struct stat sb;
- char *message;
- if (getuid() != 0)
- SKIP(return, "Skipping: %s", "Please run the test as root");
- if (stat(TRACEFS_ROOT"/snapshot", &sb))
- SKIP(return, "Skipping: %s", "snapshot not available");
- if (!tracefs_enabled(&message, &fail, &umount)) {
- if (fail) {
- TH_LOG("Tracefs setup failed: %s", message);
- ASSERT_FALSE(fail);
- }
- SKIP(return, "Skipping: %s", message);
- }
- self->umount = umount;
- }
- FIXTURE_TEARDOWN(snapshot)
- {
- __tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
- "!snapshot");
- tracefs_reset();
- if (self->umount)
- tracefs_unmount();
- }
- TEST_F(snapshot, excludes_map)
- {
- struct tracefs_cpu_map_desc map_desc;
- int cpu = sched_getcpu();
- ASSERT_GE(cpu, 0);
- tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
- "snapshot");
- ASSERT_EQ(tracefs_cpu_map(&map_desc, cpu), -EBUSY);
- }
- TEST_F(snapshot, excluded_by_map)
- {
- struct tracefs_cpu_map_desc map_desc;
- int cpu = sched_getcpu();
- ASSERT_EQ(tracefs_cpu_map(&map_desc, cpu), 0);
- ASSERT_EQ(__tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
- "snapshot"), -EBUSY);
- ASSERT_EQ(__tracefs_write(TRACEFS_ROOT"/snapshot",
- "1"), -EBUSY);
- }
- TEST_HARNESS_MAIN
|