Linux-libre 5.3-gnu
[librecmc/linux-libre.git] / tools / testing / selftests / vm / map_populate.c
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
8 #define _GNU_SOURCE
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <sys/mman.h>
12 #include <sys/socket.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #ifndef MMAP_SZ
21 #define MMAP_SZ         4096
22 #endif
23
24 #define BUG_ON(condition, description)                                  \
25         do {                                                            \
26                 if (condition) {                                        \
27                         fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \
28                                 __LINE__, (description), strerror(errno)); \
29                         exit(1);                                        \
30                 }                                                       \
31         } while (0)
32
33 static int parent_f(int sock, unsigned long *smap, int child)
34 {
35         int status, ret;
36
37         ret = read(sock, &status, sizeof(int));
38         BUG_ON(ret <= 0, "read(sock)");
39
40         *smap = 0x22222BAD;
41         ret = msync(smap, MMAP_SZ, MS_SYNC);
42         BUG_ON(ret, "msync()");
43
44         ret = write(sock, &status, sizeof(int));
45         BUG_ON(ret <= 0, "write(sock)");
46
47         waitpid(child, &status, 0);
48         BUG_ON(!WIFEXITED(status), "child in unexpected state");
49
50         return WEXITSTATUS(status);
51 }
52
53 static int child_f(int sock, unsigned long *smap, int fd)
54 {
55         int ret, buf = 0;
56
57         smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
58                         MAP_PRIVATE | MAP_POPULATE, fd, 0);
59         BUG_ON(smap == MAP_FAILED, "mmap()");
60
61         BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file");
62
63         ret = write(sock, &buf, sizeof(int));
64         BUG_ON(ret <= 0, "write(sock)");
65
66         ret = read(sock, &buf, sizeof(int));
67         BUG_ON(ret <= 0, "read(sock)");
68
69         BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page");
70         BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted");
71
72         return 0;
73 }
74
75 int main(int argc, char **argv)
76 {
77         int sock[2], child, ret;
78         FILE *ftmp;
79         unsigned long *smap;
80
81         ftmp = tmpfile();
82         BUG_ON(ftmp == 0, "tmpfile()");
83
84         ret = ftruncate(fileno(ftmp), MMAP_SZ);
85         BUG_ON(ret, "ftruncate()");
86
87         smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
88                         MAP_SHARED, fileno(ftmp), 0);
89         BUG_ON(smap == MAP_FAILED, "mmap()");
90
91         *smap = 0xdeadbabe;
92         /* Probably unnecessary, but let it be. */
93         ret = msync(smap, MMAP_SZ, MS_SYNC);
94         BUG_ON(ret, "msync()");
95
96         ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock);
97         BUG_ON(ret, "socketpair()");
98
99         child = fork();
100         BUG_ON(child == -1, "fork()");
101
102         if (child) {
103                 ret = close(sock[0]);
104                 BUG_ON(ret, "close()");
105
106                 return parent_f(sock[1], smap, child);
107         }
108
109         ret = close(sock[1]);
110         BUG_ON(ret, "close()");
111
112         return child_f(sock[0], smap, fileno(ftmp));
113 }