map_populate.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. #ifndef MMAP_SZ
  19. #define MMAP_SZ 4096
  20. #endif
  21. #define BUG_ON(condition, description) \
  22. do { \
  23. if (condition) { \
  24. fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \
  25. __LINE__, (description), strerror(errno)); \
  26. exit(1); \
  27. } \
  28. } while (0)
  29. static int 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. BUG_ON(!WIFEXITED(status), "child in unexpected state");
  41. return 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. BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page");
  55. BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted");
  56. return 0;
  57. }
  58. int main(int argc, char **argv)
  59. {
  60. int sock[2], child, ret;
  61. FILE *ftmp;
  62. unsigned long *smap;
  63. ftmp = tmpfile();
  64. BUG_ON(ftmp == 0, "tmpfile()");
  65. ret = ftruncate(fileno(ftmp), MMAP_SZ);
  66. BUG_ON(ret, "ftruncate()");
  67. smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
  68. MAP_SHARED, fileno(ftmp), 0);
  69. BUG_ON(smap == MAP_FAILED, "mmap()");
  70. *smap = 0xdeadbabe;
  71. /* Probably unnecessary, but let it be. */
  72. ret = msync(smap, MMAP_SZ, MS_SYNC);
  73. BUG_ON(ret, "msync()");
  74. ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock);
  75. BUG_ON(ret, "socketpair()");
  76. child = fork();
  77. BUG_ON(child == -1, "fork()");
  78. if (child) {
  79. ret = close(sock[0]);
  80. BUG_ON(ret, "close()");
  81. return parent_f(sock[1], smap, child);
  82. }
  83. ret = close(sock[1]);
  84. BUG_ON(ret, "close()");
  85. return child_f(sock[0], smap, fileno(ftmp));
  86. }