map_test.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. #include <linux/trace_mmap.h>
  14. #include <sys/mman.h>
  15. #include <sys/ioctl.h>
  16. #include "../user_events/user_events_selftests.h" /* share tracefs setup */
  17. #include "../kselftest_harness.h"
  18. #define TRACEFS_ROOT "/sys/kernel/tracing"
  19. static int __tracefs_write(const char *path, const char *value)
  20. {
  21. int fd, ret;
  22. fd = open(path, O_WRONLY | O_TRUNC);
  23. if (fd < 0)
  24. return fd;
  25. ret = write(fd, value, strlen(value));
  26. close(fd);
  27. return ret == -1 ? -errno : 0;
  28. }
  29. static int __tracefs_write_int(const char *path, int value)
  30. {
  31. char *str;
  32. int ret;
  33. if (asprintf(&str, "%d", value) < 0)
  34. return -1;
  35. ret = __tracefs_write(path, str);
  36. free(str);
  37. return ret;
  38. }
  39. #define tracefs_write_int(path, value) \
  40. ASSERT_EQ(__tracefs_write_int((path), (value)), 0)
  41. #define tracefs_write(path, value) \
  42. ASSERT_EQ(__tracefs_write((path), (value)), 0)
  43. static int tracefs_reset(void)
  44. {
  45. if (__tracefs_write_int(TRACEFS_ROOT"/tracing_on", 0))
  46. return -1;
  47. if (__tracefs_write(TRACEFS_ROOT"/trace", ""))
  48. return -1;
  49. if (__tracefs_write(TRACEFS_ROOT"/set_event", ""))
  50. return -1;
  51. if (__tracefs_write(TRACEFS_ROOT"/current_tracer", "nop"))
  52. return -1;
  53. return 0;
  54. }
  55. struct tracefs_cpu_map_desc {
  56. struct trace_buffer_meta *meta;
  57. int cpu_fd;
  58. };
  59. int tracefs_cpu_map(struct tracefs_cpu_map_desc *desc, int cpu)
  60. {
  61. int page_size = getpagesize();
  62. char *cpu_path;
  63. void *map;
  64. if (asprintf(&cpu_path,
  65. TRACEFS_ROOT"/per_cpu/cpu%d/trace_pipe_raw",
  66. cpu) < 0)
  67. return -ENOMEM;
  68. desc->cpu_fd = open(cpu_path, O_RDONLY | O_NONBLOCK);
  69. free(cpu_path);
  70. if (desc->cpu_fd < 0)
  71. return -ENODEV;
  72. again:
  73. map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, desc->cpu_fd, 0);
  74. if (map == MAP_FAILED)
  75. return -errno;
  76. desc->meta = (struct trace_buffer_meta *)map;
  77. /* the meta-page is bigger than the original mapping */
  78. if (page_size < desc->meta->meta_struct_len) {
  79. int meta_page_size = desc->meta->meta_page_size;
  80. munmap(desc->meta, page_size);
  81. page_size = meta_page_size;
  82. goto again;
  83. }
  84. return 0;
  85. }
  86. void tracefs_cpu_unmap(struct tracefs_cpu_map_desc *desc)
  87. {
  88. munmap(desc->meta, desc->meta->meta_page_size);
  89. close(desc->cpu_fd);
  90. }
  91. FIXTURE(map) {
  92. struct tracefs_cpu_map_desc map_desc;
  93. bool umount;
  94. };
  95. FIXTURE_VARIANT(map) {
  96. int subbuf_size;
  97. };
  98. FIXTURE_VARIANT_ADD(map, subbuf_size_4k) {
  99. .subbuf_size = 4,
  100. };
  101. FIXTURE_VARIANT_ADD(map, subbuf_size_8k) {
  102. .subbuf_size = 8,
  103. };
  104. FIXTURE_SETUP(map)
  105. {
  106. int cpu = sched_getcpu();
  107. cpu_set_t cpu_mask;
  108. bool fail, umount;
  109. char *message;
  110. if (getuid() != 0)
  111. SKIP(return, "Skipping: %s", "Please run the test as root");
  112. if (!tracefs_enabled(&message, &fail, &umount)) {
  113. if (fail) {
  114. TH_LOG("Tracefs setup failed: %s", message);
  115. ASSERT_FALSE(fail);
  116. }
  117. SKIP(return, "Skipping: %s", message);
  118. }
  119. self->umount = umount;
  120. ASSERT_GE(cpu, 0);
  121. ASSERT_EQ(tracefs_reset(), 0);
  122. tracefs_write_int(TRACEFS_ROOT"/buffer_subbuf_size_kb", variant->subbuf_size);
  123. ASSERT_EQ(tracefs_cpu_map(&self->map_desc, cpu), 0);
  124. /*
  125. * Ensure generated events will be found on this very same ring-buffer.
  126. */
  127. CPU_ZERO(&cpu_mask);
  128. CPU_SET(cpu, &cpu_mask);
  129. ASSERT_EQ(sched_setaffinity(0, sizeof(cpu_mask), &cpu_mask), 0);
  130. }
  131. FIXTURE_TEARDOWN(map)
  132. {
  133. tracefs_reset();
  134. if (self->umount)
  135. tracefs_unmount();
  136. tracefs_cpu_unmap(&self->map_desc);
  137. }
  138. TEST_F(map, meta_page_check)
  139. {
  140. struct tracefs_cpu_map_desc *desc = &self->map_desc;
  141. int cnt = 0;
  142. ASSERT_EQ(desc->meta->entries, 0);
  143. ASSERT_EQ(desc->meta->overrun, 0);
  144. ASSERT_EQ(desc->meta->read, 0);
  145. ASSERT_EQ(desc->meta->reader.id, 0);
  146. ASSERT_EQ(desc->meta->reader.read, 0);
  147. ASSERT_EQ(ioctl(desc->cpu_fd, TRACE_MMAP_IOCTL_GET_READER), 0);
  148. ASSERT_EQ(desc->meta->reader.id, 0);
  149. tracefs_write_int(TRACEFS_ROOT"/tracing_on", 1);
  150. for (int i = 0; i < 16; i++)
  151. tracefs_write_int(TRACEFS_ROOT"/trace_marker", i);
  152. again:
  153. ASSERT_EQ(ioctl(desc->cpu_fd, TRACE_MMAP_IOCTL_GET_READER), 0);
  154. ASSERT_EQ(desc->meta->entries, 16);
  155. ASSERT_EQ(desc->meta->overrun, 0);
  156. ASSERT_EQ(desc->meta->read, 16);
  157. ASSERT_EQ(desc->meta->reader.id, 1);
  158. if (!(cnt++))
  159. goto again;
  160. }
  161. TEST_F(map, data_mmap)
  162. {
  163. struct tracefs_cpu_map_desc *desc = &self->map_desc;
  164. unsigned long meta_len, data_len;
  165. void *data;
  166. meta_len = desc->meta->meta_page_size;
  167. data_len = desc->meta->subbuf_size * desc->meta->nr_subbufs;
  168. /* Map all the available subbufs */
  169. data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
  170. desc->cpu_fd, meta_len);
  171. ASSERT_NE(data, MAP_FAILED);
  172. munmap(data, data_len);
  173. /* Map all the available subbufs - 1 */
  174. data_len -= desc->meta->subbuf_size;
  175. data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
  176. desc->cpu_fd, meta_len);
  177. ASSERT_NE(data, MAP_FAILED);
  178. munmap(data, data_len);
  179. /* Overflow the available subbufs by 1 */
  180. meta_len += desc->meta->subbuf_size * 2;
  181. data = mmap(NULL, data_len, PROT_READ, MAP_SHARED,
  182. desc->cpu_fd, meta_len);
  183. ASSERT_EQ(data, MAP_FAILED);
  184. /* Verify meta-page padding */
  185. if (desc->meta->meta_page_size > getpagesize()) {
  186. data_len = desc->meta->meta_page_size;
  187. data = mmap(NULL, data_len,
  188. PROT_READ, MAP_SHARED, desc->cpu_fd, 0);
  189. ASSERT_NE(data, MAP_FAILED);
  190. for (int i = desc->meta->meta_struct_len;
  191. i < desc->meta->meta_page_size; i += sizeof(int))
  192. ASSERT_EQ(*(int *)(data + i), 0);
  193. munmap(data, data_len);
  194. }
  195. }
  196. FIXTURE(snapshot) {
  197. bool umount;
  198. };
  199. FIXTURE_SETUP(snapshot)
  200. {
  201. bool fail, umount;
  202. struct stat sb;
  203. char *message;
  204. if (getuid() != 0)
  205. SKIP(return, "Skipping: %s", "Please run the test as root");
  206. if (stat(TRACEFS_ROOT"/snapshot", &sb))
  207. SKIP(return, "Skipping: %s", "snapshot not available");
  208. if (!tracefs_enabled(&message, &fail, &umount)) {
  209. if (fail) {
  210. TH_LOG("Tracefs setup failed: %s", message);
  211. ASSERT_FALSE(fail);
  212. }
  213. SKIP(return, "Skipping: %s", message);
  214. }
  215. self->umount = umount;
  216. }
  217. FIXTURE_TEARDOWN(snapshot)
  218. {
  219. __tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
  220. "!snapshot");
  221. tracefs_reset();
  222. if (self->umount)
  223. tracefs_unmount();
  224. }
  225. TEST_F(snapshot, excludes_map)
  226. {
  227. struct tracefs_cpu_map_desc map_desc;
  228. int cpu = sched_getcpu();
  229. ASSERT_GE(cpu, 0);
  230. tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
  231. "snapshot");
  232. ASSERT_EQ(tracefs_cpu_map(&map_desc, cpu), -EBUSY);
  233. }
  234. TEST_F(snapshot, excluded_by_map)
  235. {
  236. struct tracefs_cpu_map_desc map_desc;
  237. int cpu = sched_getcpu();
  238. ASSERT_EQ(tracefs_cpu_map(&map_desc, cpu), 0);
  239. ASSERT_EQ(__tracefs_write(TRACEFS_ROOT"/events/sched/sched_switch/trigger",
  240. "snapshot"), -EBUSY);
  241. ASSERT_EQ(__tracefs_write(TRACEFS_ROOT"/snapshot",
  242. "1"), -EBUSY);
  243. }
  244. TEST_HARNESS_MAIN