xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/vm/mremap_dontunmap.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun  * Tests for mremap w/ MREMAP_DONTUNMAP.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2020, Brian Geffon <bgeffon@google.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #define _GNU_SOURCE
9*4882a593Smuzhiyun #include <sys/mman.h>
10*4882a593Smuzhiyun #include <errno.h>
11*4882a593Smuzhiyun #include <stdio.h>
12*4882a593Smuzhiyun #include <stdlib.h>
13*4882a593Smuzhiyun #include <string.h>
14*4882a593Smuzhiyun #include <unistd.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "../kselftest.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #ifndef MREMAP_DONTUNMAP
19*4882a593Smuzhiyun #define MREMAP_DONTUNMAP 4
20*4882a593Smuzhiyun #endif
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun unsigned long page_size;
23*4882a593Smuzhiyun char *page_buffer;
24*4882a593Smuzhiyun 
dump_maps(void)25*4882a593Smuzhiyun static void dump_maps(void)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	char cmd[32];
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid());
30*4882a593Smuzhiyun 	system(cmd);
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define BUG_ON(condition, description)					      \
34*4882a593Smuzhiyun 	do {								      \
35*4882a593Smuzhiyun 		if (condition) {					      \
36*4882a593Smuzhiyun 			fprintf(stderr, "[FAIL]\t%s():%d\t%s:%s\n", __func__, \
37*4882a593Smuzhiyun 				__LINE__, (description), strerror(errno));    \
38*4882a593Smuzhiyun 			dump_maps();					  \
39*4882a593Smuzhiyun 			exit(1);					      \
40*4882a593Smuzhiyun 		} 							      \
41*4882a593Smuzhiyun 	} while (0)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun // Try a simple operation for to "test" for kernel support this prevents
44*4882a593Smuzhiyun // reporting tests as failed when it's run on an older kernel.
kernel_support_for_mremap_dontunmap()45*4882a593Smuzhiyun static int kernel_support_for_mremap_dontunmap()
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	int ret = 0;
48*4882a593Smuzhiyun 	unsigned long num_pages = 1;
49*4882a593Smuzhiyun 	void *source_mapping = mmap(NULL, num_pages * page_size, PROT_NONE,
50*4882a593Smuzhiyun 				    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
51*4882a593Smuzhiyun 	BUG_ON(source_mapping == MAP_FAILED, "mmap");
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	// This simple remap should only fail if MREMAP_DONTUNMAP isn't
54*4882a593Smuzhiyun 	// supported.
55*4882a593Smuzhiyun 	void *dest_mapping =
56*4882a593Smuzhiyun 	    mremap(source_mapping, num_pages * page_size, num_pages * page_size,
57*4882a593Smuzhiyun 		   MREMAP_DONTUNMAP | MREMAP_MAYMOVE, 0);
58*4882a593Smuzhiyun 	if (dest_mapping == MAP_FAILED) {
59*4882a593Smuzhiyun 		ret = errno;
60*4882a593Smuzhiyun 	} else {
61*4882a593Smuzhiyun 		BUG_ON(munmap(dest_mapping, num_pages * page_size) == -1,
62*4882a593Smuzhiyun 		       "unable to unmap destination mapping");
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
66*4882a593Smuzhiyun 	       "unable to unmap source mapping");
67*4882a593Smuzhiyun 	return ret;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun // This helper will just validate that an entire mapping contains the expected
71*4882a593Smuzhiyun // byte.
check_region_contains_byte(void * addr,unsigned long size,char byte)72*4882a593Smuzhiyun static int check_region_contains_byte(void *addr, unsigned long size, char byte)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	BUG_ON(size & (page_size - 1),
75*4882a593Smuzhiyun 	       "check_region_contains_byte expects page multiples");
76*4882a593Smuzhiyun 	BUG_ON((unsigned long)addr & (page_size - 1),
77*4882a593Smuzhiyun 	       "check_region_contains_byte expects page alignment");
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	memset(page_buffer, byte, page_size);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	unsigned long num_pages = size / page_size;
82*4882a593Smuzhiyun 	unsigned long i;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	// Compare each page checking that it contains our expected byte.
85*4882a593Smuzhiyun 	for (i = 0; i < num_pages; ++i) {
86*4882a593Smuzhiyun 		int ret =
87*4882a593Smuzhiyun 		    memcmp(addr + (i * page_size), page_buffer, page_size);
88*4882a593Smuzhiyun 		if (ret) {
89*4882a593Smuzhiyun 			return ret;
90*4882a593Smuzhiyun 		}
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun // this test validates that MREMAP_DONTUNMAP moves the pagetables while leaving
97*4882a593Smuzhiyun // the source mapping mapped.
mremap_dontunmap_simple()98*4882a593Smuzhiyun static void mremap_dontunmap_simple()
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	unsigned long num_pages = 5;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	void *source_mapping =
103*4882a593Smuzhiyun 	    mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE,
104*4882a593Smuzhiyun 		 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
105*4882a593Smuzhiyun 	BUG_ON(source_mapping == MAP_FAILED, "mmap");
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	memset(source_mapping, 'a', num_pages * page_size);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	// Try to just move the whole mapping anywhere (not fixed).
110*4882a593Smuzhiyun 	void *dest_mapping =
111*4882a593Smuzhiyun 	    mremap(source_mapping, num_pages * page_size, num_pages * page_size,
112*4882a593Smuzhiyun 		   MREMAP_DONTUNMAP | MREMAP_MAYMOVE, NULL);
113*4882a593Smuzhiyun 	BUG_ON(dest_mapping == MAP_FAILED, "mremap");
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	// Validate that the pages have been moved, we know they were moved if
116*4882a593Smuzhiyun 	// the dest_mapping contains a's.
117*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte
118*4882a593Smuzhiyun 	       (dest_mapping, num_pages * page_size, 'a') != 0,
119*4882a593Smuzhiyun 	       "pages did not migrate");
120*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte
121*4882a593Smuzhiyun 	       (source_mapping, num_pages * page_size, 0) != 0,
122*4882a593Smuzhiyun 	       "source should have no ptes");
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	BUG_ON(munmap(dest_mapping, num_pages * page_size) == -1,
125*4882a593Smuzhiyun 	       "unable to unmap destination mapping");
126*4882a593Smuzhiyun 	BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
127*4882a593Smuzhiyun 	       "unable to unmap source mapping");
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun // This test validates that MREMAP_DONTUNMAP on a shared mapping works as expected.
mremap_dontunmap_simple_shmem()131*4882a593Smuzhiyun static void mremap_dontunmap_simple_shmem()
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	unsigned long num_pages = 5;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	int mem_fd = memfd_create("memfd", MFD_CLOEXEC);
136*4882a593Smuzhiyun 	BUG_ON(mem_fd < 0, "memfd_create");
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	BUG_ON(ftruncate(mem_fd, num_pages * page_size) < 0,
139*4882a593Smuzhiyun 			"ftruncate");
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	void *source_mapping =
142*4882a593Smuzhiyun 	    mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE,
143*4882a593Smuzhiyun 		 MAP_FILE | MAP_SHARED, mem_fd, 0);
144*4882a593Smuzhiyun 	BUG_ON(source_mapping == MAP_FAILED, "mmap");
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	BUG_ON(close(mem_fd) < 0, "close");
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	memset(source_mapping, 'a', num_pages * page_size);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	// Try to just move the whole mapping anywhere (not fixed).
151*4882a593Smuzhiyun 	void *dest_mapping =
152*4882a593Smuzhiyun 	    mremap(source_mapping, num_pages * page_size, num_pages * page_size,
153*4882a593Smuzhiyun 		   MREMAP_DONTUNMAP | MREMAP_MAYMOVE, NULL);
154*4882a593Smuzhiyun 	if (dest_mapping == MAP_FAILED && errno == EINVAL) {
155*4882a593Smuzhiyun 		// Old kernel which doesn't support MREMAP_DONTUNMAP on shmem.
156*4882a593Smuzhiyun 		BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
157*4882a593Smuzhiyun 			"unable to unmap source mapping");
158*4882a593Smuzhiyun 		return;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	BUG_ON(dest_mapping == MAP_FAILED, "mremap");
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	// Validate that the pages have been moved, we know they were moved if
164*4882a593Smuzhiyun 	// the dest_mapping contains a's.
165*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte
166*4882a593Smuzhiyun 	       (dest_mapping, num_pages * page_size, 'a') != 0,
167*4882a593Smuzhiyun 	       "pages did not migrate");
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	// Because the region is backed by shmem, we will actually see the same
170*4882a593Smuzhiyun 	// memory at the source location still.
171*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte
172*4882a593Smuzhiyun 	       (source_mapping, num_pages * page_size, 'a') != 0,
173*4882a593Smuzhiyun 	       "source should have no ptes");
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	BUG_ON(munmap(dest_mapping, num_pages * page_size) == -1,
176*4882a593Smuzhiyun 	       "unable to unmap destination mapping");
177*4882a593Smuzhiyun 	BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
178*4882a593Smuzhiyun 	       "unable to unmap source mapping");
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun // This test validates MREMAP_DONTUNMAP will move page tables to a specific
182*4882a593Smuzhiyun // destination using MREMAP_FIXED, also while validating that the source
183*4882a593Smuzhiyun // remains intact.
mremap_dontunmap_simple_fixed()184*4882a593Smuzhiyun static void mremap_dontunmap_simple_fixed()
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	unsigned long num_pages = 5;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	// Since we want to guarantee that we can remap to a point, we will
189*4882a593Smuzhiyun 	// create a mapping up front.
190*4882a593Smuzhiyun 	void *dest_mapping =
191*4882a593Smuzhiyun 	    mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE,
192*4882a593Smuzhiyun 		 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
193*4882a593Smuzhiyun 	BUG_ON(dest_mapping == MAP_FAILED, "mmap");
194*4882a593Smuzhiyun 	memset(dest_mapping, 'X', num_pages * page_size);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	void *source_mapping =
197*4882a593Smuzhiyun 	    mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE,
198*4882a593Smuzhiyun 		 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
199*4882a593Smuzhiyun 	BUG_ON(source_mapping == MAP_FAILED, "mmap");
200*4882a593Smuzhiyun 	memset(source_mapping, 'a', num_pages * page_size);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	void *remapped_mapping =
203*4882a593Smuzhiyun 	    mremap(source_mapping, num_pages * page_size, num_pages * page_size,
204*4882a593Smuzhiyun 		   MREMAP_FIXED | MREMAP_DONTUNMAP | MREMAP_MAYMOVE,
205*4882a593Smuzhiyun 		   dest_mapping);
206*4882a593Smuzhiyun 	BUG_ON(remapped_mapping == MAP_FAILED, "mremap");
207*4882a593Smuzhiyun 	BUG_ON(remapped_mapping != dest_mapping,
208*4882a593Smuzhiyun 	       "mremap should have placed the remapped mapping at dest_mapping");
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	// The dest mapping will have been unmap by mremap so we expect the Xs
211*4882a593Smuzhiyun 	// to be gone and replaced with a's.
212*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte
213*4882a593Smuzhiyun 	       (dest_mapping, num_pages * page_size, 'a') != 0,
214*4882a593Smuzhiyun 	       "pages did not migrate");
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	// And the source mapping will have had its ptes dropped.
217*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte
218*4882a593Smuzhiyun 	       (source_mapping, num_pages * page_size, 0) != 0,
219*4882a593Smuzhiyun 	       "source should have no ptes");
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	BUG_ON(munmap(dest_mapping, num_pages * page_size) == -1,
222*4882a593Smuzhiyun 	       "unable to unmap destination mapping");
223*4882a593Smuzhiyun 	BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
224*4882a593Smuzhiyun 	       "unable to unmap source mapping");
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun // This test validates that we can MREMAP_DONTUNMAP for a portion of an
228*4882a593Smuzhiyun // existing mapping.
mremap_dontunmap_partial_mapping()229*4882a593Smuzhiyun static void mremap_dontunmap_partial_mapping()
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	/*
232*4882a593Smuzhiyun 	 *  source mapping:
233*4882a593Smuzhiyun 	 *  --------------
234*4882a593Smuzhiyun 	 *  | aaaaaaaaaa |
235*4882a593Smuzhiyun 	 *  --------------
236*4882a593Smuzhiyun 	 *  to become:
237*4882a593Smuzhiyun 	 *  --------------
238*4882a593Smuzhiyun 	 *  | aaaaa00000 |
239*4882a593Smuzhiyun 	 *  --------------
240*4882a593Smuzhiyun 	 *  With the destination mapping containing 5 pages of As.
241*4882a593Smuzhiyun 	 *  ---------
242*4882a593Smuzhiyun 	 *  | aaaaa |
243*4882a593Smuzhiyun 	 *  ---------
244*4882a593Smuzhiyun 	 */
245*4882a593Smuzhiyun 	unsigned long num_pages = 10;
246*4882a593Smuzhiyun 	void *source_mapping =
247*4882a593Smuzhiyun 	    mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE,
248*4882a593Smuzhiyun 		 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
249*4882a593Smuzhiyun 	BUG_ON(source_mapping == MAP_FAILED, "mmap");
250*4882a593Smuzhiyun 	memset(source_mapping, 'a', num_pages * page_size);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	// We will grab the last 5 pages of the source and move them.
253*4882a593Smuzhiyun 	void *dest_mapping =
254*4882a593Smuzhiyun 	    mremap(source_mapping + (5 * page_size), 5 * page_size,
255*4882a593Smuzhiyun 		   5 * page_size,
256*4882a593Smuzhiyun 		   MREMAP_DONTUNMAP | MREMAP_MAYMOVE, NULL);
257*4882a593Smuzhiyun 	BUG_ON(dest_mapping == MAP_FAILED, "mremap");
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	// We expect the first 5 pages of the source to contain a's and the
260*4882a593Smuzhiyun 	// final 5 pages to contain zeros.
261*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte(source_mapping, 5 * page_size, 'a') !=
262*4882a593Smuzhiyun 	       0, "first 5 pages of source should have original pages");
263*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte
264*4882a593Smuzhiyun 	       (source_mapping + (5 * page_size), 5 * page_size, 0) != 0,
265*4882a593Smuzhiyun 	       "final 5 pages of source should have no ptes");
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	// Finally we expect the destination to have 5 pages worth of a's.
268*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte(dest_mapping, 5 * page_size, 'a') !=
269*4882a593Smuzhiyun 	       0, "dest mapping should contain ptes from the source");
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	BUG_ON(munmap(dest_mapping, 5 * page_size) == -1,
272*4882a593Smuzhiyun 	       "unable to unmap destination mapping");
273*4882a593Smuzhiyun 	BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
274*4882a593Smuzhiyun 	       "unable to unmap source mapping");
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun // This test validates that we can remap over only a portion of a mapping.
mremap_dontunmap_partial_mapping_overwrite(void)278*4882a593Smuzhiyun static void mremap_dontunmap_partial_mapping_overwrite(void)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	/*
281*4882a593Smuzhiyun 	 *  source mapping:
282*4882a593Smuzhiyun 	 *  ---------
283*4882a593Smuzhiyun 	 *  |aaaaa|
284*4882a593Smuzhiyun 	 *  ---------
285*4882a593Smuzhiyun 	 *  dest mapping initially:
286*4882a593Smuzhiyun 	 *  -----------
287*4882a593Smuzhiyun 	 *  |XXXXXXXXXX|
288*4882a593Smuzhiyun 	 *  ------------
289*4882a593Smuzhiyun 	 *  Source to become:
290*4882a593Smuzhiyun 	 *  ---------
291*4882a593Smuzhiyun 	 *  |00000|
292*4882a593Smuzhiyun 	 *  ---------
293*4882a593Smuzhiyun 	 *  With the destination mapping containing 5 pages of As.
294*4882a593Smuzhiyun 	 *  ------------
295*4882a593Smuzhiyun 	 *  |aaaaaXXXXX|
296*4882a593Smuzhiyun 	 *  ------------
297*4882a593Smuzhiyun 	 */
298*4882a593Smuzhiyun 	void *source_mapping =
299*4882a593Smuzhiyun 	    mmap(NULL, 5 * page_size, PROT_READ | PROT_WRITE,
300*4882a593Smuzhiyun 		 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
301*4882a593Smuzhiyun 	BUG_ON(source_mapping == MAP_FAILED, "mmap");
302*4882a593Smuzhiyun 	memset(source_mapping, 'a', 5 * page_size);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	void *dest_mapping =
305*4882a593Smuzhiyun 	    mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
306*4882a593Smuzhiyun 		 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
307*4882a593Smuzhiyun 	BUG_ON(dest_mapping == MAP_FAILED, "mmap");
308*4882a593Smuzhiyun 	memset(dest_mapping, 'X', 10 * page_size);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	// We will grab the last 5 pages of the source and move them.
311*4882a593Smuzhiyun 	void *remapped_mapping =
312*4882a593Smuzhiyun 	    mremap(source_mapping, 5 * page_size,
313*4882a593Smuzhiyun 		   5 * page_size,
314*4882a593Smuzhiyun 		   MREMAP_DONTUNMAP | MREMAP_MAYMOVE | MREMAP_FIXED, dest_mapping);
315*4882a593Smuzhiyun 	BUG_ON(dest_mapping == MAP_FAILED, "mremap");
316*4882a593Smuzhiyun 	BUG_ON(dest_mapping != remapped_mapping, "expected to remap to dest_mapping");
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte(source_mapping, 5 * page_size, 0) !=
319*4882a593Smuzhiyun 	       0, "first 5 pages of source should have no ptes");
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	// Finally we expect the destination to have 5 pages worth of a's.
322*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte(dest_mapping, 5 * page_size, 'a') != 0,
323*4882a593Smuzhiyun 			"dest mapping should contain ptes from the source");
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	// Finally the last 5 pages shouldn't have been touched.
326*4882a593Smuzhiyun 	BUG_ON(check_region_contains_byte(dest_mapping + (5 * page_size),
327*4882a593Smuzhiyun 				5 * page_size, 'X') != 0,
328*4882a593Smuzhiyun 			"dest mapping should have retained the last 5 pages");
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	BUG_ON(munmap(dest_mapping, 10 * page_size) == -1,
331*4882a593Smuzhiyun 	       "unable to unmap destination mapping");
332*4882a593Smuzhiyun 	BUG_ON(munmap(source_mapping, 5 * page_size) == -1,
333*4882a593Smuzhiyun 	       "unable to unmap source mapping");
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
main(void)336*4882a593Smuzhiyun int main(void)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	page_size = sysconf(_SC_PAGE_SIZE);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	// test for kernel support for MREMAP_DONTUNMAP skipping the test if
341*4882a593Smuzhiyun 	// not.
342*4882a593Smuzhiyun 	if (kernel_support_for_mremap_dontunmap() != 0) {
343*4882a593Smuzhiyun 		printf("No kernel support for MREMAP_DONTUNMAP\n");
344*4882a593Smuzhiyun 		return KSFT_SKIP;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	// Keep a page sized buffer around for when we need it.
348*4882a593Smuzhiyun 	page_buffer =
349*4882a593Smuzhiyun 	    mmap(NULL, page_size, PROT_READ | PROT_WRITE,
350*4882a593Smuzhiyun 		 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
351*4882a593Smuzhiyun 	BUG_ON(page_buffer == MAP_FAILED, "unable to mmap a page.");
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	mremap_dontunmap_simple();
354*4882a593Smuzhiyun 	mremap_dontunmap_simple_shmem();
355*4882a593Smuzhiyun 	mremap_dontunmap_simple_fixed();
356*4882a593Smuzhiyun 	mremap_dontunmap_partial_mapping();
357*4882a593Smuzhiyun 	mremap_dontunmap_partial_mapping_overwrite();
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	BUG_ON(munmap(page_buffer, page_size) == -1,
360*4882a593Smuzhiyun 	       "unable to unmap page buffer");
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	printf("OK\n");
363*4882a593Smuzhiyun 	return 0;
364*4882a593Smuzhiyun }
365