map_populate.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. #include "vm_util.h"
  20. #define MMAP_SZ 4096
  21. #define BUG_ON(condition, description) \
  22. do { \
  23. if (condition) \
  24. ksft_exit_fail_msg("[FAIL]\t%s:%d\t%s:%s\n", \
  25. __func__, __LINE__, (description), \
  26. strerror(errno)); \
  27. } while (0)
  28. #define TESTS_IN_CHILD 2
  29. static void parent_f(int sock, unsigned long *smap, int child)
  30. {
  31. int status, ret;
  32. ret = read(sock, &status, sizeof(int));
  33. BUG_ON(ret <= 0, "read(sock)");
  34. *smap = 0x22222BAD;
  35. ret = msync(smap, MMAP_SZ, MS_SYNC);
  36. BUG_ON(ret, "msync()");
  37. ret = write(sock, &status, sizeof(int));
  38. BUG_ON(ret <= 0, "write(sock)");
  39. waitpid(child, &status, 0);
  40. /* The ksft macros don't keep counters between processes */
  41. ksft_cnt.ksft_pass = WEXITSTATUS(status);
  42. ksft_cnt.ksft_fail = TESTS_IN_CHILD - WEXITSTATUS(status);
  43. }
  44. static int child_f(int sock, unsigned long *smap, int fd)
  45. {
  46. int ret, buf = 0;
  47. smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
  48. MAP_PRIVATE | MAP_POPULATE, fd, 0);
  49. BUG_ON(smap == MAP_FAILED, "mmap()");
  50. BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file");
  51. ret = write(sock, &buf, sizeof(int));
  52. BUG_ON(ret <= 0, "write(sock)");
  53. ret = read(sock, &buf, sizeof(int));
  54. BUG_ON(ret <= 0, "read(sock)");
  55. ksft_test_result(*smap != 0x22222BAD, "MAP_POPULATE COW private page\n");
  56. ksft_test_result(*smap == 0xdeadbabe, "The mapping state\n");
  57. /* The ksft macros don't keep counters between processes */
  58. return ksft_cnt.ksft_pass;
  59. }
  60. int main(int argc, char **argv)
  61. {
  62. int sock[2], child, ret;
  63. FILE *ftmp;
  64. unsigned long *smap;
  65. ksft_print_header();
  66. ksft_set_plan(TESTS_IN_CHILD);
  67. ftmp = tmpfile();
  68. BUG_ON(!ftmp, "tmpfile()");
  69. ret = ftruncate(fileno(ftmp), MMAP_SZ);
  70. if (ret < 0 && errno == ENOENT) {
  71. skip_test_dodgy_fs("ftruncate()");
  72. }
  73. BUG_ON(ret, "ftruncate()");
  74. smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
  75. MAP_SHARED, fileno(ftmp), 0);
  76. BUG_ON(smap == MAP_FAILED, "mmap()");
  77. *smap = 0xdeadbabe;
  78. /* Probably unnecessary, but let it be. */
  79. ret = msync(smap, MMAP_SZ, MS_SYNC);
  80. BUG_ON(ret, "msync()");
  81. ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock);
  82. BUG_ON(ret, "socketpair()");
  83. child = fork();
  84. BUG_ON(child == -1, "fork()");
  85. if (child) {
  86. ret = close(sock[0]);
  87. BUG_ON(ret, "close()");
  88. parent_f(sock[1], smap, child);
  89. ksft_finished();
  90. }
  91. ret = close(sock[1]);
  92. BUG_ON(ret, "close()");
  93. return child_f(sock[0], smap, fileno(ftmp));
  94. }