uffd-common.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Userfaultfd tests util functions
  4. *
  5. * Copyright (C) 2015-2023 Red Hat, Inc.
  6. */
  7. #include "uffd-common.h"
  8. uffd_test_ops_t *uffd_test_ops;
  9. uffd_test_case_ops_t *uffd_test_case_ops;
  10. /* pthread_mutex_t starts at page offset 0 */
  11. pthread_mutex_t *area_mutex(char *area, unsigned long nr, uffd_global_test_opts_t *gopts)
  12. {
  13. return (pthread_mutex_t *) (area + nr * gopts->page_size);
  14. }
  15. /*
  16. * count is placed in the page after pthread_mutex_t naturally aligned
  17. * to avoid non alignment faults on non-x86 archs.
  18. */
  19. volatile unsigned long long *area_count(char *area, unsigned long nr,
  20. uffd_global_test_opts_t *gopts)
  21. {
  22. return (volatile unsigned long long *)
  23. ((unsigned long)(area + nr * gopts->page_size +
  24. sizeof(pthread_mutex_t) + sizeof(unsigned long long) - 1) &
  25. ~(unsigned long)(sizeof(unsigned long long) - 1));
  26. }
  27. static int uffd_mem_fd_create(off_t mem_size, bool hugetlb)
  28. {
  29. unsigned int memfd_flags = 0;
  30. int mem_fd;
  31. if (hugetlb)
  32. memfd_flags = MFD_HUGETLB;
  33. mem_fd = memfd_create("uffd-test", memfd_flags);
  34. if (mem_fd < 0)
  35. err("memfd_create");
  36. if (ftruncate(mem_fd, mem_size))
  37. err("ftruncate");
  38. if (fallocate(mem_fd,
  39. FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0,
  40. mem_size))
  41. err("fallocate");
  42. return mem_fd;
  43. }
  44. static void anon_release_pages(uffd_global_test_opts_t *gopts, char *rel_area)
  45. {
  46. if (madvise(rel_area, gopts->nr_pages * gopts->page_size, MADV_DONTNEED))
  47. err("madvise(MADV_DONTNEED) failed");
  48. }
  49. static int anon_allocate_area(uffd_global_test_opts_t *gopts, void **alloc_area, bool is_src)
  50. {
  51. *alloc_area = mmap(NULL, gopts->nr_pages * gopts->page_size, PROT_READ | PROT_WRITE,
  52. MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  53. if (*alloc_area == MAP_FAILED) {
  54. *alloc_area = NULL;
  55. return -errno;
  56. }
  57. return 0;
  58. }
  59. static void noop_alias_mapping(uffd_global_test_opts_t *gopts, __u64 *start,
  60. size_t len, unsigned long offset)
  61. {
  62. }
  63. static void hugetlb_release_pages(uffd_global_test_opts_t *gopts, char *rel_area)
  64. {
  65. if (!gopts->map_shared) {
  66. if (madvise(rel_area, gopts->nr_pages * gopts->page_size, MADV_DONTNEED))
  67. err("madvise(MADV_DONTNEED) failed");
  68. } else {
  69. if (madvise(rel_area, gopts->nr_pages * gopts->page_size, MADV_REMOVE))
  70. err("madvise(MADV_REMOVE) failed");
  71. }
  72. }
  73. static int hugetlb_allocate_area(uffd_global_test_opts_t *gopts, void **alloc_area, bool is_src)
  74. {
  75. off_t size = gopts->nr_pages * gopts->page_size;
  76. off_t offset = is_src ? 0 : size;
  77. void *area_alias = NULL;
  78. char **alloc_area_alias;
  79. int mem_fd = uffd_mem_fd_create(size * 2, true);
  80. *alloc_area = mmap(NULL, size, PROT_READ | PROT_WRITE,
  81. (gopts->map_shared ? MAP_SHARED : MAP_PRIVATE) |
  82. (is_src ? 0 : MAP_NORESERVE),
  83. mem_fd, offset);
  84. if (*alloc_area == MAP_FAILED) {
  85. *alloc_area = NULL;
  86. return -errno;
  87. }
  88. if (gopts->map_shared) {
  89. area_alias = mmap(NULL, size, PROT_READ | PROT_WRITE,
  90. MAP_SHARED, mem_fd, offset);
  91. if (area_alias == MAP_FAILED)
  92. return -errno;
  93. }
  94. if (is_src) {
  95. alloc_area_alias = &gopts->area_src_alias;
  96. } else {
  97. alloc_area_alias = &gopts->area_dst_alias;
  98. }
  99. if (area_alias)
  100. *alloc_area_alias = area_alias;
  101. close(mem_fd);
  102. return 0;
  103. }
  104. static void hugetlb_alias_mapping(uffd_global_test_opts_t *gopts, __u64 *start,
  105. size_t len, unsigned long offset)
  106. {
  107. if (!gopts->map_shared)
  108. return;
  109. *start = (unsigned long) gopts->area_dst_alias + offset;
  110. }
  111. static void shmem_release_pages(uffd_global_test_opts_t *gopts, char *rel_area)
  112. {
  113. if (madvise(rel_area, gopts->nr_pages * gopts->page_size, MADV_REMOVE))
  114. err("madvise(MADV_REMOVE) failed");
  115. }
  116. static int shmem_allocate_area(uffd_global_test_opts_t *gopts, void **alloc_area, bool is_src)
  117. {
  118. void *area_alias = NULL;
  119. size_t bytes = gopts->nr_pages * gopts->page_size, hpage_size = read_pmd_pagesize();
  120. unsigned long offset = is_src ? 0 : bytes;
  121. char *p = NULL, *p_alias = NULL;
  122. int mem_fd = uffd_mem_fd_create(bytes * 2, false);
  123. size_t region_size = bytes * 2 + hpage_size;
  124. void *reserve = mmap(NULL, region_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
  125. -1, 0);
  126. if (reserve == MAP_FAILED) {
  127. close(mem_fd);
  128. return -errno;
  129. }
  130. p = reserve;
  131. p_alias = p;
  132. p_alias += bytes;
  133. p_alias += hpage_size; /* Prevent src/dst VMA merge */
  134. *alloc_area = mmap(p, bytes, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
  135. mem_fd, offset);
  136. if (*alloc_area == MAP_FAILED) {
  137. *alloc_area = NULL;
  138. munmap(reserve, region_size);
  139. close(mem_fd);
  140. return -errno;
  141. }
  142. if (*alloc_area != p)
  143. err("mmap of memfd failed at %p", p);
  144. area_alias = mmap(p_alias, bytes, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
  145. mem_fd, offset);
  146. if (area_alias == MAP_FAILED) {
  147. *alloc_area = NULL;
  148. munmap(reserve, region_size);
  149. close(mem_fd);
  150. return -errno;
  151. }
  152. if (area_alias != p_alias)
  153. err("mmap of anonymous memory failed at %p", p_alias);
  154. if (is_src)
  155. gopts->area_src_alias = area_alias;
  156. else
  157. gopts->area_dst_alias = area_alias;
  158. close(mem_fd);
  159. return 0;
  160. }
  161. static void shmem_alias_mapping(uffd_global_test_opts_t *gopts, __u64 *start,
  162. size_t len, unsigned long offset)
  163. {
  164. *start = (unsigned long)gopts->area_dst_alias + offset;
  165. }
  166. static void shmem_check_pmd_mapping(uffd_global_test_opts_t *gopts, void *p, int expect_nr_hpages)
  167. {
  168. if (!check_huge_shmem(gopts->area_dst_alias, expect_nr_hpages,
  169. read_pmd_pagesize()))
  170. err("Did not find expected %d number of hugepages",
  171. expect_nr_hpages);
  172. }
  173. struct uffd_test_ops anon_uffd_test_ops = {
  174. .allocate_area = anon_allocate_area,
  175. .release_pages = anon_release_pages,
  176. .alias_mapping = noop_alias_mapping,
  177. .check_pmd_mapping = NULL,
  178. };
  179. struct uffd_test_ops shmem_uffd_test_ops = {
  180. .allocate_area = shmem_allocate_area,
  181. .release_pages = shmem_release_pages,
  182. .alias_mapping = shmem_alias_mapping,
  183. .check_pmd_mapping = shmem_check_pmd_mapping,
  184. };
  185. struct uffd_test_ops hugetlb_uffd_test_ops = {
  186. .allocate_area = hugetlb_allocate_area,
  187. .release_pages = hugetlb_release_pages,
  188. .alias_mapping = hugetlb_alias_mapping,
  189. .check_pmd_mapping = NULL,
  190. };
  191. void uffd_stats_report(struct uffd_args *args, int n_cpus)
  192. {
  193. int i;
  194. unsigned long long miss_total = 0, wp_total = 0, minor_total = 0;
  195. for (i = 0; i < n_cpus; i++) {
  196. miss_total += args[i].missing_faults;
  197. wp_total += args[i].wp_faults;
  198. minor_total += args[i].minor_faults;
  199. }
  200. printf("userfaults: ");
  201. if (miss_total) {
  202. printf("%llu missing (", miss_total);
  203. for (i = 0; i < n_cpus; i++)
  204. printf("%lu+", args[i].missing_faults);
  205. printf("\b) ");
  206. }
  207. if (wp_total) {
  208. printf("%llu wp (", wp_total);
  209. for (i = 0; i < n_cpus; i++)
  210. printf("%lu+", args[i].wp_faults);
  211. printf("\b) ");
  212. }
  213. if (minor_total) {
  214. printf("%llu minor (", minor_total);
  215. for (i = 0; i < n_cpus; i++)
  216. printf("%lu+", args[i].minor_faults);
  217. printf("\b)");
  218. }
  219. printf("\n");
  220. }
  221. int userfaultfd_open(uffd_global_test_opts_t *gopts, uint64_t *features)
  222. {
  223. struct uffdio_api uffdio_api;
  224. gopts->uffd = uffd_open(UFFD_FLAGS);
  225. if (gopts->uffd < 0)
  226. return -1;
  227. gopts->uffd_flags = fcntl(gopts->uffd, F_GETFD, NULL);
  228. uffdio_api.api = UFFD_API;
  229. uffdio_api.features = *features;
  230. if (ioctl(gopts->uffd, UFFDIO_API, &uffdio_api))
  231. /* Probably lack of CAP_PTRACE? */
  232. return -1;
  233. if (uffdio_api.api != UFFD_API)
  234. err("UFFDIO_API error: %" PRIu64, (uint64_t)uffdio_api.api);
  235. *features = uffdio_api.features;
  236. return 0;
  237. }
  238. static inline void munmap_area(uffd_global_test_opts_t *gopts, void **area)
  239. {
  240. if (*area)
  241. if (munmap(*area, gopts->nr_pages * gopts->page_size))
  242. err("munmap");
  243. *area = NULL;
  244. }
  245. void uffd_test_ctx_clear(uffd_global_test_opts_t *gopts)
  246. {
  247. size_t i;
  248. if (gopts->pipefd) {
  249. for (i = 0; i < gopts->nr_parallel * 2; ++i) {
  250. if (close(gopts->pipefd[i]))
  251. err("close pipefd");
  252. }
  253. free(gopts->pipefd);
  254. gopts->pipefd = NULL;
  255. }
  256. if (gopts->count_verify) {
  257. free(gopts->count_verify);
  258. gopts->count_verify = NULL;
  259. }
  260. if (gopts->uffd != -1) {
  261. if (close(gopts->uffd))
  262. err("close uffd");
  263. gopts->uffd = -1;
  264. }
  265. munmap_area(gopts, (void **)&gopts->area_src);
  266. munmap_area(gopts, (void **)&gopts->area_src_alias);
  267. munmap_area(gopts, (void **)&gopts->area_dst);
  268. munmap_area(gopts, (void **)&gopts->area_dst_alias);
  269. munmap_area(gopts, (void **)&gopts->area_remap);
  270. }
  271. int uffd_test_ctx_init(uffd_global_test_opts_t *gopts, uint64_t features, const char **errmsg)
  272. {
  273. unsigned long nr, cpu;
  274. int ret;
  275. gopts->area_src_alias = NULL;
  276. gopts->area_dst_alias = NULL;
  277. gopts->area_remap = NULL;
  278. if (uffd_test_case_ops && uffd_test_case_ops->pre_alloc) {
  279. ret = uffd_test_case_ops->pre_alloc(gopts, errmsg);
  280. if (ret)
  281. return ret;
  282. }
  283. ret = uffd_test_ops->allocate_area(gopts, (void **) &gopts->area_src, true);
  284. ret |= uffd_test_ops->allocate_area(gopts, (void **) &gopts->area_dst, false);
  285. if (ret) {
  286. if (errmsg)
  287. *errmsg = "memory allocation failed";
  288. return ret;
  289. }
  290. if (uffd_test_case_ops && uffd_test_case_ops->post_alloc) {
  291. ret = uffd_test_case_ops->post_alloc(gopts, errmsg);
  292. if (ret)
  293. return ret;
  294. }
  295. ret = userfaultfd_open(gopts, &features);
  296. if (ret) {
  297. if (errmsg)
  298. *errmsg = "possible lack of privilege";
  299. return ret;
  300. }
  301. gopts->count_verify = malloc(gopts->nr_pages * sizeof(unsigned long long));
  302. if (!gopts->count_verify)
  303. err("count_verify");
  304. for (nr = 0; nr < gopts->nr_pages; nr++) {
  305. *area_mutex(gopts->area_src, nr, gopts) =
  306. (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
  307. gopts->count_verify[nr] = *area_count(gopts->area_src, nr, gopts) = 1;
  308. /*
  309. * In the transition between 255 to 256, powerpc will
  310. * read out of order in my_bcmp and see both bytes as
  311. * zero, so leave a placeholder below always non-zero
  312. * after the count, to avoid my_bcmp to trigger false
  313. * positives.
  314. */
  315. *(area_count(gopts->area_src, nr, gopts) + 1) = 1;
  316. }
  317. /*
  318. * After initialization of area_src, we must explicitly release pages
  319. * for area_dst to make sure it's fully empty. Otherwise we could have
  320. * some area_dst pages be erroneously initialized with zero pages,
  321. * hence we could hit memory corruption later in the test.
  322. *
  323. * One example is when THP is globally enabled, above allocate_area()
  324. * calls could have the two areas merged into a single VMA (as they
  325. * will have the same VMA flags so they're mergeable). When we
  326. * initialize the area_src above, it's possible that some part of
  327. * area_dst could have been faulted in via one huge THP that will be
  328. * shared between area_src and area_dst. It could cause some of the
  329. * area_dst won't be trapped by missing userfaults.
  330. *
  331. * This release_pages() will guarantee even if that happened, we'll
  332. * proactively split the thp and drop any accidentally initialized
  333. * pages within area_dst.
  334. */
  335. uffd_test_ops->release_pages(gopts, gopts->area_dst);
  336. gopts->pipefd = malloc(sizeof(int) * gopts->nr_parallel * 2);
  337. if (!gopts->pipefd)
  338. err("pipefd");
  339. for (cpu = 0; cpu < gopts->nr_parallel; cpu++)
  340. if (pipe2(&gopts->pipefd[cpu * 2], O_CLOEXEC | O_NONBLOCK))
  341. err("pipe");
  342. return 0;
  343. }
  344. void wp_range(int ufd, __u64 start, __u64 len, bool wp)
  345. {
  346. struct uffdio_writeprotect prms;
  347. /* Write protection page faults */
  348. prms.range.start = start;
  349. prms.range.len = len;
  350. /* Undo write-protect, do wakeup after that */
  351. prms.mode = wp ? UFFDIO_WRITEPROTECT_MODE_WP : 0;
  352. if (ioctl(ufd, UFFDIO_WRITEPROTECT, &prms))
  353. err("clear WP failed: address=0x%"PRIx64, (uint64_t)start);
  354. }
  355. static void continue_range(int ufd, __u64 start, __u64 len, bool wp)
  356. {
  357. struct uffdio_continue req;
  358. int ret;
  359. req.range.start = start;
  360. req.range.len = len;
  361. req.mode = 0;
  362. if (wp)
  363. req.mode |= UFFDIO_CONTINUE_MODE_WP;
  364. if (ioctl(ufd, UFFDIO_CONTINUE, &req))
  365. err("UFFDIO_CONTINUE failed for address 0x%" PRIx64,
  366. (uint64_t)start);
  367. /*
  368. * Error handling within the kernel for continue is subtly different
  369. * from copy or zeropage, so it may be a source of bugs. Trigger an
  370. * error (-EEXIST) on purpose, to verify doing so doesn't cause a BUG.
  371. */
  372. req.mapped = 0;
  373. ret = ioctl(ufd, UFFDIO_CONTINUE, &req);
  374. if (ret >= 0 || req.mapped != -EEXIST)
  375. err("failed to exercise UFFDIO_CONTINUE error handling, ret=%d, mapped=%" PRId64,
  376. ret, (int64_t) req.mapped);
  377. }
  378. int uffd_read_msg(uffd_global_test_opts_t *gopts, struct uffd_msg *msg)
  379. {
  380. int ret = read(gopts->uffd, msg, sizeof(*msg));
  381. if (ret != sizeof(*msg)) {
  382. if (ret < 0) {
  383. if (errno == EAGAIN || errno == EINTR)
  384. return 1;
  385. err("blocking read error");
  386. } else {
  387. err("short read");
  388. }
  389. }
  390. return 0;
  391. }
  392. void uffd_handle_page_fault(uffd_global_test_opts_t *gopts, struct uffd_msg *msg,
  393. struct uffd_args *args)
  394. {
  395. unsigned long offset;
  396. if (msg->event != UFFD_EVENT_PAGEFAULT)
  397. err("unexpected msg event %u", msg->event);
  398. if (msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WP) {
  399. /* Write protect page faults */
  400. wp_range(gopts->uffd, msg->arg.pagefault.address, gopts->page_size, false);
  401. args->wp_faults++;
  402. } else if (msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_MINOR) {
  403. uint8_t *area;
  404. int b;
  405. /*
  406. * Minor page faults
  407. *
  408. * To prove we can modify the original range for testing
  409. * purposes, we're going to bit flip this range before
  410. * continuing.
  411. *
  412. * Note that this requires all minor page fault tests operate on
  413. * area_dst (non-UFFD-registered) and area_dst_alias
  414. * (UFFD-registered).
  415. */
  416. area = (uint8_t *)(gopts->area_dst +
  417. ((char *)msg->arg.pagefault.address -
  418. gopts->area_dst_alias));
  419. for (b = 0; b < gopts->page_size; ++b)
  420. area[b] = ~area[b];
  421. continue_range(gopts->uffd, msg->arg.pagefault.address, gopts->page_size,
  422. args->apply_wp);
  423. args->minor_faults++;
  424. } else {
  425. /*
  426. * Missing page faults.
  427. *
  428. * Here we force a write check for each of the missing mode
  429. * faults. It's guaranteed because the only threads that
  430. * will trigger uffd faults are the locking threads, and
  431. * their first instruction to touch the missing page will
  432. * always be pthread_mutex_lock().
  433. *
  434. * Note that here we relied on an NPTL glibc impl detail to
  435. * always read the lock type at the entry of the lock op
  436. * (pthread_mutex_t.__data.__type, offset 0x10) before
  437. * doing any locking operations to guarantee that. It's
  438. * actually not good to rely on this impl detail because
  439. * logically a pthread-compatible lib can implement the
  440. * locks without types and we can fail when linking with
  441. * them. However since we used to find bugs with this
  442. * strict check we still keep it around. Hopefully this
  443. * could be a good hint when it fails again. If one day
  444. * it'll break on some other impl of glibc we'll revisit.
  445. */
  446. if (msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE)
  447. err("unexpected write fault");
  448. offset = (char *)(unsigned long)msg->arg.pagefault.address - gopts->area_dst;
  449. offset &= ~(gopts->page_size-1);
  450. if (copy_page(gopts, offset, args->apply_wp))
  451. args->missing_faults++;
  452. }
  453. }
  454. void *uffd_poll_thread(void *arg)
  455. {
  456. struct uffd_args *args = (struct uffd_args *)arg;
  457. uffd_global_test_opts_t *gopts = args->gopts;
  458. unsigned long cpu = args->cpu;
  459. struct pollfd pollfd[2];
  460. struct uffd_msg msg;
  461. struct uffdio_register uffd_reg;
  462. int ret;
  463. char tmp_chr;
  464. if (!args->handle_fault)
  465. args->handle_fault = uffd_handle_page_fault;
  466. pollfd[0].fd = gopts->uffd;
  467. pollfd[0].events = POLLIN;
  468. pollfd[1].fd = gopts->pipefd[cpu*2];
  469. pollfd[1].events = POLLIN;
  470. gopts->ready_for_fork = true;
  471. for (;;) {
  472. ret = poll(pollfd, 2, -1);
  473. if (ret <= 0) {
  474. if (errno == EINTR || errno == EAGAIN)
  475. continue;
  476. err("poll error: %d", ret);
  477. }
  478. if (pollfd[1].revents) {
  479. if (!(pollfd[1].revents & POLLIN))
  480. err("pollfd[1].revents %d", pollfd[1].revents);
  481. if (read(pollfd[1].fd, &tmp_chr, 1) != 1)
  482. err("read pipefd error");
  483. break;
  484. }
  485. if (!(pollfd[0].revents & POLLIN))
  486. err("pollfd[0].revents %d", pollfd[0].revents);
  487. if (uffd_read_msg(gopts, &msg))
  488. continue;
  489. switch (msg.event) {
  490. default:
  491. err("unexpected msg event %u\n", msg.event);
  492. break;
  493. case UFFD_EVENT_PAGEFAULT:
  494. args->handle_fault(gopts, &msg, args);
  495. break;
  496. case UFFD_EVENT_FORK:
  497. close(gopts->uffd);
  498. gopts->uffd = msg.arg.fork.ufd;
  499. pollfd[0].fd = gopts->uffd;
  500. break;
  501. case UFFD_EVENT_REMOVE:
  502. uffd_reg.range.start = msg.arg.remove.start;
  503. uffd_reg.range.len = msg.arg.remove.end -
  504. msg.arg.remove.start;
  505. if (ioctl(gopts->uffd, UFFDIO_UNREGISTER, &uffd_reg.range))
  506. err("remove failure");
  507. break;
  508. case UFFD_EVENT_REMAP:
  509. gopts->area_remap = gopts->area_dst; /* save for later unmap */
  510. gopts->area_dst = (char *)(unsigned long)msg.arg.remap.to;
  511. break;
  512. }
  513. }
  514. return NULL;
  515. }
  516. static void retry_copy_page(uffd_global_test_opts_t *gopts, struct uffdio_copy *uffdio_copy,
  517. unsigned long offset)
  518. {
  519. uffd_test_ops->alias_mapping(gopts,
  520. &uffdio_copy->dst,
  521. uffdio_copy->len,
  522. offset);
  523. if (ioctl(gopts->uffd, UFFDIO_COPY, uffdio_copy)) {
  524. /* real retval in ufdio_copy.copy */
  525. if (uffdio_copy->copy != -EEXIST)
  526. err("UFFDIO_COPY retry error: %"PRId64,
  527. (int64_t)uffdio_copy->copy);
  528. } else {
  529. err("UFFDIO_COPY retry unexpected: %"PRId64,
  530. (int64_t)uffdio_copy->copy);
  531. }
  532. }
  533. static void wake_range(int ufd, unsigned long addr, unsigned long len)
  534. {
  535. struct uffdio_range uffdio_wake;
  536. uffdio_wake.start = addr;
  537. uffdio_wake.len = len;
  538. if (ioctl(ufd, UFFDIO_WAKE, &uffdio_wake))
  539. fprintf(stderr, "error waking %lu\n",
  540. addr), exit(1);
  541. }
  542. int __copy_page(uffd_global_test_opts_t *gopts, unsigned long offset, bool retry, bool wp)
  543. {
  544. struct uffdio_copy uffdio_copy;
  545. if (offset >= gopts->nr_pages * gopts->page_size)
  546. err("unexpected offset %lu\n", offset);
  547. uffdio_copy.dst = (unsigned long) gopts->area_dst + offset;
  548. uffdio_copy.src = (unsigned long) gopts->area_src + offset;
  549. uffdio_copy.len = gopts->page_size;
  550. if (wp)
  551. uffdio_copy.mode = UFFDIO_COPY_MODE_WP;
  552. else
  553. uffdio_copy.mode = 0;
  554. uffdio_copy.copy = 0;
  555. if (ioctl(gopts->uffd, UFFDIO_COPY, &uffdio_copy)) {
  556. /* real retval in ufdio_copy.copy */
  557. if (uffdio_copy.copy != -EEXIST)
  558. err("UFFDIO_COPY error: %"PRId64,
  559. (int64_t)uffdio_copy.copy);
  560. wake_range(gopts->uffd, uffdio_copy.dst, gopts->page_size);
  561. } else if (uffdio_copy.copy != gopts->page_size) {
  562. err("UFFDIO_COPY error: %"PRId64, (int64_t)uffdio_copy.copy);
  563. } else {
  564. if (gopts->test_uffdio_copy_eexist && retry) {
  565. gopts->test_uffdio_copy_eexist = false;
  566. retry_copy_page(gopts, &uffdio_copy, offset);
  567. }
  568. return 1;
  569. }
  570. return 0;
  571. }
  572. int copy_page(uffd_global_test_opts_t *gopts, unsigned long offset, bool wp)
  573. {
  574. return __copy_page(gopts, offset, false, wp);
  575. }
  576. int move_page(uffd_global_test_opts_t *gopts, unsigned long offset, unsigned long len)
  577. {
  578. struct uffdio_move uffdio_move;
  579. if (offset + len > gopts->nr_pages * gopts->page_size)
  580. err("unexpected offset %lu and length %lu\n", offset, len);
  581. uffdio_move.dst = (unsigned long) gopts->area_dst + offset;
  582. uffdio_move.src = (unsigned long) gopts->area_src + offset;
  583. uffdio_move.len = len;
  584. uffdio_move.mode = UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES;
  585. uffdio_move.move = 0;
  586. if (ioctl(gopts->uffd, UFFDIO_MOVE, &uffdio_move)) {
  587. /* real retval in uffdio_move.move */
  588. if (uffdio_move.move != -EEXIST)
  589. err("UFFDIO_MOVE error: %"PRId64,
  590. (int64_t)uffdio_move.move);
  591. wake_range(gopts->uffd, uffdio_move.dst, len);
  592. } else if (uffdio_move.move != len) {
  593. err("UFFDIO_MOVE error: %"PRId64, (int64_t)uffdio_move.move);
  594. } else
  595. return 1;
  596. return 0;
  597. }
  598. int uffd_open_dev(unsigned int flags)
  599. {
  600. int fd, uffd;
  601. fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC);
  602. if (fd < 0)
  603. return fd;
  604. uffd = ioctl(fd, USERFAULTFD_IOC_NEW, flags);
  605. close(fd);
  606. return uffd;
  607. }
  608. int uffd_open_sys(unsigned int flags)
  609. {
  610. #ifdef __NR_userfaultfd
  611. return syscall(__NR_userfaultfd, flags);
  612. #else
  613. return -1;
  614. #endif
  615. }
  616. int uffd_open(unsigned int flags)
  617. {
  618. int uffd = uffd_open_sys(flags);
  619. if (uffd < 0)
  620. uffd = uffd_open_dev(flags);
  621. return uffd;
  622. }
  623. int uffd_get_features(uint64_t *features)
  624. {
  625. struct uffdio_api uffdio_api = { .api = UFFD_API, .features = 0 };
  626. /*
  627. * This should by default work in most kernels; the feature list
  628. * will be the same no matter what we pass in here.
  629. */
  630. int fd = uffd_open(UFFD_USER_MODE_ONLY);
  631. if (fd < 0)
  632. /* Maybe the kernel is older than user-only mode? */
  633. fd = uffd_open(0);
  634. if (fd < 0)
  635. return fd;
  636. if (ioctl(fd, UFFDIO_API, &uffdio_api)) {
  637. close(fd);
  638. return -errno;
  639. }
  640. *features = uffdio_api.features;
  641. close(fd);
  642. return 0;
  643. }