xref: /linux/tools/testing/selftests/mm/map_populate.c (revision 72bea132f3680ee51e7ed2cee62892b6f5121909)
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 #include "../kselftest.h"
20 
21 #define MMAP_SZ		4096
22 
23 #define BUG_ON(condition, description)						\
24 	do {									\
25 		if (condition)							\
26 			ksft_exit_fail_msg("[FAIL]\t%s:%d\t%s:%s\n",		\
27 					   __func__, __LINE__, (description),	\
28 					   strerror(errno));			\
29 	} while (0)
30 
31 #define TESTS_IN_CHILD 2
32 
33 static void 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 
49 	/* The ksft macros don't keep counters between processes */
50 	ksft_cnt.ksft_pass = WEXITSTATUS(status);
51 	ksft_cnt.ksft_fail = TESTS_IN_CHILD - WEXITSTATUS(status);
52 }
53 
54 static int child_f(int sock, unsigned long *smap, int fd)
55 {
56 	int ret, buf = 0;
57 
58 	smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
59 			MAP_PRIVATE | MAP_POPULATE, fd, 0);
60 	BUG_ON(smap == MAP_FAILED, "mmap()");
61 
62 	BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file");
63 
64 	ret = write(sock, &buf, sizeof(int));
65 	BUG_ON(ret <= 0, "write(sock)");
66 
67 	ret = read(sock, &buf, sizeof(int));
68 	BUG_ON(ret <= 0, "read(sock)");
69 
70 	ksft_test_result(*smap != 0x22222BAD, "MAP_POPULATE COW private page\n");
71 	ksft_test_result(*smap == 0xdeadbabe, "The mapping state\n");
72 
73 	/* The ksft macros don't keep counters between processes */
74 	return ksft_cnt.ksft_pass;
75 }
76 
77 int main(int argc, char **argv)
78 {
79 	int sock[2], child, ret;
80 	FILE *ftmp;
81 	unsigned long *smap;
82 
83 	ksft_print_header();
84 	ksft_set_plan(TESTS_IN_CHILD);
85 
86 	ftmp = tmpfile();
87 	BUG_ON(!ftmp, "tmpfile()");
88 
89 	ret = ftruncate(fileno(ftmp), MMAP_SZ);
90 	BUG_ON(ret, "ftruncate()");
91 
92 	smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
93 			MAP_SHARED, fileno(ftmp), 0);
94 	BUG_ON(smap == MAP_FAILED, "mmap()");
95 
96 	*smap = 0xdeadbabe;
97 	/* Probably unnecessary, but let it be. */
98 	ret = msync(smap, MMAP_SZ, MS_SYNC);
99 	BUG_ON(ret, "msync()");
100 
101 	ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock);
102 	BUG_ON(ret, "socketpair()");
103 
104 	child = fork();
105 	BUG_ON(child == -1, "fork()");
106 
107 	if (child) {
108 		ret = close(sock[0]);
109 		BUG_ON(ret, "close()");
110 
111 		parent_f(sock[1], smap, child);
112 
113 		ksft_finished();
114 	}
115 
116 	ret = close(sock[1]);
117 	BUG_ON(ret, "close()");
118 
119 	return child_f(sock[0], smap, fileno(ftmp));
120 }
121