xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/vm/mlock2-tests.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE
3*053f45beSAndroid Build Coastguard Worker #include <sys/mman.h>
4*053f45beSAndroid Build Coastguard Worker #include <stdint.h>
5*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
6*053f45beSAndroid Build Coastguard Worker #include <string.h>
7*053f45beSAndroid Build Coastguard Worker #include <sys/time.h>
8*053f45beSAndroid Build Coastguard Worker #include <sys/resource.h>
9*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
10*053f45beSAndroid Build Coastguard Worker #include "mlock2.h"
11*053f45beSAndroid Build Coastguard Worker 
12*053f45beSAndroid Build Coastguard Worker #include "../kselftest.h"
13*053f45beSAndroid Build Coastguard Worker 
14*053f45beSAndroid Build Coastguard Worker struct vm_boundaries {
15*053f45beSAndroid Build Coastguard Worker 	unsigned long start;
16*053f45beSAndroid Build Coastguard Worker 	unsigned long end;
17*053f45beSAndroid Build Coastguard Worker };
18*053f45beSAndroid Build Coastguard Worker 
get_vm_area(unsigned long addr,struct vm_boundaries * area)19*053f45beSAndroid Build Coastguard Worker static int get_vm_area(unsigned long addr, struct vm_boundaries *area)
20*053f45beSAndroid Build Coastguard Worker {
21*053f45beSAndroid Build Coastguard Worker 	FILE *file;
22*053f45beSAndroid Build Coastguard Worker 	int ret = 1;
23*053f45beSAndroid Build Coastguard Worker 	char line[1024] = {0};
24*053f45beSAndroid Build Coastguard Worker 	char *end_addr;
25*053f45beSAndroid Build Coastguard Worker 	char *stop;
26*053f45beSAndroid Build Coastguard Worker 	unsigned long start;
27*053f45beSAndroid Build Coastguard Worker 	unsigned long end;
28*053f45beSAndroid Build Coastguard Worker 
29*053f45beSAndroid Build Coastguard Worker 	if (!area)
30*053f45beSAndroid Build Coastguard Worker 		return ret;
31*053f45beSAndroid Build Coastguard Worker 
32*053f45beSAndroid Build Coastguard Worker 	file = fopen("/proc/self/maps", "r");
33*053f45beSAndroid Build Coastguard Worker 	if (!file) {
34*053f45beSAndroid Build Coastguard Worker 		perror("fopen");
35*053f45beSAndroid Build Coastguard Worker 		return ret;
36*053f45beSAndroid Build Coastguard Worker 	}
37*053f45beSAndroid Build Coastguard Worker 
38*053f45beSAndroid Build Coastguard Worker 	memset(area, 0, sizeof(struct vm_boundaries));
39*053f45beSAndroid Build Coastguard Worker 
40*053f45beSAndroid Build Coastguard Worker 	while(fgets(line, 1024, file)) {
41*053f45beSAndroid Build Coastguard Worker 		end_addr = strchr(line, '-');
42*053f45beSAndroid Build Coastguard Worker 		if (!end_addr) {
43*053f45beSAndroid Build Coastguard Worker 			printf("cannot parse /proc/self/maps\n");
44*053f45beSAndroid Build Coastguard Worker 			goto out;
45*053f45beSAndroid Build Coastguard Worker 		}
46*053f45beSAndroid Build Coastguard Worker 		*end_addr = '\0';
47*053f45beSAndroid Build Coastguard Worker 		end_addr++;
48*053f45beSAndroid Build Coastguard Worker 		stop = strchr(end_addr, ' ');
49*053f45beSAndroid Build Coastguard Worker 		if (!stop) {
50*053f45beSAndroid Build Coastguard Worker 			printf("cannot parse /proc/self/maps\n");
51*053f45beSAndroid Build Coastguard Worker 			goto out;
52*053f45beSAndroid Build Coastguard Worker 		}
53*053f45beSAndroid Build Coastguard Worker 		stop = '\0';
54*053f45beSAndroid Build Coastguard Worker 
55*053f45beSAndroid Build Coastguard Worker 		sscanf(line, "%lx", &start);
56*053f45beSAndroid Build Coastguard Worker 		sscanf(end_addr, "%lx", &end);
57*053f45beSAndroid Build Coastguard Worker 
58*053f45beSAndroid Build Coastguard Worker 		if (start <= addr && end > addr) {
59*053f45beSAndroid Build Coastguard Worker 			area->start = start;
60*053f45beSAndroid Build Coastguard Worker 			area->end = end;
61*053f45beSAndroid Build Coastguard Worker 			ret = 0;
62*053f45beSAndroid Build Coastguard Worker 			goto out;
63*053f45beSAndroid Build Coastguard Worker 		}
64*053f45beSAndroid Build Coastguard Worker 	}
65*053f45beSAndroid Build Coastguard Worker out:
66*053f45beSAndroid Build Coastguard Worker 	fclose(file);
67*053f45beSAndroid Build Coastguard Worker 	return ret;
68*053f45beSAndroid Build Coastguard Worker }
69*053f45beSAndroid Build Coastguard Worker 
70*053f45beSAndroid Build Coastguard Worker #define VMFLAGS "VmFlags:"
71*053f45beSAndroid Build Coastguard Worker 
is_vmflag_set(unsigned long addr,const char * vmflag)72*053f45beSAndroid Build Coastguard Worker static bool is_vmflag_set(unsigned long addr, const char *vmflag)
73*053f45beSAndroid Build Coastguard Worker {
74*053f45beSAndroid Build Coastguard Worker 	char *line = NULL;
75*053f45beSAndroid Build Coastguard Worker 	char *flags;
76*053f45beSAndroid Build Coastguard Worker 	size_t size = 0;
77*053f45beSAndroid Build Coastguard Worker 	bool ret = false;
78*053f45beSAndroid Build Coastguard Worker 	FILE *smaps;
79*053f45beSAndroid Build Coastguard Worker 
80*053f45beSAndroid Build Coastguard Worker 	smaps = seek_to_smaps_entry(addr);
81*053f45beSAndroid Build Coastguard Worker 	if (!smaps) {
82*053f45beSAndroid Build Coastguard Worker 		printf("Unable to parse /proc/self/smaps\n");
83*053f45beSAndroid Build Coastguard Worker 		goto out;
84*053f45beSAndroid Build Coastguard Worker 	}
85*053f45beSAndroid Build Coastguard Worker 
86*053f45beSAndroid Build Coastguard Worker 	while (getline(&line, &size, smaps) > 0) {
87*053f45beSAndroid Build Coastguard Worker 		if (!strstr(line, VMFLAGS)) {
88*053f45beSAndroid Build Coastguard Worker 			free(line);
89*053f45beSAndroid Build Coastguard Worker 			line = NULL;
90*053f45beSAndroid Build Coastguard Worker 			size = 0;
91*053f45beSAndroid Build Coastguard Worker 			continue;
92*053f45beSAndroid Build Coastguard Worker 		}
93*053f45beSAndroid Build Coastguard Worker 
94*053f45beSAndroid Build Coastguard Worker 		flags = line + strlen(VMFLAGS);
95*053f45beSAndroid Build Coastguard Worker 		ret = (strstr(flags, vmflag) != NULL);
96*053f45beSAndroid Build Coastguard Worker 		goto out;
97*053f45beSAndroid Build Coastguard Worker 	}
98*053f45beSAndroid Build Coastguard Worker 
99*053f45beSAndroid Build Coastguard Worker out:
100*053f45beSAndroid Build Coastguard Worker 	free(line);
101*053f45beSAndroid Build Coastguard Worker 	fclose(smaps);
102*053f45beSAndroid Build Coastguard Worker 	return ret;
103*053f45beSAndroid Build Coastguard Worker }
104*053f45beSAndroid Build Coastguard Worker 
105*053f45beSAndroid Build Coastguard Worker #define SIZE "Size:"
106*053f45beSAndroid Build Coastguard Worker #define RSS  "Rss:"
107*053f45beSAndroid Build Coastguard Worker #define LOCKED "lo"
108*053f45beSAndroid Build Coastguard Worker 
get_value_for_name(unsigned long addr,const char * name)109*053f45beSAndroid Build Coastguard Worker static unsigned long get_value_for_name(unsigned long addr, const char *name)
110*053f45beSAndroid Build Coastguard Worker {
111*053f45beSAndroid Build Coastguard Worker 	char *line = NULL;
112*053f45beSAndroid Build Coastguard Worker 	size_t size = 0;
113*053f45beSAndroid Build Coastguard Worker 	char *value_ptr;
114*053f45beSAndroid Build Coastguard Worker 	FILE *smaps = NULL;
115*053f45beSAndroid Build Coastguard Worker 	unsigned long value = -1UL;
116*053f45beSAndroid Build Coastguard Worker 
117*053f45beSAndroid Build Coastguard Worker 	smaps = seek_to_smaps_entry(addr);
118*053f45beSAndroid Build Coastguard Worker 	if (!smaps) {
119*053f45beSAndroid Build Coastguard Worker 		printf("Unable to parse /proc/self/smaps\n");
120*053f45beSAndroid Build Coastguard Worker 		goto out;
121*053f45beSAndroid Build Coastguard Worker 	}
122*053f45beSAndroid Build Coastguard Worker 
123*053f45beSAndroid Build Coastguard Worker 	while (getline(&line, &size, smaps) > 0) {
124*053f45beSAndroid Build Coastguard Worker 		if (!strstr(line, name)) {
125*053f45beSAndroid Build Coastguard Worker 			free(line);
126*053f45beSAndroid Build Coastguard Worker 			line = NULL;
127*053f45beSAndroid Build Coastguard Worker 			size = 0;
128*053f45beSAndroid Build Coastguard Worker 			continue;
129*053f45beSAndroid Build Coastguard Worker 		}
130*053f45beSAndroid Build Coastguard Worker 
131*053f45beSAndroid Build Coastguard Worker 		value_ptr = line + strlen(name);
132*053f45beSAndroid Build Coastguard Worker 		if (sscanf(value_ptr, "%lu kB", &value) < 1) {
133*053f45beSAndroid Build Coastguard Worker 			printf("Unable to parse smaps entry for Size\n");
134*053f45beSAndroid Build Coastguard Worker 			goto out;
135*053f45beSAndroid Build Coastguard Worker 		}
136*053f45beSAndroid Build Coastguard Worker 		break;
137*053f45beSAndroid Build Coastguard Worker 	}
138*053f45beSAndroid Build Coastguard Worker 
139*053f45beSAndroid Build Coastguard Worker out:
140*053f45beSAndroid Build Coastguard Worker 	if (smaps)
141*053f45beSAndroid Build Coastguard Worker 		fclose(smaps);
142*053f45beSAndroid Build Coastguard Worker 	free(line);
143*053f45beSAndroid Build Coastguard Worker 	return value;
144*053f45beSAndroid Build Coastguard Worker }
145*053f45beSAndroid Build Coastguard Worker 
is_vma_lock_on_fault(unsigned long addr)146*053f45beSAndroid Build Coastguard Worker static bool is_vma_lock_on_fault(unsigned long addr)
147*053f45beSAndroid Build Coastguard Worker {
148*053f45beSAndroid Build Coastguard Worker 	bool locked;
149*053f45beSAndroid Build Coastguard Worker 	unsigned long vma_size, vma_rss;
150*053f45beSAndroid Build Coastguard Worker 
151*053f45beSAndroid Build Coastguard Worker 	locked = is_vmflag_set(addr, LOCKED);
152*053f45beSAndroid Build Coastguard Worker 	if (!locked)
153*053f45beSAndroid Build Coastguard Worker 		return false;
154*053f45beSAndroid Build Coastguard Worker 
155*053f45beSAndroid Build Coastguard Worker 	vma_size = get_value_for_name(addr, SIZE);
156*053f45beSAndroid Build Coastguard Worker 	vma_rss = get_value_for_name(addr, RSS);
157*053f45beSAndroid Build Coastguard Worker 
158*053f45beSAndroid Build Coastguard Worker 	/* only one page is faulted in */
159*053f45beSAndroid Build Coastguard Worker 	return (vma_rss < vma_size);
160*053f45beSAndroid Build Coastguard Worker }
161*053f45beSAndroid Build Coastguard Worker 
162*053f45beSAndroid Build Coastguard Worker #define PRESENT_BIT     0x8000000000000000ULL
163*053f45beSAndroid Build Coastguard Worker #define PFN_MASK        0x007FFFFFFFFFFFFFULL
164*053f45beSAndroid Build Coastguard Worker #define UNEVICTABLE_BIT (1UL << 18)
165*053f45beSAndroid Build Coastguard Worker 
lock_check(unsigned long addr)166*053f45beSAndroid Build Coastguard Worker static int lock_check(unsigned long addr)
167*053f45beSAndroid Build Coastguard Worker {
168*053f45beSAndroid Build Coastguard Worker 	bool locked;
169*053f45beSAndroid Build Coastguard Worker 	unsigned long vma_size, vma_rss;
170*053f45beSAndroid Build Coastguard Worker 
171*053f45beSAndroid Build Coastguard Worker 	locked = is_vmflag_set(addr, LOCKED);
172*053f45beSAndroid Build Coastguard Worker 	if (!locked)
173*053f45beSAndroid Build Coastguard Worker 		return false;
174*053f45beSAndroid Build Coastguard Worker 
175*053f45beSAndroid Build Coastguard Worker 	vma_size = get_value_for_name(addr, SIZE);
176*053f45beSAndroid Build Coastguard Worker 	vma_rss = get_value_for_name(addr, RSS);
177*053f45beSAndroid Build Coastguard Worker 
178*053f45beSAndroid Build Coastguard Worker 	return (vma_rss == vma_size);
179*053f45beSAndroid Build Coastguard Worker }
180*053f45beSAndroid Build Coastguard Worker 
unlock_lock_check(char * map)181*053f45beSAndroid Build Coastguard Worker static int unlock_lock_check(char *map)
182*053f45beSAndroid Build Coastguard Worker {
183*053f45beSAndroid Build Coastguard Worker 	if (is_vmflag_set((unsigned long)map, LOCKED)) {
184*053f45beSAndroid Build Coastguard Worker 		printf("VMA flag %s is present on page 1 after unlock\n", LOCKED);
185*053f45beSAndroid Build Coastguard Worker 		return 1;
186*053f45beSAndroid Build Coastguard Worker 	}
187*053f45beSAndroid Build Coastguard Worker 
188*053f45beSAndroid Build Coastguard Worker 	return 0;
189*053f45beSAndroid Build Coastguard Worker }
190*053f45beSAndroid Build Coastguard Worker 
test_mlock_lock()191*053f45beSAndroid Build Coastguard Worker static int test_mlock_lock()
192*053f45beSAndroid Build Coastguard Worker {
193*053f45beSAndroid Build Coastguard Worker 	char *map;
194*053f45beSAndroid Build Coastguard Worker 	int ret = 1;
195*053f45beSAndroid Build Coastguard Worker 	unsigned long page_size = getpagesize();
196*053f45beSAndroid Build Coastguard Worker 
197*053f45beSAndroid Build Coastguard Worker 	map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
198*053f45beSAndroid Build Coastguard Worker 		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
199*053f45beSAndroid Build Coastguard Worker 	if (map == MAP_FAILED) {
200*053f45beSAndroid Build Coastguard Worker 		perror("test_mlock_locked mmap");
201*053f45beSAndroid Build Coastguard Worker 		goto out;
202*053f45beSAndroid Build Coastguard Worker 	}
203*053f45beSAndroid Build Coastguard Worker 
204*053f45beSAndroid Build Coastguard Worker 	if (mlock2_(map, 2 * page_size, 0)) {
205*053f45beSAndroid Build Coastguard Worker 		if (errno == ENOSYS) {
206*053f45beSAndroid Build Coastguard Worker 			printf("Cannot call new mlock family, skipping test\n");
207*053f45beSAndroid Build Coastguard Worker 			_exit(KSFT_SKIP);
208*053f45beSAndroid Build Coastguard Worker 		}
209*053f45beSAndroid Build Coastguard Worker 		perror("mlock2(0)");
210*053f45beSAndroid Build Coastguard Worker 		goto unmap;
211*053f45beSAndroid Build Coastguard Worker 	}
212*053f45beSAndroid Build Coastguard Worker 
213*053f45beSAndroid Build Coastguard Worker 	if (!lock_check((unsigned long)map))
214*053f45beSAndroid Build Coastguard Worker 		goto unmap;
215*053f45beSAndroid Build Coastguard Worker 
216*053f45beSAndroid Build Coastguard Worker 	/* Now unlock and recheck attributes */
217*053f45beSAndroid Build Coastguard Worker 	if (munlock(map, 2 * page_size)) {
218*053f45beSAndroid Build Coastguard Worker 		perror("munlock()");
219*053f45beSAndroid Build Coastguard Worker 		goto unmap;
220*053f45beSAndroid Build Coastguard Worker 	}
221*053f45beSAndroid Build Coastguard Worker 
222*053f45beSAndroid Build Coastguard Worker 	ret = unlock_lock_check(map);
223*053f45beSAndroid Build Coastguard Worker 
224*053f45beSAndroid Build Coastguard Worker unmap:
225*053f45beSAndroid Build Coastguard Worker 	munmap(map, 2 * page_size);
226*053f45beSAndroid Build Coastguard Worker out:
227*053f45beSAndroid Build Coastguard Worker 	return ret;
228*053f45beSAndroid Build Coastguard Worker }
229*053f45beSAndroid Build Coastguard Worker 
onfault_check(char * map)230*053f45beSAndroid Build Coastguard Worker static int onfault_check(char *map)
231*053f45beSAndroid Build Coastguard Worker {
232*053f45beSAndroid Build Coastguard Worker 	*map = 'a';
233*053f45beSAndroid Build Coastguard Worker 	if (!is_vma_lock_on_fault((unsigned long)map)) {
234*053f45beSAndroid Build Coastguard Worker 		printf("VMA is not marked for lock on fault\n");
235*053f45beSAndroid Build Coastguard Worker 		return 1;
236*053f45beSAndroid Build Coastguard Worker 	}
237*053f45beSAndroid Build Coastguard Worker 
238*053f45beSAndroid Build Coastguard Worker 	return 0;
239*053f45beSAndroid Build Coastguard Worker }
240*053f45beSAndroid Build Coastguard Worker 
unlock_onfault_check(char * map)241*053f45beSAndroid Build Coastguard Worker static int unlock_onfault_check(char *map)
242*053f45beSAndroid Build Coastguard Worker {
243*053f45beSAndroid Build Coastguard Worker 	unsigned long page_size = getpagesize();
244*053f45beSAndroid Build Coastguard Worker 
245*053f45beSAndroid Build Coastguard Worker 	if (is_vma_lock_on_fault((unsigned long)map) ||
246*053f45beSAndroid Build Coastguard Worker 	    is_vma_lock_on_fault((unsigned long)map + page_size)) {
247*053f45beSAndroid Build Coastguard Worker 		printf("VMA is still lock on fault after unlock\n");
248*053f45beSAndroid Build Coastguard Worker 		return 1;
249*053f45beSAndroid Build Coastguard Worker 	}
250*053f45beSAndroid Build Coastguard Worker 
251*053f45beSAndroid Build Coastguard Worker 	return 0;
252*053f45beSAndroid Build Coastguard Worker }
253*053f45beSAndroid Build Coastguard Worker 
test_mlock_onfault()254*053f45beSAndroid Build Coastguard Worker static int test_mlock_onfault()
255*053f45beSAndroid Build Coastguard Worker {
256*053f45beSAndroid Build Coastguard Worker 	char *map;
257*053f45beSAndroid Build Coastguard Worker 	int ret = 1;
258*053f45beSAndroid Build Coastguard Worker 	unsigned long page_size = getpagesize();
259*053f45beSAndroid Build Coastguard Worker 
260*053f45beSAndroid Build Coastguard Worker 	map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
261*053f45beSAndroid Build Coastguard Worker 		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
262*053f45beSAndroid Build Coastguard Worker 	if (map == MAP_FAILED) {
263*053f45beSAndroid Build Coastguard Worker 		perror("test_mlock_locked mmap");
264*053f45beSAndroid Build Coastguard Worker 		goto out;
265*053f45beSAndroid Build Coastguard Worker 	}
266*053f45beSAndroid Build Coastguard Worker 
267*053f45beSAndroid Build Coastguard Worker 	if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
268*053f45beSAndroid Build Coastguard Worker 		if (errno == ENOSYS) {
269*053f45beSAndroid Build Coastguard Worker 			printf("Cannot call new mlock family, skipping test\n");
270*053f45beSAndroid Build Coastguard Worker 			_exit(KSFT_SKIP);
271*053f45beSAndroid Build Coastguard Worker 		}
272*053f45beSAndroid Build Coastguard Worker 		perror("mlock2(MLOCK_ONFAULT)");
273*053f45beSAndroid Build Coastguard Worker 		goto unmap;
274*053f45beSAndroid Build Coastguard Worker 	}
275*053f45beSAndroid Build Coastguard Worker 
276*053f45beSAndroid Build Coastguard Worker 	if (onfault_check(map))
277*053f45beSAndroid Build Coastguard Worker 		goto unmap;
278*053f45beSAndroid Build Coastguard Worker 
279*053f45beSAndroid Build Coastguard Worker 	/* Now unlock and recheck attributes */
280*053f45beSAndroid Build Coastguard Worker 	if (munlock(map, 2 * page_size)) {
281*053f45beSAndroid Build Coastguard Worker 		if (errno == ENOSYS) {
282*053f45beSAndroid Build Coastguard Worker 			printf("Cannot call new mlock family, skipping test\n");
283*053f45beSAndroid Build Coastguard Worker 			_exit(KSFT_SKIP);
284*053f45beSAndroid Build Coastguard Worker 		}
285*053f45beSAndroid Build Coastguard Worker 		perror("munlock()");
286*053f45beSAndroid Build Coastguard Worker 		goto unmap;
287*053f45beSAndroid Build Coastguard Worker 	}
288*053f45beSAndroid Build Coastguard Worker 
289*053f45beSAndroid Build Coastguard Worker 	ret = unlock_onfault_check(map);
290*053f45beSAndroid Build Coastguard Worker unmap:
291*053f45beSAndroid Build Coastguard Worker 	munmap(map, 2 * page_size);
292*053f45beSAndroid Build Coastguard Worker out:
293*053f45beSAndroid Build Coastguard Worker 	return ret;
294*053f45beSAndroid Build Coastguard Worker }
295*053f45beSAndroid Build Coastguard Worker 
test_lock_onfault_of_present()296*053f45beSAndroid Build Coastguard Worker static int test_lock_onfault_of_present()
297*053f45beSAndroid Build Coastguard Worker {
298*053f45beSAndroid Build Coastguard Worker 	char *map;
299*053f45beSAndroid Build Coastguard Worker 	int ret = 1;
300*053f45beSAndroid Build Coastguard Worker 	unsigned long page_size = getpagesize();
301*053f45beSAndroid Build Coastguard Worker 
302*053f45beSAndroid Build Coastguard Worker 	map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
303*053f45beSAndroid Build Coastguard Worker 		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
304*053f45beSAndroid Build Coastguard Worker 	if (map == MAP_FAILED) {
305*053f45beSAndroid Build Coastguard Worker 		perror("test_mlock_locked mmap");
306*053f45beSAndroid Build Coastguard Worker 		goto out;
307*053f45beSAndroid Build Coastguard Worker 	}
308*053f45beSAndroid Build Coastguard Worker 
309*053f45beSAndroid Build Coastguard Worker 	*map = 'a';
310*053f45beSAndroid Build Coastguard Worker 
311*053f45beSAndroid Build Coastguard Worker 	if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
312*053f45beSAndroid Build Coastguard Worker 		if (errno == ENOSYS) {
313*053f45beSAndroid Build Coastguard Worker 			printf("Cannot call new mlock family, skipping test\n");
314*053f45beSAndroid Build Coastguard Worker 			_exit(KSFT_SKIP);
315*053f45beSAndroid Build Coastguard Worker 		}
316*053f45beSAndroid Build Coastguard Worker 		perror("mlock2(MLOCK_ONFAULT)");
317*053f45beSAndroid Build Coastguard Worker 		goto unmap;
318*053f45beSAndroid Build Coastguard Worker 	}
319*053f45beSAndroid Build Coastguard Worker 
320*053f45beSAndroid Build Coastguard Worker 	if (!is_vma_lock_on_fault((unsigned long)map) ||
321*053f45beSAndroid Build Coastguard Worker 	    !is_vma_lock_on_fault((unsigned long)map + page_size)) {
322*053f45beSAndroid Build Coastguard Worker 		printf("VMA with present pages is not marked lock on fault\n");
323*053f45beSAndroid Build Coastguard Worker 		goto unmap;
324*053f45beSAndroid Build Coastguard Worker 	}
325*053f45beSAndroid Build Coastguard Worker 	ret = 0;
326*053f45beSAndroid Build Coastguard Worker unmap:
327*053f45beSAndroid Build Coastguard Worker 	munmap(map, 2 * page_size);
328*053f45beSAndroid Build Coastguard Worker out:
329*053f45beSAndroid Build Coastguard Worker 	return ret;
330*053f45beSAndroid Build Coastguard Worker }
331*053f45beSAndroid Build Coastguard Worker 
test_munlockall()332*053f45beSAndroid Build Coastguard Worker static int test_munlockall()
333*053f45beSAndroid Build Coastguard Worker {
334*053f45beSAndroid Build Coastguard Worker 	char *map;
335*053f45beSAndroid Build Coastguard Worker 	int ret = 1;
336*053f45beSAndroid Build Coastguard Worker 	unsigned long page_size = getpagesize();
337*053f45beSAndroid Build Coastguard Worker 
338*053f45beSAndroid Build Coastguard Worker 	map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
339*053f45beSAndroid Build Coastguard Worker 		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
340*053f45beSAndroid Build Coastguard Worker 
341*053f45beSAndroid Build Coastguard Worker 	if (map == MAP_FAILED) {
342*053f45beSAndroid Build Coastguard Worker 		perror("test_munlockall mmap");
343*053f45beSAndroid Build Coastguard Worker 		goto out;
344*053f45beSAndroid Build Coastguard Worker 	}
345*053f45beSAndroid Build Coastguard Worker 
346*053f45beSAndroid Build Coastguard Worker 	if (mlockall(MCL_CURRENT)) {
347*053f45beSAndroid Build Coastguard Worker 		perror("mlockall(MCL_CURRENT)");
348*053f45beSAndroid Build Coastguard Worker 		goto out;
349*053f45beSAndroid Build Coastguard Worker 	}
350*053f45beSAndroid Build Coastguard Worker 
351*053f45beSAndroid Build Coastguard Worker 	if (!lock_check((unsigned long)map))
352*053f45beSAndroid Build Coastguard Worker 		goto unmap;
353*053f45beSAndroid Build Coastguard Worker 
354*053f45beSAndroid Build Coastguard Worker 	if (munlockall()) {
355*053f45beSAndroid Build Coastguard Worker 		perror("munlockall()");
356*053f45beSAndroid Build Coastguard Worker 		goto unmap;
357*053f45beSAndroid Build Coastguard Worker 	}
358*053f45beSAndroid Build Coastguard Worker 
359*053f45beSAndroid Build Coastguard Worker 	if (unlock_lock_check(map))
360*053f45beSAndroid Build Coastguard Worker 		goto unmap;
361*053f45beSAndroid Build Coastguard Worker 
362*053f45beSAndroid Build Coastguard Worker 	munmap(map, 2 * page_size);
363*053f45beSAndroid Build Coastguard Worker 
364*053f45beSAndroid Build Coastguard Worker 	map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
365*053f45beSAndroid Build Coastguard Worker 		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
366*053f45beSAndroid Build Coastguard Worker 
367*053f45beSAndroid Build Coastguard Worker 	if (map == MAP_FAILED) {
368*053f45beSAndroid Build Coastguard Worker 		perror("test_munlockall second mmap");
369*053f45beSAndroid Build Coastguard Worker 		goto out;
370*053f45beSAndroid Build Coastguard Worker 	}
371*053f45beSAndroid Build Coastguard Worker 
372*053f45beSAndroid Build Coastguard Worker 	if (mlockall(MCL_CURRENT | MCL_ONFAULT)) {
373*053f45beSAndroid Build Coastguard Worker 		perror("mlockall(MCL_CURRENT | MCL_ONFAULT)");
374*053f45beSAndroid Build Coastguard Worker 		goto unmap;
375*053f45beSAndroid Build Coastguard Worker 	}
376*053f45beSAndroid Build Coastguard Worker 
377*053f45beSAndroid Build Coastguard Worker 	if (onfault_check(map))
378*053f45beSAndroid Build Coastguard Worker 		goto unmap;
379*053f45beSAndroid Build Coastguard Worker 
380*053f45beSAndroid Build Coastguard Worker 	if (munlockall()) {
381*053f45beSAndroid Build Coastguard Worker 		perror("munlockall()");
382*053f45beSAndroid Build Coastguard Worker 		goto unmap;
383*053f45beSAndroid Build Coastguard Worker 	}
384*053f45beSAndroid Build Coastguard Worker 
385*053f45beSAndroid Build Coastguard Worker 	if (unlock_onfault_check(map))
386*053f45beSAndroid Build Coastguard Worker 		goto unmap;
387*053f45beSAndroid Build Coastguard Worker 
388*053f45beSAndroid Build Coastguard Worker 	if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
389*053f45beSAndroid Build Coastguard Worker 		perror("mlockall(MCL_CURRENT | MCL_FUTURE)");
390*053f45beSAndroid Build Coastguard Worker 		goto out;
391*053f45beSAndroid Build Coastguard Worker 	}
392*053f45beSAndroid Build Coastguard Worker 
393*053f45beSAndroid Build Coastguard Worker 	if (!lock_check((unsigned long)map))
394*053f45beSAndroid Build Coastguard Worker 		goto unmap;
395*053f45beSAndroid Build Coastguard Worker 
396*053f45beSAndroid Build Coastguard Worker 	if (munlockall()) {
397*053f45beSAndroid Build Coastguard Worker 		perror("munlockall()");
398*053f45beSAndroid Build Coastguard Worker 		goto unmap;
399*053f45beSAndroid Build Coastguard Worker 	}
400*053f45beSAndroid Build Coastguard Worker 
401*053f45beSAndroid Build Coastguard Worker 	ret = unlock_lock_check(map);
402*053f45beSAndroid Build Coastguard Worker 
403*053f45beSAndroid Build Coastguard Worker unmap:
404*053f45beSAndroid Build Coastguard Worker 	munmap(map, 2 * page_size);
405*053f45beSAndroid Build Coastguard Worker out:
406*053f45beSAndroid Build Coastguard Worker 	munlockall();
407*053f45beSAndroid Build Coastguard Worker 	return ret;
408*053f45beSAndroid Build Coastguard Worker }
409*053f45beSAndroid Build Coastguard Worker 
test_vma_management(bool call_mlock)410*053f45beSAndroid Build Coastguard Worker static int test_vma_management(bool call_mlock)
411*053f45beSAndroid Build Coastguard Worker {
412*053f45beSAndroid Build Coastguard Worker 	int ret = 1;
413*053f45beSAndroid Build Coastguard Worker 	void *map;
414*053f45beSAndroid Build Coastguard Worker 	unsigned long page_size = getpagesize();
415*053f45beSAndroid Build Coastguard Worker 	struct vm_boundaries page1;
416*053f45beSAndroid Build Coastguard Worker 	struct vm_boundaries page2;
417*053f45beSAndroid Build Coastguard Worker 	struct vm_boundaries page3;
418*053f45beSAndroid Build Coastguard Worker 
419*053f45beSAndroid Build Coastguard Worker 	map = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE,
420*053f45beSAndroid Build Coastguard Worker 		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
421*053f45beSAndroid Build Coastguard Worker 	if (map == MAP_FAILED) {
422*053f45beSAndroid Build Coastguard Worker 		perror("mmap()");
423*053f45beSAndroid Build Coastguard Worker 		return ret;
424*053f45beSAndroid Build Coastguard Worker 	}
425*053f45beSAndroid Build Coastguard Worker 
426*053f45beSAndroid Build Coastguard Worker 	if (call_mlock && mlock2_(map, 3 * page_size, MLOCK_ONFAULT)) {
427*053f45beSAndroid Build Coastguard Worker 		if (errno == ENOSYS) {
428*053f45beSAndroid Build Coastguard Worker 			printf("Cannot call new mlock family, skipping test\n");
429*053f45beSAndroid Build Coastguard Worker 			_exit(KSFT_SKIP);
430*053f45beSAndroid Build Coastguard Worker 		}
431*053f45beSAndroid Build Coastguard Worker 		perror("mlock(ONFAULT)\n");
432*053f45beSAndroid Build Coastguard Worker 		goto out;
433*053f45beSAndroid Build Coastguard Worker 	}
434*053f45beSAndroid Build Coastguard Worker 
435*053f45beSAndroid Build Coastguard Worker 	if (get_vm_area((unsigned long)map, &page1) ||
436*053f45beSAndroid Build Coastguard Worker 	    get_vm_area((unsigned long)map + page_size, &page2) ||
437*053f45beSAndroid Build Coastguard Worker 	    get_vm_area((unsigned long)map + page_size * 2, &page3)) {
438*053f45beSAndroid Build Coastguard Worker 		printf("couldn't find mapping in /proc/self/maps\n");
439*053f45beSAndroid Build Coastguard Worker 		goto out;
440*053f45beSAndroid Build Coastguard Worker 	}
441*053f45beSAndroid Build Coastguard Worker 
442*053f45beSAndroid Build Coastguard Worker 	/*
443*053f45beSAndroid Build Coastguard Worker 	 * Before we unlock a portion, we need to that all three pages are in
444*053f45beSAndroid Build Coastguard Worker 	 * the same VMA.  If they are not we abort this test (Note that this is
445*053f45beSAndroid Build Coastguard Worker 	 * not a failure)
446*053f45beSAndroid Build Coastguard Worker 	 */
447*053f45beSAndroid Build Coastguard Worker 	if (page1.start != page2.start || page2.start != page3.start) {
448*053f45beSAndroid Build Coastguard Worker 		printf("VMAs are not merged to start, aborting test\n");
449*053f45beSAndroid Build Coastguard Worker 		ret = 0;
450*053f45beSAndroid Build Coastguard Worker 		goto out;
451*053f45beSAndroid Build Coastguard Worker 	}
452*053f45beSAndroid Build Coastguard Worker 
453*053f45beSAndroid Build Coastguard Worker 	if (munlock(map + page_size, page_size)) {
454*053f45beSAndroid Build Coastguard Worker 		perror("munlock()");
455*053f45beSAndroid Build Coastguard Worker 		goto out;
456*053f45beSAndroid Build Coastguard Worker 	}
457*053f45beSAndroid Build Coastguard Worker 
458*053f45beSAndroid Build Coastguard Worker 	if (get_vm_area((unsigned long)map, &page1) ||
459*053f45beSAndroid Build Coastguard Worker 	    get_vm_area((unsigned long)map + page_size, &page2) ||
460*053f45beSAndroid Build Coastguard Worker 	    get_vm_area((unsigned long)map + page_size * 2, &page3)) {
461*053f45beSAndroid Build Coastguard Worker 		printf("couldn't find mapping in /proc/self/maps\n");
462*053f45beSAndroid Build Coastguard Worker 		goto out;
463*053f45beSAndroid Build Coastguard Worker 	}
464*053f45beSAndroid Build Coastguard Worker 
465*053f45beSAndroid Build Coastguard Worker 	/* All three VMAs should be different */
466*053f45beSAndroid Build Coastguard Worker 	if (page1.start == page2.start || page2.start == page3.start) {
467*053f45beSAndroid Build Coastguard Worker 		printf("failed to split VMA for munlock\n");
468*053f45beSAndroid Build Coastguard Worker 		goto out;
469*053f45beSAndroid Build Coastguard Worker 	}
470*053f45beSAndroid Build Coastguard Worker 
471*053f45beSAndroid Build Coastguard Worker 	/* Now unlock the first and third page and check the VMAs again */
472*053f45beSAndroid Build Coastguard Worker 	if (munlock(map, page_size * 3)) {
473*053f45beSAndroid Build Coastguard Worker 		perror("munlock()");
474*053f45beSAndroid Build Coastguard Worker 		goto out;
475*053f45beSAndroid Build Coastguard Worker 	}
476*053f45beSAndroid Build Coastguard Worker 
477*053f45beSAndroid Build Coastguard Worker 	if (get_vm_area((unsigned long)map, &page1) ||
478*053f45beSAndroid Build Coastguard Worker 	    get_vm_area((unsigned long)map + page_size, &page2) ||
479*053f45beSAndroid Build Coastguard Worker 	    get_vm_area((unsigned long)map + page_size * 2, &page3)) {
480*053f45beSAndroid Build Coastguard Worker 		printf("couldn't find mapping in /proc/self/maps\n");
481*053f45beSAndroid Build Coastguard Worker 		goto out;
482*053f45beSAndroid Build Coastguard Worker 	}
483*053f45beSAndroid Build Coastguard Worker 
484*053f45beSAndroid Build Coastguard Worker 	/* Now all three VMAs should be the same */
485*053f45beSAndroid Build Coastguard Worker 	if (page1.start != page2.start || page2.start != page3.start) {
486*053f45beSAndroid Build Coastguard Worker 		printf("failed to merge VMAs after munlock\n");
487*053f45beSAndroid Build Coastguard Worker 		goto out;
488*053f45beSAndroid Build Coastguard Worker 	}
489*053f45beSAndroid Build Coastguard Worker 
490*053f45beSAndroid Build Coastguard Worker 	ret = 0;
491*053f45beSAndroid Build Coastguard Worker out:
492*053f45beSAndroid Build Coastguard Worker 	munmap(map, 3 * page_size);
493*053f45beSAndroid Build Coastguard Worker 	return ret;
494*053f45beSAndroid Build Coastguard Worker }
495*053f45beSAndroid Build Coastguard Worker 
test_mlockall(int (test_function)(bool call_mlock))496*053f45beSAndroid Build Coastguard Worker static int test_mlockall(int (test_function)(bool call_mlock))
497*053f45beSAndroid Build Coastguard Worker {
498*053f45beSAndroid Build Coastguard Worker 	int ret = 1;
499*053f45beSAndroid Build Coastguard Worker 
500*053f45beSAndroid Build Coastguard Worker 	if (mlockall(MCL_CURRENT | MCL_ONFAULT | MCL_FUTURE)) {
501*053f45beSAndroid Build Coastguard Worker 		perror("mlockall");
502*053f45beSAndroid Build Coastguard Worker 		return ret;
503*053f45beSAndroid Build Coastguard Worker 	}
504*053f45beSAndroid Build Coastguard Worker 
505*053f45beSAndroid Build Coastguard Worker 	ret = test_function(false);
506*053f45beSAndroid Build Coastguard Worker 	munlockall();
507*053f45beSAndroid Build Coastguard Worker 	return ret;
508*053f45beSAndroid Build Coastguard Worker }
509*053f45beSAndroid Build Coastguard Worker 
main(int argc,char ** argv)510*053f45beSAndroid Build Coastguard Worker int main(int argc, char **argv)
511*053f45beSAndroid Build Coastguard Worker {
512*053f45beSAndroid Build Coastguard Worker 	int ret = 0;
513*053f45beSAndroid Build Coastguard Worker 	ret += test_mlock_lock();
514*053f45beSAndroid Build Coastguard Worker 	ret += test_mlock_onfault();
515*053f45beSAndroid Build Coastguard Worker 	ret += test_munlockall();
516*053f45beSAndroid Build Coastguard Worker 	ret += test_lock_onfault_of_present();
517*053f45beSAndroid Build Coastguard Worker 	ret += test_vma_management(true);
518*053f45beSAndroid Build Coastguard Worker 	ret += test_mlockall(test_vma_management);
519*053f45beSAndroid Build Coastguard Worker 	return ret;
520*053f45beSAndroid Build Coastguard Worker }
521