uffd-stress.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Stress userfaultfd syscall.
  4. *
  5. * Copyright (C) 2015 Red Hat, Inc.
  6. *
  7. * This test allocates two virtual areas and bounces the physical
  8. * memory across the two virtual areas (from area_src to area_dst)
  9. * using userfaultfd.
  10. *
  11. * There are three threads running per CPU:
  12. *
  13. * 1) one per-CPU thread takes a per-page pthread_mutex in a random
  14. * page of the area_dst (while the physical page may still be in
  15. * area_src), and increments a per-page counter in the same page,
  16. * and checks its value against a verification region.
  17. *
  18. * 2) another per-CPU thread handles the userfaults generated by
  19. * thread 1 above. userfaultfd blocking reads or poll() modes are
  20. * exercised interleaved.
  21. *
  22. * 3) one last per-CPU thread transfers the memory in the background
  23. * at maximum bandwidth (if not already transferred by thread
  24. * 2). Each cpu thread takes cares of transferring a portion of the
  25. * area.
  26. *
  27. * When all threads of type 3 completed the transfer, one bounce is
  28. * complete. area_src and area_dst are then swapped. All threads are
  29. * respawned and so the bounce is immediately restarted in the
  30. * opposite direction.
  31. *
  32. * per-CPU threads 1 by triggering userfaults inside
  33. * pthread_mutex_lock will also verify the atomicity of the memory
  34. * transfer (UFFDIO_COPY).
  35. */
  36. #include "uffd-common.h"
  37. uint64_t features;
  38. #ifdef __NR_userfaultfd
  39. #define BOUNCE_RANDOM (1<<0)
  40. #define BOUNCE_RACINGFAULTS (1<<1)
  41. #define BOUNCE_VERIFY (1<<2)
  42. #define BOUNCE_POLL (1<<3)
  43. static int bounces;
  44. /* exercise the test_uffdio_*_eexist every ALARM_INTERVAL_SECS */
  45. #define ALARM_INTERVAL_SECS 10
  46. static char *zeropage;
  47. pthread_attr_t attr;
  48. #define swap(a, b) \
  49. do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
  50. const char *examples =
  51. "# Run anonymous memory test on 100MiB region with 99999 bounces:\n"
  52. "./uffd-stress anon 100 99999\n\n"
  53. "# Run share memory test on 1GiB region with 99 bounces:\n"
  54. "./uffd-stress shmem 1000 99\n\n"
  55. "# Run hugetlb memory test on 256MiB region with 50 bounces:\n"
  56. "./uffd-stress hugetlb 256 50\n\n"
  57. "# Run the same hugetlb test but using private file:\n"
  58. "./uffd-stress hugetlb-private 256 50\n\n"
  59. "# 10MiB-~6GiB 999 bounces anonymous test, "
  60. "continue forever unless an error triggers\n"
  61. "while ./uffd-stress anon $[RANDOM % 6000 + 10] 999; do true; done\n\n";
  62. static void usage(void)
  63. {
  64. fprintf(stderr, "\nUsage: ./uffd-stress <test type> <MiB> <bounces>\n\n");
  65. fprintf(stderr, "Supported <test type>: anon, hugetlb, "
  66. "hugetlb-private, shmem, shmem-private\n\n");
  67. fprintf(stderr, "Examples:\n\n");
  68. fprintf(stderr, "%s", examples);
  69. exit(1);
  70. }
  71. static void uffd_stats_reset(struct uffd_args *args, unsigned long n_cpus)
  72. {
  73. int i;
  74. for (i = 0; i < n_cpus; i++) {
  75. args[i].cpu = i;
  76. args[i].apply_wp = test_uffdio_wp;
  77. args[i].missing_faults = 0;
  78. args[i].wp_faults = 0;
  79. args[i].minor_faults = 0;
  80. }
  81. }
  82. static void *locking_thread(void *arg)
  83. {
  84. unsigned long cpu = (unsigned long) arg;
  85. unsigned long page_nr;
  86. unsigned long long count;
  87. if (!(bounces & BOUNCE_RANDOM)) {
  88. page_nr = -bounces;
  89. if (!(bounces & BOUNCE_RACINGFAULTS))
  90. page_nr += cpu * nr_pages_per_cpu;
  91. }
  92. while (!finished) {
  93. if (bounces & BOUNCE_RANDOM) {
  94. if (getrandom(&page_nr, sizeof(page_nr), 0) != sizeof(page_nr))
  95. err("getrandom failed");
  96. } else
  97. page_nr += 1;
  98. page_nr %= nr_pages;
  99. pthread_mutex_lock(area_mutex(area_dst, page_nr));
  100. count = *area_count(area_dst, page_nr);
  101. if (count != count_verify[page_nr])
  102. err("page_nr %lu memory corruption %llu %llu",
  103. page_nr, count, count_verify[page_nr]);
  104. count++;
  105. *area_count(area_dst, page_nr) = count_verify[page_nr] = count;
  106. pthread_mutex_unlock(area_mutex(area_dst, page_nr));
  107. }
  108. return NULL;
  109. }
  110. static int copy_page_retry(int ufd, unsigned long offset)
  111. {
  112. return __copy_page(ufd, offset, true, test_uffdio_wp);
  113. }
  114. pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER;
  115. static void *uffd_read_thread(void *arg)
  116. {
  117. struct uffd_args *args = (struct uffd_args *)arg;
  118. struct uffd_msg msg;
  119. pthread_mutex_unlock(&uffd_read_mutex);
  120. /* from here cancellation is ok */
  121. for (;;) {
  122. if (uffd_read_msg(uffd, &msg))
  123. continue;
  124. uffd_handle_page_fault(&msg, args);
  125. }
  126. return NULL;
  127. }
  128. static void *background_thread(void *arg)
  129. {
  130. unsigned long cpu = (unsigned long) arg;
  131. unsigned long page_nr, start_nr, mid_nr, end_nr;
  132. start_nr = cpu * nr_pages_per_cpu;
  133. end_nr = (cpu+1) * nr_pages_per_cpu;
  134. mid_nr = (start_nr + end_nr) / 2;
  135. /* Copy the first half of the pages */
  136. for (page_nr = start_nr; page_nr < mid_nr; page_nr++)
  137. copy_page_retry(uffd, page_nr * page_size);
  138. /*
  139. * If we need to test uffd-wp, set it up now. Then we'll have
  140. * at least the first half of the pages mapped already which
  141. * can be write-protected for testing
  142. */
  143. if (test_uffdio_wp)
  144. wp_range(uffd, (unsigned long)area_dst + start_nr * page_size,
  145. nr_pages_per_cpu * page_size, true);
  146. /*
  147. * Continue the 2nd half of the page copying, handling write
  148. * protection faults if any
  149. */
  150. for (page_nr = mid_nr; page_nr < end_nr; page_nr++)
  151. copy_page_retry(uffd, page_nr * page_size);
  152. return NULL;
  153. }
  154. static int stress(struct uffd_args *args)
  155. {
  156. unsigned long cpu;
  157. pthread_t locking_threads[nr_cpus];
  158. pthread_t uffd_threads[nr_cpus];
  159. pthread_t background_threads[nr_cpus];
  160. finished = 0;
  161. for (cpu = 0; cpu < nr_cpus; cpu++) {
  162. if (pthread_create(&locking_threads[cpu], &attr,
  163. locking_thread, (void *)cpu))
  164. return 1;
  165. if (bounces & BOUNCE_POLL) {
  166. if (pthread_create(&uffd_threads[cpu], &attr, uffd_poll_thread, &args[cpu]))
  167. err("uffd_poll_thread create");
  168. } else {
  169. if (pthread_create(&uffd_threads[cpu], &attr,
  170. uffd_read_thread,
  171. (void *)&args[cpu]))
  172. return 1;
  173. pthread_mutex_lock(&uffd_read_mutex);
  174. }
  175. if (pthread_create(&background_threads[cpu], &attr,
  176. background_thread, (void *)cpu))
  177. return 1;
  178. }
  179. for (cpu = 0; cpu < nr_cpus; cpu++)
  180. if (pthread_join(background_threads[cpu], NULL))
  181. return 1;
  182. /*
  183. * Be strict and immediately zap area_src, the whole area has
  184. * been transferred already by the background treads. The
  185. * area_src could then be faulted in a racy way by still
  186. * running uffdio_threads reading zeropages after we zapped
  187. * area_src (but they're guaranteed to get -EEXIST from
  188. * UFFDIO_COPY without writing zero pages into area_dst
  189. * because the background threads already completed).
  190. */
  191. uffd_test_ops->release_pages(area_src);
  192. finished = 1;
  193. for (cpu = 0; cpu < nr_cpus; cpu++)
  194. if (pthread_join(locking_threads[cpu], NULL))
  195. return 1;
  196. for (cpu = 0; cpu < nr_cpus; cpu++) {
  197. char c;
  198. if (bounces & BOUNCE_POLL) {
  199. if (write(pipefd[cpu*2+1], &c, 1) != 1)
  200. err("pipefd write error");
  201. if (pthread_join(uffd_threads[cpu],
  202. (void *)&args[cpu]))
  203. return 1;
  204. } else {
  205. if (pthread_cancel(uffd_threads[cpu]))
  206. return 1;
  207. if (pthread_join(uffd_threads[cpu], NULL))
  208. return 1;
  209. }
  210. }
  211. return 0;
  212. }
  213. static int userfaultfd_stress(void)
  214. {
  215. void *area;
  216. unsigned long nr;
  217. struct uffd_args args[nr_cpus];
  218. uint64_t mem_size = nr_pages * page_size;
  219. int flags = 0;
  220. memset(args, 0, sizeof(struct uffd_args) * nr_cpus);
  221. if (features & UFFD_FEATURE_WP_UNPOPULATED && test_type == TEST_ANON)
  222. flags = UFFD_FEATURE_WP_UNPOPULATED;
  223. if (uffd_test_ctx_init(flags, NULL))
  224. err("context init failed");
  225. if (posix_memalign(&area, page_size, page_size))
  226. err("out of memory");
  227. zeropage = area;
  228. bzero(zeropage, page_size);
  229. pthread_mutex_lock(&uffd_read_mutex);
  230. pthread_attr_init(&attr);
  231. pthread_attr_setstacksize(&attr, 16*1024*1024);
  232. while (bounces--) {
  233. printf("bounces: %d, mode:", bounces);
  234. if (bounces & BOUNCE_RANDOM)
  235. printf(" rnd");
  236. if (bounces & BOUNCE_RACINGFAULTS)
  237. printf(" racing");
  238. if (bounces & BOUNCE_VERIFY)
  239. printf(" ver");
  240. if (bounces & BOUNCE_POLL)
  241. printf(" poll");
  242. else
  243. printf(" read");
  244. printf(", ");
  245. fflush(stdout);
  246. if (bounces & BOUNCE_POLL)
  247. fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK);
  248. else
  249. fcntl(uffd, F_SETFL, uffd_flags & ~O_NONBLOCK);
  250. /* register */
  251. if (uffd_register(uffd, area_dst, mem_size,
  252. true, test_uffdio_wp, false))
  253. err("register failure");
  254. if (area_dst_alias) {
  255. if (uffd_register(uffd, area_dst_alias, mem_size,
  256. true, test_uffdio_wp, false))
  257. err("register failure alias");
  258. }
  259. /*
  260. * The madvise done previously isn't enough: some
  261. * uffd_thread could have read userfaults (one of
  262. * those already resolved by the background thread)
  263. * and it may be in the process of calling
  264. * UFFDIO_COPY. UFFDIO_COPY will read the zapped
  265. * area_src and it would map a zero page in it (of
  266. * course such a UFFDIO_COPY is perfectly safe as it'd
  267. * return -EEXIST). The problem comes at the next
  268. * bounce though: that racing UFFDIO_COPY would
  269. * generate zeropages in the area_src, so invalidating
  270. * the previous MADV_DONTNEED. Without this additional
  271. * MADV_DONTNEED those zeropages leftovers in the
  272. * area_src would lead to -EEXIST failure during the
  273. * next bounce, effectively leaving a zeropage in the
  274. * area_dst.
  275. *
  276. * Try to comment this out madvise to see the memory
  277. * corruption being caught pretty quick.
  278. *
  279. * khugepaged is also inhibited to collapse THP after
  280. * MADV_DONTNEED only after the UFFDIO_REGISTER, so it's
  281. * required to MADV_DONTNEED here.
  282. */
  283. uffd_test_ops->release_pages(area_dst);
  284. uffd_stats_reset(args, nr_cpus);
  285. /* bounce pass */
  286. if (stress(args)) {
  287. uffd_test_ctx_clear();
  288. return 1;
  289. }
  290. /* Clear all the write protections if there is any */
  291. if (test_uffdio_wp)
  292. wp_range(uffd, (unsigned long)area_dst,
  293. nr_pages * page_size, false);
  294. /* unregister */
  295. if (uffd_unregister(uffd, area_dst, mem_size))
  296. err("unregister failure");
  297. if (area_dst_alias) {
  298. if (uffd_unregister(uffd, area_dst_alias, mem_size))
  299. err("unregister failure alias");
  300. }
  301. /* verification */
  302. if (bounces & BOUNCE_VERIFY)
  303. for (nr = 0; nr < nr_pages; nr++)
  304. if (*area_count(area_dst, nr) != count_verify[nr])
  305. err("error area_count %llu %llu %lu\n",
  306. *area_count(area_src, nr),
  307. count_verify[nr], nr);
  308. /* prepare next bounce */
  309. swap(area_src, area_dst);
  310. swap(area_src_alias, area_dst_alias);
  311. uffd_stats_report(args, nr_cpus);
  312. }
  313. uffd_test_ctx_clear();
  314. return 0;
  315. }
  316. static void set_test_type(const char *type)
  317. {
  318. if (!strcmp(type, "anon")) {
  319. test_type = TEST_ANON;
  320. uffd_test_ops = &anon_uffd_test_ops;
  321. } else if (!strcmp(type, "hugetlb")) {
  322. test_type = TEST_HUGETLB;
  323. uffd_test_ops = &hugetlb_uffd_test_ops;
  324. map_shared = true;
  325. } else if (!strcmp(type, "hugetlb-private")) {
  326. test_type = TEST_HUGETLB;
  327. uffd_test_ops = &hugetlb_uffd_test_ops;
  328. } else if (!strcmp(type, "shmem")) {
  329. map_shared = true;
  330. test_type = TEST_SHMEM;
  331. uffd_test_ops = &shmem_uffd_test_ops;
  332. } else if (!strcmp(type, "shmem-private")) {
  333. test_type = TEST_SHMEM;
  334. uffd_test_ops = &shmem_uffd_test_ops;
  335. }
  336. }
  337. static void parse_test_type_arg(const char *raw_type)
  338. {
  339. set_test_type(raw_type);
  340. if (!test_type)
  341. err("failed to parse test type argument: '%s'", raw_type);
  342. if (test_type == TEST_HUGETLB)
  343. page_size = default_huge_page_size();
  344. else
  345. page_size = sysconf(_SC_PAGE_SIZE);
  346. if (!page_size)
  347. err("Unable to determine page size");
  348. if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2
  349. > page_size)
  350. err("Impossible to run this test");
  351. /*
  352. * Whether we can test certain features depends not just on test type,
  353. * but also on whether or not this particular kernel supports the
  354. * feature.
  355. */
  356. if (uffd_get_features(&features))
  357. err("failed to get available features");
  358. test_uffdio_wp = test_uffdio_wp &&
  359. (features & UFFD_FEATURE_PAGEFAULT_FLAG_WP);
  360. if (test_type != TEST_ANON && !(features & UFFD_FEATURE_WP_HUGETLBFS_SHMEM))
  361. test_uffdio_wp = false;
  362. close(uffd);
  363. uffd = -1;
  364. }
  365. static void sigalrm(int sig)
  366. {
  367. if (sig != SIGALRM)
  368. abort();
  369. test_uffdio_copy_eexist = true;
  370. alarm(ALARM_INTERVAL_SECS);
  371. }
  372. int main(int argc, char **argv)
  373. {
  374. size_t bytes;
  375. if (argc < 4)
  376. usage();
  377. if (signal(SIGALRM, sigalrm) == SIG_ERR)
  378. err("failed to arm SIGALRM");
  379. alarm(ALARM_INTERVAL_SECS);
  380. parse_test_type_arg(argv[1]);
  381. bytes = atol(argv[2]) * 1024 * 1024;
  382. if (test_type == TEST_HUGETLB &&
  383. get_free_hugepages() < bytes / page_size) {
  384. printf("skip: Skipping userfaultfd... not enough hugepages\n");
  385. return KSFT_SKIP;
  386. }
  387. nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  388. nr_pages_per_cpu = bytes / page_size / nr_cpus;
  389. if (!nr_pages_per_cpu) {
  390. _err("invalid MiB");
  391. usage();
  392. }
  393. bounces = atoi(argv[3]);
  394. if (bounces <= 0) {
  395. _err("invalid bounces");
  396. usage();
  397. }
  398. nr_pages = nr_pages_per_cpu * nr_cpus;
  399. printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
  400. nr_pages, nr_pages_per_cpu);
  401. return userfaultfd_stress();
  402. }
  403. #else /* __NR_userfaultfd */
  404. #warning "missing __NR_userfaultfd definition"
  405. int main(void)
  406. {
  407. printf("skip: Skipping userfaultfd test (missing __NR_userfaultfd)\n");
  408. return KSFT_SKIP;
  409. }
  410. #endif /* __NR_userfaultfd */