map_populate.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2018 Dmitry Safonov, Arista Networks
  4. *
  5. * MAP_POPULATE | MAP_PRIVATE should COW VMA pages.
  6. */
  7. #define _GNU_SOURCE
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <sys/mman.h>
  11. #include <sys/socket.h>
  12. #include <sys/types.h>
  13. #include <sys/wait.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include "../kselftest.h"
  19. #define MMAP_SZ 4096
  20. #define BUG_ON(condition, description) \
  21. do { \
  22. if (condition) \
  23. ksft_exit_fail_msg("[FAIL]\t%s:%d\t%s:%s\n", \
  24. __func__, __LINE__, (description), \
  25. strerror(errno)); \
  26. } while (0)
  27. #define TESTS_IN_CHILD 2
  28. static void parent_f(int sock, unsigned long *smap, int child)
  29. {
  30. int status, ret;
  31. ret = read(sock, &status, sizeof(int));
  32. BUG_ON(ret <= 0, "read(sock)");
  33. *smap = 0x22222BAD;
  34. ret = msync(smap, MMAP_SZ, MS_SYNC);
  35. BUG_ON(ret, "msync()");
  36. ret = write(sock, &status, sizeof(int));
  37. BUG_ON(ret <= 0, "write(sock)");
  38. waitpid(child, &status, 0);
  39. /* The ksft macros don't keep counters between processes */
  40. ksft_cnt.ksft_pass = WEXITSTATUS(status);
  41. ksft_cnt.ksft_fail = TESTS_IN_CHILD - WEXITSTATUS(status);
  42. }
  43. static int child_f(int sock, unsigned long *smap, int fd)
  44. {
  45. int ret, buf = 0;
  46. smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
  47. MAP_PRIVATE | MAP_POPULATE, fd, 0);
  48. BUG_ON(smap == MAP_FAILED, "mmap()");
  49. BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file");
  50. ret = write(sock, &buf, sizeof(int));
  51. BUG_ON(ret <= 0, "write(sock)");
  52. ret = read(sock, &buf, sizeof(int));
  53. BUG_ON(ret <= 0, "read(sock)");
  54. ksft_test_result(*smap != 0x22222BAD, "MAP_POPULATE COW private page\n");
  55. ksft_test_result(*smap == 0xdeadbabe, "The mapping state\n");
  56. /* The ksft macros don't keep counters between processes */
  57. return ksft_cnt.ksft_pass;
  58. }
  59. int main(int argc, char **argv)
  60. {
  61. int sock[2], child, ret;
  62. FILE *ftmp;
  63. unsigned long *smap;
  64. ksft_print_header();
  65. ksft_set_plan(TESTS_IN_CHILD);
  66. ftmp = tmpfile();
  67. BUG_ON(!ftmp, "tmpfile()");
  68. ret = ftruncate(fileno(ftmp), MMAP_SZ);
  69. BUG_ON(ret, "ftruncate()");
  70. smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
  71. MAP_SHARED, fileno(ftmp), 0);
  72. BUG_ON(smap == MAP_FAILED, "mmap()");
  73. *smap = 0xdeadbabe;
  74. /* Probably unnecessary, but let it be. */
  75. ret = msync(smap, MMAP_SZ, MS_SYNC);
  76. BUG_ON(ret, "msync()");
  77. ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock);
  78. BUG_ON(ret, "socketpair()");
  79. child = fork();
  80. BUG_ON(child == -1, "fork()");
  81. if (child) {
  82. ret = close(sock[0]);
  83. BUG_ON(ret, "close()");
  84. parent_f(sock[1], smap, child);
  85. ksft_finished();
  86. }
  87. ret = close(sock[1]);
  88. BUG_ON(ret, "close()");
  89. return child_f(sock[0], smap, fileno(ftmp));
  90. }