File Index
Files and directories
Sign in
FILE

map_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/ring-buffer/map_test.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Ring-buffer memory mapping tests
  4 *
  5 * Copyright (c) 2024 Vincent Donnefort <vdonnefort@google.com>
  6 */
  7#include <fcntl.h>
  8#include <sched.h>
  9#include <stdbool.h>
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include <unistd.h>
 13
 14#include <linux/trace_mmap.h>
 15
 16#include <sys/mman.h>
 17#include <sys/ioctl.h>
 18
 19#include "../user_events/user_events_selftests.h" /* share tracefs setup */
 20#include "kselftest_harness.h"
 21
 22#define TRACEFS_ROOT "/sys/kernel/tracing"
 23
 24static int __tracefs_write(const char *path, const char *value)
 25{
 26	int fd, ret;
 27
 28	fd = open(path, O_WRONLY | O_TRUNC);
 29	if (fd < 0)
 30		return fd;
 31
 32	ret = write(fd, value, strlen(value));
 33
 34	close(fd);
 35
 36	return ret == -1 ? -errno : 0;
 37}
 38
 39static int __tracefs_write_int(const char *path, int value)
 40{
 41	char *str;
 42	int ret;
 43
 44	if (asprintf(&str, "%d", value) < 0)
 45		return -1;
 46
 47	ret = __tracefs_write(path, str);
 48
 49	free(str);
 50
 51	return ret;
 52}
 53
 54#define tracefs_write_int(path, value) \
 55	ASSERT_EQ(__tracefs_write_int((path), (value)), 0)
 56
 57#define tracefs_write(path, value) \
 58	ASSERT_EQ(__tracefs_write((path), (value)), 0)
 59
 60static int tracefs_reset(void)
 61{
 62	if (__tracefs_write_int(TRACEFS_ROOT"/tracing_on", 0))
 63		return -1;
 64	if (__tracefs_write(TRACEFS_ROOT"/trace", ""))
 65		return -1;
 66	if (__tracefs_write(TRACEFS_ROOT"/set_event", ""))
 67		return -1;
 68	if (__tracefs_write(TRACEFS_ROOT"/current_tracer", "nop"))
 69		return -1;
 70
 71	return 0;
 72}
 73
 74struct tracefs_cpu_map_desc {
 75	struct trace_buffer_meta	*meta;
 76	int				cpu_fd;
 77};
 78
 79int tracefs_cpu_map(struct tracefs_cpu_map_desc *desc, int cpu)
 80{
 81	int page_size = getpagesize();
 82	char *cpu_path;
 83	void *map;
 84
 85	if (asprintf(&cpu_path,
 86		     TRACEFS_ROOT"/per_cpu/cpu%d/trace_pipe_raw",
 87		     cpu) < 0)
 88		return -ENOMEM;
 89
 90	desc->cpu_fd = open(cpu_path, O_RDONLY | O_NONBLOCK);
 91	free(cpu_path);
 92	if (desc->cpu_fd < 0)
 93		return -ENODEV;
 94
 95again:
 96	map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, desc->cpu_fd, 0);
 97	if (map == MAP_FAILED)
 98		return -errno;
 99
100	desc->meta = (struct trace_buffer_meta *)map;
101
102	/* the meta-page is bigger than the original mapping */
103	if (page_size < desc->meta->meta_struct_len) {
104		int meta_page_size = desc->meta->meta_page_size;
105
106		munmap(desc->meta, page_size);
107		page_size = meta_page_size;
108		goto again;
109	}
110
111	return 0;
112}
113
114void tracefs_cpu_unmap(struct tracefs_cpu_map_desc *desc)
115{
116	munmap(desc->meta, desc->meta->meta_page_size);
117	close(desc->cpu_fd);
118}
119
120FIXTURE(map) {
121	struct tracefs_cpu_map_desc	map_desc;
122	bool				umount;
123};
124
125FIXTURE_VARIANT(map) {
126	int	subbuf_size;
127};
128
129FIXTURE_VARIANT_ADD(map, subbuf_size_4k) {
130	.subbuf_size = 4,
131};
132
133FIXTURE_VARIANT_ADD(map, subbuf_size_8k) {
134	.subbuf_size = 8,
135};
136
137FIXTURE_SETUP(map)
138{
139	int cpu = sched_getcpu();
140	cpu_set_t cpu_mask;
141	bool fail, umount;
142	char *message;
143
144	if (getuid() != 0)
145		SKIP(return, "Skipping: %s", "Please run the test as root");
146
147	if (!tracefs_enabled(&message, &fail, &umount)) {
148		if (fail) {
149			TH_LOG("Tracefs setup failed: %s", message);
150			ASSERT_FALSE(fail);
151		}
152		SKIP(return, "Skipping: %s", message);
153	}
154
155	self->umount = umount;
156
157	ASSERT_GE(cpu, 0);
158
159	ASSERT_EQ(tracefs_reset(), 0);
160
161	tracefs_write_int(TRACEFS_ROOT"/buffer_subbuf_size_kb", variant->subbuf_size);
162
163	ASSERT_EQ(tracefs_cpu_map(&self->map_desc, cpu), 0);
164
165	/*
166	 * Ensure generated events will be found on this very same ring-buffer.
167	 */
168	CPU_ZERO(&cpu_mask);
169	CPU_SET(cpu, &cpu_mask);
170	ASSERT_EQ(sched_setaffinity(0, sizeof(cpu_mask), &cpu_mask), 0);
171}
172
173FIXTURE_TEARDOWN(map)
174{
175	tracefs_reset();
176
177	if (self->umount)
178		tracefs_unmount();
179
180	tracefs_cpu_unmap(&self->map_desc);
181}
182
183TEST_F(map, meta_page_check)
184{
185	struct tracefs_cpu_map_desc *desc = &self->map_desc;
186	int cnt = 0;
187
188	ASSERT_EQ(desc->meta->entries, 0);
189	ASSERT_EQ(desc->meta->overrun, 0);
190	ASSERT_EQ(desc->meta->read, 0);
191
192	ASSERT_EQ(desc->meta->reader.id, 0);
193	ASSERT_EQ(desc->meta->reader.read, 0);
194
195	ASSERT_EQ(ioctl(desc->cpu_fd, TRACE_MMAP_IOCTL_GET_READER), 0);
196	ASSERT_EQ(desc->meta->reader.id, 0);
197
198	tracefs_write_int(TRACEFS_ROOT"/tracing_on", 1);
199	for (int i = 0; i < 16; i++)
200		tracefs_write_int(TRACEFS_ROOT"/trace_marker", i);
201again:
202	ASSERT_EQ(ioctl(desc->cpu_fd, TRACE_MMAP_IOCTL_GET_READER), 0);
203
204	ASSERT_EQ(desc->meta->entries, 16);
205	ASSERT_EQ(desc->meta->overrun, 0);
206	ASSERT_EQ(desc->meta->read, 16);
207
208	ASSERT_EQ(desc->meta->reader.id, 1);
209
210	if (!(cnt++))
211		goto again;
212}
213
214TEST_F(map, data_mmap)
215{
216	struct tracefs_cpu_map_desc *desc = &self->map_desc;
217	unsigned long meta_len, data_len;
218	void *data;
219
220	meta_len = desc->meta->meta_page_size;
221	data_len = desc->meta->subbuf_size * desc->meta->nr_subbufs;
222
223	/* Map all the available subbufs */
224	data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
225		    desc->cpu_fd, meta_len);
226	ASSERT_NE(data, MAP_FAILED);
227	munmap(data, data_len);
228
229	/* Map all the available subbufs - 1 */
230	data_len -= desc->meta->subbuf_size;
231	data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
232		    desc->cpu_fd, meta_len);
233	ASSERT_NE(data, MAP_FAILED);
234	munmap(data, data_len);
235
236	/* Offset within ring-buffer bounds, mapping size overflow */
237	meta_len += desc->meta->subbuf_size * 2;
238	data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
239		    desc->cpu_fd, meta_len);
240	ASSERT_EQ(data, MAP_FAILED);
241
242	/* Offset outside ring-buffer bounds */
243	data_len = desc->meta->subbuf_size * desc->meta->nr_subbufs;
244	data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
245		    desc->cpu_fd, data_len + (desc->meta->subbuf_size * 2));
246	ASSERT_EQ(data, MAP_FAILED);
247
248	/* Verify meta-page padding */
249	if (desc->meta->meta_page_size > getpagesize()) {
250		data_len = desc->meta->meta_page_size;
251		data = mmap(NULL, data_len,
252			    PROT_READ, MAP_SHARED, desc->cpu_fd, 0);
253		ASSERT_NE(data, MAP_FAILED);
254
255		for (int i = desc->meta->meta_struct_len;
256		     i < desc->meta->meta_page_size; i += sizeof(int))
257			ASSERT_EQ(*(int *)(data + i), 0);
258
259		munmap(data, data_len);
260	}
261}
262
263FIXTURE(snapshot) {
264	bool	umount;
265};
266
267FIXTURE_SETUP(snapshot)
268{
269	bool fail, umount;
270	struct stat sb;
271	char *message;
272
273	if (getuid() != 0)
274		SKIP(return, "Skipping: %s", "Please run the test as root");
275
276	if (stat(TRACEFS_ROOT"/snapshot", &sb))
277		SKIP(return, "Skipping: %s", "snapshot not available");
278
279	if (!tracefs_enabled(&message, &fail, &umount)) {
280		if (fail) {
281			TH_LOG("Tracefs setup failed: %s", message);
282			ASSERT_FALSE(fail);
283		}
284		SKIP(return, "Skipping: %s", message);
285	}
286
287	self->umount = umount;
288}
289
290FIXTURE_TEARDOWN(snapshot)
291{
292	__tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
293			"!snapshot");
294	tracefs_reset();
295
296	if (self->umount)
297		tracefs_unmount();
298}
299
300TEST_F(snapshot, excludes_map)
301{
302	struct tracefs_cpu_map_desc map_desc;
303	int cpu = sched_getcpu();
304
305	ASSERT_GE(cpu, 0);
306	tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
307		      "snapshot");
308	ASSERT_EQ(tracefs_cpu_map(&map_desc, cpu), -EBUSY);
309}
310
311TEST_F(snapshot, excluded_by_map)
312{
313	struct tracefs_cpu_map_desc map_desc;
314	int cpu = sched_getcpu();
315
316	ASSERT_EQ(tracefs_cpu_map(&map_desc, cpu), 0);
317
318	ASSERT_EQ(__tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
319				  "snapshot"), -EBUSY);
320	ASSERT_EQ(__tracefs_write(TRACEFS_ROOT"/snapshot",
321				  "1"), -EBUSY);
322}
323
324TEST_HARNESS_MAIN
~/ Read-only file preview.