xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/vm/khugepaged.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
1*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE
2*053f45beSAndroid Build Coastguard Worker #include <ctype.h>
3*053f45beSAndroid Build Coastguard Worker #include <errno.h>
4*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
5*053f45beSAndroid Build Coastguard Worker #include <limits.h>
6*053f45beSAndroid Build Coastguard Worker #include <dirent.h>
7*053f45beSAndroid Build Coastguard Worker #include <signal.h>
8*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
9*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
10*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
11*053f45beSAndroid Build Coastguard Worker #include <string.h>
12*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
13*053f45beSAndroid Build Coastguard Worker 
14*053f45beSAndroid Build Coastguard Worker #include <sys/mman.h>
15*053f45beSAndroid Build Coastguard Worker #include <sys/wait.h>
16*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
17*053f45beSAndroid Build Coastguard Worker #include <sys/stat.h>
18*053f45beSAndroid Build Coastguard Worker #include <sys/sysmacros.h>
19*053f45beSAndroid Build Coastguard Worker #include <sys/vfs.h>
20*053f45beSAndroid Build Coastguard Worker 
21*053f45beSAndroid Build Coastguard Worker #include "linux/magic.h"
22*053f45beSAndroid Build Coastguard Worker 
23*053f45beSAndroid Build Coastguard Worker #include "vm_util.h"
24*053f45beSAndroid Build Coastguard Worker 
25*053f45beSAndroid Build Coastguard Worker #ifndef MADV_PAGEOUT
26*053f45beSAndroid Build Coastguard Worker #define MADV_PAGEOUT 21
27*053f45beSAndroid Build Coastguard Worker #endif
28*053f45beSAndroid Build Coastguard Worker #ifndef MADV_POPULATE_READ
29*053f45beSAndroid Build Coastguard Worker #define MADV_POPULATE_READ 22
30*053f45beSAndroid Build Coastguard Worker #endif
31*053f45beSAndroid Build Coastguard Worker #ifndef MADV_COLLAPSE
32*053f45beSAndroid Build Coastguard Worker #define MADV_COLLAPSE 25
33*053f45beSAndroid Build Coastguard Worker #endif
34*053f45beSAndroid Build Coastguard Worker 
35*053f45beSAndroid Build Coastguard Worker #define BASE_ADDR ((void *)(1UL << 30))
36*053f45beSAndroid Build Coastguard Worker static unsigned long hpage_pmd_size;
37*053f45beSAndroid Build Coastguard Worker static unsigned long page_size;
38*053f45beSAndroid Build Coastguard Worker static int hpage_pmd_nr;
39*053f45beSAndroid Build Coastguard Worker 
40*053f45beSAndroid Build Coastguard Worker #define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/"
41*053f45beSAndroid Build Coastguard Worker #define PID_SMAPS "/proc/self/smaps"
42*053f45beSAndroid Build Coastguard Worker #define TEST_FILE "collapse_test_file"
43*053f45beSAndroid Build Coastguard Worker 
44*053f45beSAndroid Build Coastguard Worker #define MAX_LINE_LENGTH 500
45*053f45beSAndroid Build Coastguard Worker 
46*053f45beSAndroid Build Coastguard Worker enum vma_type {
47*053f45beSAndroid Build Coastguard Worker 	VMA_ANON,
48*053f45beSAndroid Build Coastguard Worker 	VMA_FILE,
49*053f45beSAndroid Build Coastguard Worker 	VMA_SHMEM,
50*053f45beSAndroid Build Coastguard Worker };
51*053f45beSAndroid Build Coastguard Worker 
52*053f45beSAndroid Build Coastguard Worker struct mem_ops {
53*053f45beSAndroid Build Coastguard Worker 	void *(*setup_area)(int nr_hpages);
54*053f45beSAndroid Build Coastguard Worker 	void (*cleanup_area)(void *p, unsigned long size);
55*053f45beSAndroid Build Coastguard Worker 	void (*fault)(void *p, unsigned long start, unsigned long end);
56*053f45beSAndroid Build Coastguard Worker 	bool (*check_huge)(void *addr, int nr_hpages);
57*053f45beSAndroid Build Coastguard Worker 	const char *name;
58*053f45beSAndroid Build Coastguard Worker };
59*053f45beSAndroid Build Coastguard Worker 
60*053f45beSAndroid Build Coastguard Worker static struct mem_ops *file_ops;
61*053f45beSAndroid Build Coastguard Worker static struct mem_ops *anon_ops;
62*053f45beSAndroid Build Coastguard Worker static struct mem_ops *shmem_ops;
63*053f45beSAndroid Build Coastguard Worker 
64*053f45beSAndroid Build Coastguard Worker struct collapse_context {
65*053f45beSAndroid Build Coastguard Worker 	void (*collapse)(const char *msg, char *p, int nr_hpages,
66*053f45beSAndroid Build Coastguard Worker 			 struct mem_ops *ops, bool expect);
67*053f45beSAndroid Build Coastguard Worker 	bool enforce_pte_scan_limits;
68*053f45beSAndroid Build Coastguard Worker 	const char *name;
69*053f45beSAndroid Build Coastguard Worker };
70*053f45beSAndroid Build Coastguard Worker 
71*053f45beSAndroid Build Coastguard Worker static struct collapse_context *khugepaged_context;
72*053f45beSAndroid Build Coastguard Worker static struct collapse_context *madvise_context;
73*053f45beSAndroid Build Coastguard Worker 
74*053f45beSAndroid Build Coastguard Worker struct file_info {
75*053f45beSAndroid Build Coastguard Worker 	const char *dir;
76*053f45beSAndroid Build Coastguard Worker 	char path[PATH_MAX];
77*053f45beSAndroid Build Coastguard Worker 	enum vma_type type;
78*053f45beSAndroid Build Coastguard Worker 	int fd;
79*053f45beSAndroid Build Coastguard Worker 	char dev_queue_read_ahead_path[PATH_MAX];
80*053f45beSAndroid Build Coastguard Worker };
81*053f45beSAndroid Build Coastguard Worker 
82*053f45beSAndroid Build Coastguard Worker static struct file_info finfo;
83*053f45beSAndroid Build Coastguard Worker 
84*053f45beSAndroid Build Coastguard Worker enum thp_enabled {
85*053f45beSAndroid Build Coastguard Worker 	THP_ALWAYS,
86*053f45beSAndroid Build Coastguard Worker 	THP_MADVISE,
87*053f45beSAndroid Build Coastguard Worker 	THP_NEVER,
88*053f45beSAndroid Build Coastguard Worker };
89*053f45beSAndroid Build Coastguard Worker 
90*053f45beSAndroid Build Coastguard Worker static const char *thp_enabled_strings[] = {
91*053f45beSAndroid Build Coastguard Worker 	"always",
92*053f45beSAndroid Build Coastguard Worker 	"madvise",
93*053f45beSAndroid Build Coastguard Worker 	"never",
94*053f45beSAndroid Build Coastguard Worker 	NULL
95*053f45beSAndroid Build Coastguard Worker };
96*053f45beSAndroid Build Coastguard Worker 
97*053f45beSAndroid Build Coastguard Worker enum thp_defrag {
98*053f45beSAndroid Build Coastguard Worker 	THP_DEFRAG_ALWAYS,
99*053f45beSAndroid Build Coastguard Worker 	THP_DEFRAG_DEFER,
100*053f45beSAndroid Build Coastguard Worker 	THP_DEFRAG_DEFER_MADVISE,
101*053f45beSAndroid Build Coastguard Worker 	THP_DEFRAG_MADVISE,
102*053f45beSAndroid Build Coastguard Worker 	THP_DEFRAG_NEVER,
103*053f45beSAndroid Build Coastguard Worker };
104*053f45beSAndroid Build Coastguard Worker 
105*053f45beSAndroid Build Coastguard Worker static const char *thp_defrag_strings[] = {
106*053f45beSAndroid Build Coastguard Worker 	"always",
107*053f45beSAndroid Build Coastguard Worker 	"defer",
108*053f45beSAndroid Build Coastguard Worker 	"defer+madvise",
109*053f45beSAndroid Build Coastguard Worker 	"madvise",
110*053f45beSAndroid Build Coastguard Worker 	"never",
111*053f45beSAndroid Build Coastguard Worker 	NULL
112*053f45beSAndroid Build Coastguard Worker };
113*053f45beSAndroid Build Coastguard Worker 
114*053f45beSAndroid Build Coastguard Worker enum shmem_enabled {
115*053f45beSAndroid Build Coastguard Worker 	SHMEM_ALWAYS,
116*053f45beSAndroid Build Coastguard Worker 	SHMEM_WITHIN_SIZE,
117*053f45beSAndroid Build Coastguard Worker 	SHMEM_ADVISE,
118*053f45beSAndroid Build Coastguard Worker 	SHMEM_NEVER,
119*053f45beSAndroid Build Coastguard Worker 	SHMEM_DENY,
120*053f45beSAndroid Build Coastguard Worker 	SHMEM_FORCE,
121*053f45beSAndroid Build Coastguard Worker };
122*053f45beSAndroid Build Coastguard Worker 
123*053f45beSAndroid Build Coastguard Worker static const char *shmem_enabled_strings[] = {
124*053f45beSAndroid Build Coastguard Worker 	"always",
125*053f45beSAndroid Build Coastguard Worker 	"within_size",
126*053f45beSAndroid Build Coastguard Worker 	"advise",
127*053f45beSAndroid Build Coastguard Worker 	"never",
128*053f45beSAndroid Build Coastguard Worker 	"deny",
129*053f45beSAndroid Build Coastguard Worker 	"force",
130*053f45beSAndroid Build Coastguard Worker 	NULL
131*053f45beSAndroid Build Coastguard Worker };
132*053f45beSAndroid Build Coastguard Worker 
133*053f45beSAndroid Build Coastguard Worker struct khugepaged_settings {
134*053f45beSAndroid Build Coastguard Worker 	bool defrag;
135*053f45beSAndroid Build Coastguard Worker 	unsigned int alloc_sleep_millisecs;
136*053f45beSAndroid Build Coastguard Worker 	unsigned int scan_sleep_millisecs;
137*053f45beSAndroid Build Coastguard Worker 	unsigned int max_ptes_none;
138*053f45beSAndroid Build Coastguard Worker 	unsigned int max_ptes_swap;
139*053f45beSAndroid Build Coastguard Worker 	unsigned int max_ptes_shared;
140*053f45beSAndroid Build Coastguard Worker 	unsigned long pages_to_scan;
141*053f45beSAndroid Build Coastguard Worker };
142*053f45beSAndroid Build Coastguard Worker 
143*053f45beSAndroid Build Coastguard Worker struct settings {
144*053f45beSAndroid Build Coastguard Worker 	enum thp_enabled thp_enabled;
145*053f45beSAndroid Build Coastguard Worker 	enum thp_defrag thp_defrag;
146*053f45beSAndroid Build Coastguard Worker 	enum shmem_enabled shmem_enabled;
147*053f45beSAndroid Build Coastguard Worker 	bool use_zero_page;
148*053f45beSAndroid Build Coastguard Worker 	struct khugepaged_settings khugepaged;
149*053f45beSAndroid Build Coastguard Worker 	unsigned long read_ahead_kb;
150*053f45beSAndroid Build Coastguard Worker };
151*053f45beSAndroid Build Coastguard Worker 
152*053f45beSAndroid Build Coastguard Worker static struct settings saved_settings;
153*053f45beSAndroid Build Coastguard Worker static bool skip_settings_restore;
154*053f45beSAndroid Build Coastguard Worker 
155*053f45beSAndroid Build Coastguard Worker static int exit_status;
156*053f45beSAndroid Build Coastguard Worker 
success(const char * msg)157*053f45beSAndroid Build Coastguard Worker static void success(const char *msg)
158*053f45beSAndroid Build Coastguard Worker {
159*053f45beSAndroid Build Coastguard Worker 	printf(" \e[32m%s\e[0m\n", msg);
160*053f45beSAndroid Build Coastguard Worker }
161*053f45beSAndroid Build Coastguard Worker 
fail(const char * msg)162*053f45beSAndroid Build Coastguard Worker static void fail(const char *msg)
163*053f45beSAndroid Build Coastguard Worker {
164*053f45beSAndroid Build Coastguard Worker 	printf(" \e[31m%s\e[0m\n", msg);
165*053f45beSAndroid Build Coastguard Worker 	exit_status++;
166*053f45beSAndroid Build Coastguard Worker }
167*053f45beSAndroid Build Coastguard Worker 
skip(const char * msg)168*053f45beSAndroid Build Coastguard Worker static void skip(const char *msg)
169*053f45beSAndroid Build Coastguard Worker {
170*053f45beSAndroid Build Coastguard Worker 	printf(" \e[33m%s\e[0m\n", msg);
171*053f45beSAndroid Build Coastguard Worker }
172*053f45beSAndroid Build Coastguard Worker 
read_file(const char * path,char * buf,size_t buflen)173*053f45beSAndroid Build Coastguard Worker static int read_file(const char *path, char *buf, size_t buflen)
174*053f45beSAndroid Build Coastguard Worker {
175*053f45beSAndroid Build Coastguard Worker 	int fd;
176*053f45beSAndroid Build Coastguard Worker 	ssize_t numread;
177*053f45beSAndroid Build Coastguard Worker 
178*053f45beSAndroid Build Coastguard Worker 	fd = open(path, O_RDONLY);
179*053f45beSAndroid Build Coastguard Worker 	if (fd == -1)
180*053f45beSAndroid Build Coastguard Worker 		return 0;
181*053f45beSAndroid Build Coastguard Worker 
182*053f45beSAndroid Build Coastguard Worker 	numread = read(fd, buf, buflen - 1);
183*053f45beSAndroid Build Coastguard Worker 	if (numread < 1) {
184*053f45beSAndroid Build Coastguard Worker 		close(fd);
185*053f45beSAndroid Build Coastguard Worker 		return 0;
186*053f45beSAndroid Build Coastguard Worker 	}
187*053f45beSAndroid Build Coastguard Worker 
188*053f45beSAndroid Build Coastguard Worker 	buf[numread] = '\0';
189*053f45beSAndroid Build Coastguard Worker 	close(fd);
190*053f45beSAndroid Build Coastguard Worker 
191*053f45beSAndroid Build Coastguard Worker 	return (unsigned int) numread;
192*053f45beSAndroid Build Coastguard Worker }
193*053f45beSAndroid Build Coastguard Worker 
write_file(const char * path,const char * buf,size_t buflen)194*053f45beSAndroid Build Coastguard Worker static int write_file(const char *path, const char *buf, size_t buflen)
195*053f45beSAndroid Build Coastguard Worker {
196*053f45beSAndroid Build Coastguard Worker 	int fd;
197*053f45beSAndroid Build Coastguard Worker 	ssize_t numwritten;
198*053f45beSAndroid Build Coastguard Worker 
199*053f45beSAndroid Build Coastguard Worker 	fd = open(path, O_WRONLY);
200*053f45beSAndroid Build Coastguard Worker 	if (fd == -1) {
201*053f45beSAndroid Build Coastguard Worker 		printf("open(%s)\n", path);
202*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
203*053f45beSAndroid Build Coastguard Worker 		return 0;
204*053f45beSAndroid Build Coastguard Worker 	}
205*053f45beSAndroid Build Coastguard Worker 
206*053f45beSAndroid Build Coastguard Worker 	numwritten = write(fd, buf, buflen - 1);
207*053f45beSAndroid Build Coastguard Worker 	close(fd);
208*053f45beSAndroid Build Coastguard Worker 	if (numwritten < 1) {
209*053f45beSAndroid Build Coastguard Worker 		printf("write(%s)\n", buf);
210*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
211*053f45beSAndroid Build Coastguard Worker 		return 0;
212*053f45beSAndroid Build Coastguard Worker 	}
213*053f45beSAndroid Build Coastguard Worker 
214*053f45beSAndroid Build Coastguard Worker 	return (unsigned int) numwritten;
215*053f45beSAndroid Build Coastguard Worker }
216*053f45beSAndroid Build Coastguard Worker 
read_string(const char * name,const char * strings[])217*053f45beSAndroid Build Coastguard Worker static int read_string(const char *name, const char *strings[])
218*053f45beSAndroid Build Coastguard Worker {
219*053f45beSAndroid Build Coastguard Worker 	char path[PATH_MAX];
220*053f45beSAndroid Build Coastguard Worker 	char buf[256];
221*053f45beSAndroid Build Coastguard Worker 	char *c;
222*053f45beSAndroid Build Coastguard Worker 	int ret;
223*053f45beSAndroid Build Coastguard Worker 
224*053f45beSAndroid Build Coastguard Worker 	ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
225*053f45beSAndroid Build Coastguard Worker 	if (ret >= PATH_MAX) {
226*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pathname is too long\n", __func__);
227*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
228*053f45beSAndroid Build Coastguard Worker 	}
229*053f45beSAndroid Build Coastguard Worker 
230*053f45beSAndroid Build Coastguard Worker 	if (!read_file(path, buf, sizeof(buf))) {
231*053f45beSAndroid Build Coastguard Worker 		perror(path);
232*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
233*053f45beSAndroid Build Coastguard Worker 	}
234*053f45beSAndroid Build Coastguard Worker 
235*053f45beSAndroid Build Coastguard Worker 	c = strchr(buf, '[');
236*053f45beSAndroid Build Coastguard Worker 	if (!c) {
237*053f45beSAndroid Build Coastguard Worker 		printf("%s: Parse failure\n", __func__);
238*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
239*053f45beSAndroid Build Coastguard Worker 	}
240*053f45beSAndroid Build Coastguard Worker 
241*053f45beSAndroid Build Coastguard Worker 	c++;
242*053f45beSAndroid Build Coastguard Worker 	memmove(buf, c, sizeof(buf) - (c - buf));
243*053f45beSAndroid Build Coastguard Worker 
244*053f45beSAndroid Build Coastguard Worker 	c = strchr(buf, ']');
245*053f45beSAndroid Build Coastguard Worker 	if (!c) {
246*053f45beSAndroid Build Coastguard Worker 		printf("%s: Parse failure\n", __func__);
247*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
248*053f45beSAndroid Build Coastguard Worker 	}
249*053f45beSAndroid Build Coastguard Worker 	*c = '\0';
250*053f45beSAndroid Build Coastguard Worker 
251*053f45beSAndroid Build Coastguard Worker 	ret = 0;
252*053f45beSAndroid Build Coastguard Worker 	while (strings[ret]) {
253*053f45beSAndroid Build Coastguard Worker 		if (!strcmp(strings[ret], buf))
254*053f45beSAndroid Build Coastguard Worker 			return ret;
255*053f45beSAndroid Build Coastguard Worker 		ret++;
256*053f45beSAndroid Build Coastguard Worker 	}
257*053f45beSAndroid Build Coastguard Worker 
258*053f45beSAndroid Build Coastguard Worker 	printf("Failed to parse %s\n", name);
259*053f45beSAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
260*053f45beSAndroid Build Coastguard Worker }
261*053f45beSAndroid Build Coastguard Worker 
write_string(const char * name,const char * val)262*053f45beSAndroid Build Coastguard Worker static void write_string(const char *name, const char *val)
263*053f45beSAndroid Build Coastguard Worker {
264*053f45beSAndroid Build Coastguard Worker 	char path[PATH_MAX];
265*053f45beSAndroid Build Coastguard Worker 	int ret;
266*053f45beSAndroid Build Coastguard Worker 
267*053f45beSAndroid Build Coastguard Worker 	ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
268*053f45beSAndroid Build Coastguard Worker 	if (ret >= PATH_MAX) {
269*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pathname is too long\n", __func__);
270*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
271*053f45beSAndroid Build Coastguard Worker 	}
272*053f45beSAndroid Build Coastguard Worker 
273*053f45beSAndroid Build Coastguard Worker 	if (!write_file(path, val, strlen(val) + 1)) {
274*053f45beSAndroid Build Coastguard Worker 		perror(path);
275*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
276*053f45beSAndroid Build Coastguard Worker 	}
277*053f45beSAndroid Build Coastguard Worker }
278*053f45beSAndroid Build Coastguard Worker 
_read_num(const char * path)279*053f45beSAndroid Build Coastguard Worker static const unsigned long _read_num(const char *path)
280*053f45beSAndroid Build Coastguard Worker {
281*053f45beSAndroid Build Coastguard Worker 	char buf[21];
282*053f45beSAndroid Build Coastguard Worker 
283*053f45beSAndroid Build Coastguard Worker 	if (read_file(path, buf, sizeof(buf)) < 0) {
284*053f45beSAndroid Build Coastguard Worker 		perror("read_file(read_num)");
285*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
286*053f45beSAndroid Build Coastguard Worker 	}
287*053f45beSAndroid Build Coastguard Worker 
288*053f45beSAndroid Build Coastguard Worker 	return strtoul(buf, NULL, 10);
289*053f45beSAndroid Build Coastguard Worker }
290*053f45beSAndroid Build Coastguard Worker 
read_num(const char * name)291*053f45beSAndroid Build Coastguard Worker static const unsigned long read_num(const char *name)
292*053f45beSAndroid Build Coastguard Worker {
293*053f45beSAndroid Build Coastguard Worker 	char path[PATH_MAX];
294*053f45beSAndroid Build Coastguard Worker 	int ret;
295*053f45beSAndroid Build Coastguard Worker 
296*053f45beSAndroid Build Coastguard Worker 	ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
297*053f45beSAndroid Build Coastguard Worker 	if (ret >= PATH_MAX) {
298*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pathname is too long\n", __func__);
299*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
300*053f45beSAndroid Build Coastguard Worker 	}
301*053f45beSAndroid Build Coastguard Worker 	return _read_num(path);
302*053f45beSAndroid Build Coastguard Worker }
303*053f45beSAndroid Build Coastguard Worker 
_write_num(const char * path,unsigned long num)304*053f45beSAndroid Build Coastguard Worker static void _write_num(const char *path, unsigned long num)
305*053f45beSAndroid Build Coastguard Worker {
306*053f45beSAndroid Build Coastguard Worker 	char buf[21];
307*053f45beSAndroid Build Coastguard Worker 
308*053f45beSAndroid Build Coastguard Worker 	sprintf(buf, "%ld", num);
309*053f45beSAndroid Build Coastguard Worker 	if (!write_file(path, buf, strlen(buf) + 1)) {
310*053f45beSAndroid Build Coastguard Worker 		perror(path);
311*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
312*053f45beSAndroid Build Coastguard Worker 	}
313*053f45beSAndroid Build Coastguard Worker }
314*053f45beSAndroid Build Coastguard Worker 
write_num(const char * name,unsigned long num)315*053f45beSAndroid Build Coastguard Worker static void write_num(const char *name, unsigned long num)
316*053f45beSAndroid Build Coastguard Worker {
317*053f45beSAndroid Build Coastguard Worker 	char path[PATH_MAX];
318*053f45beSAndroid Build Coastguard Worker 	int ret;
319*053f45beSAndroid Build Coastguard Worker 
320*053f45beSAndroid Build Coastguard Worker 	ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
321*053f45beSAndroid Build Coastguard Worker 	if (ret >= PATH_MAX) {
322*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pathname is too long\n", __func__);
323*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
324*053f45beSAndroid Build Coastguard Worker 	}
325*053f45beSAndroid Build Coastguard Worker 	_write_num(path, num);
326*053f45beSAndroid Build Coastguard Worker }
327*053f45beSAndroid Build Coastguard Worker 
write_settings(struct settings * settings)328*053f45beSAndroid Build Coastguard Worker static void write_settings(struct settings *settings)
329*053f45beSAndroid Build Coastguard Worker {
330*053f45beSAndroid Build Coastguard Worker 	struct khugepaged_settings *khugepaged = &settings->khugepaged;
331*053f45beSAndroid Build Coastguard Worker 
332*053f45beSAndroid Build Coastguard Worker 	write_string("enabled", thp_enabled_strings[settings->thp_enabled]);
333*053f45beSAndroid Build Coastguard Worker 	write_string("defrag", thp_defrag_strings[settings->thp_defrag]);
334*053f45beSAndroid Build Coastguard Worker 	write_string("shmem_enabled",
335*053f45beSAndroid Build Coastguard Worker 			shmem_enabled_strings[settings->shmem_enabled]);
336*053f45beSAndroid Build Coastguard Worker 	write_num("use_zero_page", settings->use_zero_page);
337*053f45beSAndroid Build Coastguard Worker 
338*053f45beSAndroid Build Coastguard Worker 	write_num("khugepaged/defrag", khugepaged->defrag);
339*053f45beSAndroid Build Coastguard Worker 	write_num("khugepaged/alloc_sleep_millisecs",
340*053f45beSAndroid Build Coastguard Worker 			khugepaged->alloc_sleep_millisecs);
341*053f45beSAndroid Build Coastguard Worker 	write_num("khugepaged/scan_sleep_millisecs",
342*053f45beSAndroid Build Coastguard Worker 			khugepaged->scan_sleep_millisecs);
343*053f45beSAndroid Build Coastguard Worker 	write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
344*053f45beSAndroid Build Coastguard Worker 	write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
345*053f45beSAndroid Build Coastguard Worker 	write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared);
346*053f45beSAndroid Build Coastguard Worker 	write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan);
347*053f45beSAndroid Build Coastguard Worker 
348*053f45beSAndroid Build Coastguard Worker 	if (file_ops && finfo.type == VMA_FILE)
349*053f45beSAndroid Build Coastguard Worker 		_write_num(finfo.dev_queue_read_ahead_path,
350*053f45beSAndroid Build Coastguard Worker 			   settings->read_ahead_kb);
351*053f45beSAndroid Build Coastguard Worker }
352*053f45beSAndroid Build Coastguard Worker 
353*053f45beSAndroid Build Coastguard Worker #define MAX_SETTINGS_DEPTH 4
354*053f45beSAndroid Build Coastguard Worker static struct settings settings_stack[MAX_SETTINGS_DEPTH];
355*053f45beSAndroid Build Coastguard Worker static int settings_index;
356*053f45beSAndroid Build Coastguard Worker 
current_settings(void)357*053f45beSAndroid Build Coastguard Worker static struct settings *current_settings(void)
358*053f45beSAndroid Build Coastguard Worker {
359*053f45beSAndroid Build Coastguard Worker 	if (!settings_index) {
360*053f45beSAndroid Build Coastguard Worker 		printf("Fail: No settings set");
361*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
362*053f45beSAndroid Build Coastguard Worker 	}
363*053f45beSAndroid Build Coastguard Worker 	return settings_stack + settings_index - 1;
364*053f45beSAndroid Build Coastguard Worker }
365*053f45beSAndroid Build Coastguard Worker 
push_settings(struct settings * settings)366*053f45beSAndroid Build Coastguard Worker static void push_settings(struct settings *settings)
367*053f45beSAndroid Build Coastguard Worker {
368*053f45beSAndroid Build Coastguard Worker 	if (settings_index >= MAX_SETTINGS_DEPTH) {
369*053f45beSAndroid Build Coastguard Worker 		printf("Fail: Settings stack exceeded");
370*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
371*053f45beSAndroid Build Coastguard Worker 	}
372*053f45beSAndroid Build Coastguard Worker 	settings_stack[settings_index++] = *settings;
373*053f45beSAndroid Build Coastguard Worker 	write_settings(current_settings());
374*053f45beSAndroid Build Coastguard Worker }
375*053f45beSAndroid Build Coastguard Worker 
pop_settings(void)376*053f45beSAndroid Build Coastguard Worker static void pop_settings(void)
377*053f45beSAndroid Build Coastguard Worker {
378*053f45beSAndroid Build Coastguard Worker 	if (settings_index <= 0) {
379*053f45beSAndroid Build Coastguard Worker 		printf("Fail: Settings stack empty");
380*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
381*053f45beSAndroid Build Coastguard Worker 	}
382*053f45beSAndroid Build Coastguard Worker 	--settings_index;
383*053f45beSAndroid Build Coastguard Worker 	write_settings(current_settings());
384*053f45beSAndroid Build Coastguard Worker }
385*053f45beSAndroid Build Coastguard Worker 
restore_settings(int sig)386*053f45beSAndroid Build Coastguard Worker static void restore_settings(int sig)
387*053f45beSAndroid Build Coastguard Worker {
388*053f45beSAndroid Build Coastguard Worker 	if (skip_settings_restore)
389*053f45beSAndroid Build Coastguard Worker 		goto out;
390*053f45beSAndroid Build Coastguard Worker 
391*053f45beSAndroid Build Coastguard Worker 	printf("Restore THP and khugepaged settings...");
392*053f45beSAndroid Build Coastguard Worker 	write_settings(&saved_settings);
393*053f45beSAndroid Build Coastguard Worker 	success("OK");
394*053f45beSAndroid Build Coastguard Worker 	if (sig)
395*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
396*053f45beSAndroid Build Coastguard Worker out:
397*053f45beSAndroid Build Coastguard Worker 	exit(exit_status);
398*053f45beSAndroid Build Coastguard Worker }
399*053f45beSAndroid Build Coastguard Worker 
save_settings(void)400*053f45beSAndroid Build Coastguard Worker static void save_settings(void)
401*053f45beSAndroid Build Coastguard Worker {
402*053f45beSAndroid Build Coastguard Worker 	printf("Save THP and khugepaged settings...");
403*053f45beSAndroid Build Coastguard Worker 	saved_settings = (struct settings) {
404*053f45beSAndroid Build Coastguard Worker 		.thp_enabled = read_string("enabled", thp_enabled_strings),
405*053f45beSAndroid Build Coastguard Worker 		.thp_defrag = read_string("defrag", thp_defrag_strings),
406*053f45beSAndroid Build Coastguard Worker 		.shmem_enabled =
407*053f45beSAndroid Build Coastguard Worker 			read_string("shmem_enabled", shmem_enabled_strings),
408*053f45beSAndroid Build Coastguard Worker 		.use_zero_page = read_num("use_zero_page"),
409*053f45beSAndroid Build Coastguard Worker 	};
410*053f45beSAndroid Build Coastguard Worker 	saved_settings.khugepaged = (struct khugepaged_settings) {
411*053f45beSAndroid Build Coastguard Worker 		.defrag = read_num("khugepaged/defrag"),
412*053f45beSAndroid Build Coastguard Worker 		.alloc_sleep_millisecs =
413*053f45beSAndroid Build Coastguard Worker 			read_num("khugepaged/alloc_sleep_millisecs"),
414*053f45beSAndroid Build Coastguard Worker 		.scan_sleep_millisecs =
415*053f45beSAndroid Build Coastguard Worker 			read_num("khugepaged/scan_sleep_millisecs"),
416*053f45beSAndroid Build Coastguard Worker 		.max_ptes_none = read_num("khugepaged/max_ptes_none"),
417*053f45beSAndroid Build Coastguard Worker 		.max_ptes_swap = read_num("khugepaged/max_ptes_swap"),
418*053f45beSAndroid Build Coastguard Worker 		.max_ptes_shared = read_num("khugepaged/max_ptes_shared"),
419*053f45beSAndroid Build Coastguard Worker 		.pages_to_scan = read_num("khugepaged/pages_to_scan"),
420*053f45beSAndroid Build Coastguard Worker 	};
421*053f45beSAndroid Build Coastguard Worker 	if (file_ops && finfo.type == VMA_FILE)
422*053f45beSAndroid Build Coastguard Worker 		saved_settings.read_ahead_kb =
423*053f45beSAndroid Build Coastguard Worker 				_read_num(finfo.dev_queue_read_ahead_path);
424*053f45beSAndroid Build Coastguard Worker 
425*053f45beSAndroid Build Coastguard Worker 	success("OK");
426*053f45beSAndroid Build Coastguard Worker 
427*053f45beSAndroid Build Coastguard Worker 	signal(SIGTERM, restore_settings);
428*053f45beSAndroid Build Coastguard Worker 	signal(SIGINT, restore_settings);
429*053f45beSAndroid Build Coastguard Worker 	signal(SIGHUP, restore_settings);
430*053f45beSAndroid Build Coastguard Worker 	signal(SIGQUIT, restore_settings);
431*053f45beSAndroid Build Coastguard Worker }
432*053f45beSAndroid Build Coastguard Worker 
get_finfo(const char * dir)433*053f45beSAndroid Build Coastguard Worker static void get_finfo(const char *dir)
434*053f45beSAndroid Build Coastguard Worker {
435*053f45beSAndroid Build Coastguard Worker 	struct stat path_stat;
436*053f45beSAndroid Build Coastguard Worker 	struct statfs fs;
437*053f45beSAndroid Build Coastguard Worker 	char buf[1 << 10];
438*053f45beSAndroid Build Coastguard Worker 	char path[PATH_MAX];
439*053f45beSAndroid Build Coastguard Worker 	char *str, *end;
440*053f45beSAndroid Build Coastguard Worker 
441*053f45beSAndroid Build Coastguard Worker 	finfo.dir = dir;
442*053f45beSAndroid Build Coastguard Worker 	stat(finfo.dir, &path_stat);
443*053f45beSAndroid Build Coastguard Worker 	if (!S_ISDIR(path_stat.st_mode)) {
444*053f45beSAndroid Build Coastguard Worker 		printf("%s: Not a directory (%s)\n", __func__, finfo.dir);
445*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
446*053f45beSAndroid Build Coastguard Worker 	}
447*053f45beSAndroid Build Coastguard Worker 	if (snprintf(finfo.path, sizeof(finfo.path), "%s/" TEST_FILE,
448*053f45beSAndroid Build Coastguard Worker 		     finfo.dir) >= sizeof(finfo.path)) {
449*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pathname is too long\n", __func__);
450*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
451*053f45beSAndroid Build Coastguard Worker 	}
452*053f45beSAndroid Build Coastguard Worker 	if (statfs(finfo.dir, &fs)) {
453*053f45beSAndroid Build Coastguard Worker 		perror("statfs()");
454*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
455*053f45beSAndroid Build Coastguard Worker 	}
456*053f45beSAndroid Build Coastguard Worker 	finfo.type = fs.f_type == TMPFS_MAGIC ? VMA_SHMEM : VMA_FILE;
457*053f45beSAndroid Build Coastguard Worker 	if (finfo.type == VMA_SHMEM)
458*053f45beSAndroid Build Coastguard Worker 		return;
459*053f45beSAndroid Build Coastguard Worker 
460*053f45beSAndroid Build Coastguard Worker 	/* Find owning device's queue/read_ahead_kb control */
461*053f45beSAndroid Build Coastguard Worker 	if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/uevent",
462*053f45beSAndroid Build Coastguard Worker 		     major(path_stat.st_dev), minor(path_stat.st_dev))
463*053f45beSAndroid Build Coastguard Worker 	    >= sizeof(path)) {
464*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pathname is too long\n", __func__);
465*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
466*053f45beSAndroid Build Coastguard Worker 	}
467*053f45beSAndroid Build Coastguard Worker 	if (read_file(path, buf, sizeof(buf)) < 0) {
468*053f45beSAndroid Build Coastguard Worker 		perror("read_file(read_num)");
469*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
470*053f45beSAndroid Build Coastguard Worker 	}
471*053f45beSAndroid Build Coastguard Worker 	if (strstr(buf, "DEVTYPE=disk")) {
472*053f45beSAndroid Build Coastguard Worker 		/* Found it */
473*053f45beSAndroid Build Coastguard Worker 		if (snprintf(finfo.dev_queue_read_ahead_path,
474*053f45beSAndroid Build Coastguard Worker 			     sizeof(finfo.dev_queue_read_ahead_path),
475*053f45beSAndroid Build Coastguard Worker 			     "/sys/dev/block/%d:%d/queue/read_ahead_kb",
476*053f45beSAndroid Build Coastguard Worker 			     major(path_stat.st_dev), minor(path_stat.st_dev))
477*053f45beSAndroid Build Coastguard Worker 		    >= sizeof(finfo.dev_queue_read_ahead_path)) {
478*053f45beSAndroid Build Coastguard Worker 			printf("%s: Pathname is too long\n", __func__);
479*053f45beSAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
480*053f45beSAndroid Build Coastguard Worker 		}
481*053f45beSAndroid Build Coastguard Worker 		return;
482*053f45beSAndroid Build Coastguard Worker 	}
483*053f45beSAndroid Build Coastguard Worker 	if (!strstr(buf, "DEVTYPE=partition")) {
484*053f45beSAndroid Build Coastguard Worker 		printf("%s: Unknown device type: %s\n", __func__, path);
485*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
486*053f45beSAndroid Build Coastguard Worker 	}
487*053f45beSAndroid Build Coastguard Worker 	/*
488*053f45beSAndroid Build Coastguard Worker 	 * Partition of block device - need to find actual device.
489*053f45beSAndroid Build Coastguard Worker 	 * Using naming convention that devnameN is partition of
490*053f45beSAndroid Build Coastguard Worker 	 * device devname.
491*053f45beSAndroid Build Coastguard Worker 	 */
492*053f45beSAndroid Build Coastguard Worker 	str = strstr(buf, "DEVNAME=");
493*053f45beSAndroid Build Coastguard Worker 	if (!str) {
494*053f45beSAndroid Build Coastguard Worker 		printf("%s: Could not read: %s", __func__, path);
495*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
496*053f45beSAndroid Build Coastguard Worker 	}
497*053f45beSAndroid Build Coastguard Worker 	str += 8;
498*053f45beSAndroid Build Coastguard Worker 	end = str;
499*053f45beSAndroid Build Coastguard Worker 	while (*end) {
500*053f45beSAndroid Build Coastguard Worker 		if (isdigit(*end)) {
501*053f45beSAndroid Build Coastguard Worker 			*end = '\0';
502*053f45beSAndroid Build Coastguard Worker 			if (snprintf(finfo.dev_queue_read_ahead_path,
503*053f45beSAndroid Build Coastguard Worker 				     sizeof(finfo.dev_queue_read_ahead_path),
504*053f45beSAndroid Build Coastguard Worker 				     "/sys/block/%s/queue/read_ahead_kb",
505*053f45beSAndroid Build Coastguard Worker 				     str) >= sizeof(finfo.dev_queue_read_ahead_path)) {
506*053f45beSAndroid Build Coastguard Worker 				printf("%s: Pathname is too long\n", __func__);
507*053f45beSAndroid Build Coastguard Worker 				exit(EXIT_FAILURE);
508*053f45beSAndroid Build Coastguard Worker 			}
509*053f45beSAndroid Build Coastguard Worker 			return;
510*053f45beSAndroid Build Coastguard Worker 		}
511*053f45beSAndroid Build Coastguard Worker 		++end;
512*053f45beSAndroid Build Coastguard Worker 	}
513*053f45beSAndroid Build Coastguard Worker 	printf("%s: Could not read: %s\n", __func__, path);
514*053f45beSAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
515*053f45beSAndroid Build Coastguard Worker }
516*053f45beSAndroid Build Coastguard Worker 
check_swap(void * addr,unsigned long size)517*053f45beSAndroid Build Coastguard Worker static bool check_swap(void *addr, unsigned long size)
518*053f45beSAndroid Build Coastguard Worker {
519*053f45beSAndroid Build Coastguard Worker 	bool swap = false;
520*053f45beSAndroid Build Coastguard Worker 	int ret;
521*053f45beSAndroid Build Coastguard Worker 	FILE *fp;
522*053f45beSAndroid Build Coastguard Worker 	char buffer[MAX_LINE_LENGTH];
523*053f45beSAndroid Build Coastguard Worker 	char addr_pattern[MAX_LINE_LENGTH];
524*053f45beSAndroid Build Coastguard Worker 
525*053f45beSAndroid Build Coastguard Worker 	ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
526*053f45beSAndroid Build Coastguard Worker 		       (unsigned long) addr);
527*053f45beSAndroid Build Coastguard Worker 	if (ret >= MAX_LINE_LENGTH) {
528*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pattern is too long\n", __func__);
529*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
530*053f45beSAndroid Build Coastguard Worker 	}
531*053f45beSAndroid Build Coastguard Worker 
532*053f45beSAndroid Build Coastguard Worker 
533*053f45beSAndroid Build Coastguard Worker 	fp = fopen(PID_SMAPS, "r");
534*053f45beSAndroid Build Coastguard Worker 	if (!fp) {
535*053f45beSAndroid Build Coastguard Worker 		printf("%s: Failed to open file %s\n", __func__, PID_SMAPS);
536*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
537*053f45beSAndroid Build Coastguard Worker 	}
538*053f45beSAndroid Build Coastguard Worker 	if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer)))
539*053f45beSAndroid Build Coastguard Worker 		goto err_out;
540*053f45beSAndroid Build Coastguard Worker 
541*053f45beSAndroid Build Coastguard Worker 	ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "Swap:%19ld kB",
542*053f45beSAndroid Build Coastguard Worker 		       size >> 10);
543*053f45beSAndroid Build Coastguard Worker 	if (ret >= MAX_LINE_LENGTH) {
544*053f45beSAndroid Build Coastguard Worker 		printf("%s: Pattern is too long\n", __func__);
545*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
546*053f45beSAndroid Build Coastguard Worker 	}
547*053f45beSAndroid Build Coastguard Worker 	/*
548*053f45beSAndroid Build Coastguard Worker 	 * Fetch the Swap: in the same block and check whether it got
549*053f45beSAndroid Build Coastguard Worker 	 * the expected number of hugeepages next.
550*053f45beSAndroid Build Coastguard Worker 	 */
551*053f45beSAndroid Build Coastguard Worker 	if (!check_for_pattern(fp, "Swap:", buffer, sizeof(buffer)))
552*053f45beSAndroid Build Coastguard Worker 		goto err_out;
553*053f45beSAndroid Build Coastguard Worker 
554*053f45beSAndroid Build Coastguard Worker 	if (strncmp(buffer, addr_pattern, strlen(addr_pattern)))
555*053f45beSAndroid Build Coastguard Worker 		goto err_out;
556*053f45beSAndroid Build Coastguard Worker 
557*053f45beSAndroid Build Coastguard Worker 	swap = true;
558*053f45beSAndroid Build Coastguard Worker err_out:
559*053f45beSAndroid Build Coastguard Worker 	fclose(fp);
560*053f45beSAndroid Build Coastguard Worker 	return swap;
561*053f45beSAndroid Build Coastguard Worker }
562*053f45beSAndroid Build Coastguard Worker 
alloc_mapping(int nr)563*053f45beSAndroid Build Coastguard Worker static void *alloc_mapping(int nr)
564*053f45beSAndroid Build Coastguard Worker {
565*053f45beSAndroid Build Coastguard Worker 	void *p;
566*053f45beSAndroid Build Coastguard Worker 
567*053f45beSAndroid Build Coastguard Worker 	p = mmap(BASE_ADDR, nr * hpage_pmd_size, PROT_READ | PROT_WRITE,
568*053f45beSAndroid Build Coastguard Worker 		 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
569*053f45beSAndroid Build Coastguard Worker 	if (p != BASE_ADDR) {
570*053f45beSAndroid Build Coastguard Worker 		printf("Failed to allocate VMA at %p\n", BASE_ADDR);
571*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
572*053f45beSAndroid Build Coastguard Worker 	}
573*053f45beSAndroid Build Coastguard Worker 
574*053f45beSAndroid Build Coastguard Worker 	return p;
575*053f45beSAndroid Build Coastguard Worker }
576*053f45beSAndroid Build Coastguard Worker 
fill_memory(int * p,unsigned long start,unsigned long end)577*053f45beSAndroid Build Coastguard Worker static void fill_memory(int *p, unsigned long start, unsigned long end)
578*053f45beSAndroid Build Coastguard Worker {
579*053f45beSAndroid Build Coastguard Worker 	int i;
580*053f45beSAndroid Build Coastguard Worker 
581*053f45beSAndroid Build Coastguard Worker 	for (i = start / page_size; i < end / page_size; i++)
582*053f45beSAndroid Build Coastguard Worker 		p[i * page_size / sizeof(*p)] = i + 0xdead0000;
583*053f45beSAndroid Build Coastguard Worker }
584*053f45beSAndroid Build Coastguard Worker 
585*053f45beSAndroid Build Coastguard Worker /*
586*053f45beSAndroid Build Coastguard Worker  * MADV_COLLAPSE is a best-effort request and may fail if an internal
587*053f45beSAndroid Build Coastguard Worker  * resource is temporarily unavailable, in which case it will set errno to
588*053f45beSAndroid Build Coastguard Worker  * EAGAIN.  In such a case, immediately reattempt the operation one more
589*053f45beSAndroid Build Coastguard Worker  * time.
590*053f45beSAndroid Build Coastguard Worker  */
madvise_collapse_retry(void * p,unsigned long size)591*053f45beSAndroid Build Coastguard Worker static int madvise_collapse_retry(void *p, unsigned long size)
592*053f45beSAndroid Build Coastguard Worker {
593*053f45beSAndroid Build Coastguard Worker 	bool retry = true;
594*053f45beSAndroid Build Coastguard Worker 	int ret;
595*053f45beSAndroid Build Coastguard Worker 
596*053f45beSAndroid Build Coastguard Worker retry:
597*053f45beSAndroid Build Coastguard Worker 	ret = madvise(p, size, MADV_COLLAPSE);
598*053f45beSAndroid Build Coastguard Worker 	if (ret && errno == EAGAIN && retry) {
599*053f45beSAndroid Build Coastguard Worker 		retry = false;
600*053f45beSAndroid Build Coastguard Worker 		goto retry;
601*053f45beSAndroid Build Coastguard Worker 	}
602*053f45beSAndroid Build Coastguard Worker 	return ret;
603*053f45beSAndroid Build Coastguard Worker }
604*053f45beSAndroid Build Coastguard Worker 
605*053f45beSAndroid Build Coastguard Worker /*
606*053f45beSAndroid Build Coastguard Worker  * Returns pmd-mapped hugepage in VMA marked VM_HUGEPAGE, filled with
607*053f45beSAndroid Build Coastguard Worker  * validate_memory()'able contents.
608*053f45beSAndroid Build Coastguard Worker  */
alloc_hpage(struct mem_ops * ops)609*053f45beSAndroid Build Coastguard Worker static void *alloc_hpage(struct mem_ops *ops)
610*053f45beSAndroid Build Coastguard Worker {
611*053f45beSAndroid Build Coastguard Worker 	void *p = ops->setup_area(1);
612*053f45beSAndroid Build Coastguard Worker 
613*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, hpage_pmd_size);
614*053f45beSAndroid Build Coastguard Worker 
615*053f45beSAndroid Build Coastguard Worker 	/*
616*053f45beSAndroid Build Coastguard Worker 	 * VMA should be neither VM_HUGEPAGE nor VM_NOHUGEPAGE.
617*053f45beSAndroid Build Coastguard Worker 	 * The latter is ineligible for collapse by MADV_COLLAPSE
618*053f45beSAndroid Build Coastguard Worker 	 * while the former might cause MADV_COLLAPSE to race with
619*053f45beSAndroid Build Coastguard Worker 	 * khugepaged on low-load system (like a test machine), which
620*053f45beSAndroid Build Coastguard Worker 	 * would cause MADV_COLLAPSE to fail with EAGAIN.
621*053f45beSAndroid Build Coastguard Worker 	 */
622*053f45beSAndroid Build Coastguard Worker 	printf("Allocate huge page...");
623*053f45beSAndroid Build Coastguard Worker 	if (madvise_collapse_retry(p, hpage_pmd_size)) {
624*053f45beSAndroid Build Coastguard Worker 		perror("madvise(MADV_COLLAPSE)");
625*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
626*053f45beSAndroid Build Coastguard Worker 	}
627*053f45beSAndroid Build Coastguard Worker 	if (!ops->check_huge(p, 1)) {
628*053f45beSAndroid Build Coastguard Worker 		perror("madvise(MADV_COLLAPSE)");
629*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
630*053f45beSAndroid Build Coastguard Worker 	}
631*053f45beSAndroid Build Coastguard Worker 	if (madvise(p, hpage_pmd_size, MADV_HUGEPAGE)) {
632*053f45beSAndroid Build Coastguard Worker 		perror("madvise(MADV_HUGEPAGE)");
633*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
634*053f45beSAndroid Build Coastguard Worker 	}
635*053f45beSAndroid Build Coastguard Worker 	success("OK");
636*053f45beSAndroid Build Coastguard Worker 	return p;
637*053f45beSAndroid Build Coastguard Worker }
638*053f45beSAndroid Build Coastguard Worker 
validate_memory(int * p,unsigned long start,unsigned long end)639*053f45beSAndroid Build Coastguard Worker static void validate_memory(int *p, unsigned long start, unsigned long end)
640*053f45beSAndroid Build Coastguard Worker {
641*053f45beSAndroid Build Coastguard Worker 	int i;
642*053f45beSAndroid Build Coastguard Worker 
643*053f45beSAndroid Build Coastguard Worker 	for (i = start / page_size; i < end / page_size; i++) {
644*053f45beSAndroid Build Coastguard Worker 		if (p[i * page_size / sizeof(*p)] != i + 0xdead0000) {
645*053f45beSAndroid Build Coastguard Worker 			printf("Page %d is corrupted: %#x\n",
646*053f45beSAndroid Build Coastguard Worker 					i, p[i * page_size / sizeof(*p)]);
647*053f45beSAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
648*053f45beSAndroid Build Coastguard Worker 		}
649*053f45beSAndroid Build Coastguard Worker 	}
650*053f45beSAndroid Build Coastguard Worker }
651*053f45beSAndroid Build Coastguard Worker 
anon_setup_area(int nr_hpages)652*053f45beSAndroid Build Coastguard Worker static void *anon_setup_area(int nr_hpages)
653*053f45beSAndroid Build Coastguard Worker {
654*053f45beSAndroid Build Coastguard Worker 	return alloc_mapping(nr_hpages);
655*053f45beSAndroid Build Coastguard Worker }
656*053f45beSAndroid Build Coastguard Worker 
anon_cleanup_area(void * p,unsigned long size)657*053f45beSAndroid Build Coastguard Worker static void anon_cleanup_area(void *p, unsigned long size)
658*053f45beSAndroid Build Coastguard Worker {
659*053f45beSAndroid Build Coastguard Worker 	munmap(p, size);
660*053f45beSAndroid Build Coastguard Worker }
661*053f45beSAndroid Build Coastguard Worker 
anon_fault(void * p,unsigned long start,unsigned long end)662*053f45beSAndroid Build Coastguard Worker static void anon_fault(void *p, unsigned long start, unsigned long end)
663*053f45beSAndroid Build Coastguard Worker {
664*053f45beSAndroid Build Coastguard Worker 	fill_memory(p, start, end);
665*053f45beSAndroid Build Coastguard Worker }
666*053f45beSAndroid Build Coastguard Worker 
anon_check_huge(void * addr,int nr_hpages)667*053f45beSAndroid Build Coastguard Worker static bool anon_check_huge(void *addr, int nr_hpages)
668*053f45beSAndroid Build Coastguard Worker {
669*053f45beSAndroid Build Coastguard Worker 	return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
670*053f45beSAndroid Build Coastguard Worker }
671*053f45beSAndroid Build Coastguard Worker 
file_setup_area(int nr_hpages)672*053f45beSAndroid Build Coastguard Worker static void *file_setup_area(int nr_hpages)
673*053f45beSAndroid Build Coastguard Worker {
674*053f45beSAndroid Build Coastguard Worker 	int fd;
675*053f45beSAndroid Build Coastguard Worker 	void *p;
676*053f45beSAndroid Build Coastguard Worker 	unsigned long size;
677*053f45beSAndroid Build Coastguard Worker 
678*053f45beSAndroid Build Coastguard Worker 	unlink(finfo.path);  /* Cleanup from previous failed tests */
679*053f45beSAndroid Build Coastguard Worker 	printf("Creating %s for collapse%s...", finfo.path,
680*053f45beSAndroid Build Coastguard Worker 	       finfo.type == VMA_SHMEM ? " (tmpfs)" : "");
681*053f45beSAndroid Build Coastguard Worker 	fd = open(finfo.path, O_DSYNC | O_CREAT | O_RDWR | O_TRUNC | O_EXCL,
682*053f45beSAndroid Build Coastguard Worker 		  777);
683*053f45beSAndroid Build Coastguard Worker 	if (fd < 0) {
684*053f45beSAndroid Build Coastguard Worker 		perror("open()");
685*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
686*053f45beSAndroid Build Coastguard Worker 	}
687*053f45beSAndroid Build Coastguard Worker 
688*053f45beSAndroid Build Coastguard Worker 	size = nr_hpages * hpage_pmd_size;
689*053f45beSAndroid Build Coastguard Worker 	p = alloc_mapping(nr_hpages);
690*053f45beSAndroid Build Coastguard Worker 	fill_memory(p, 0, size);
691*053f45beSAndroid Build Coastguard Worker 	write(fd, p, size);
692*053f45beSAndroid Build Coastguard Worker 	close(fd);
693*053f45beSAndroid Build Coastguard Worker 	munmap(p, size);
694*053f45beSAndroid Build Coastguard Worker 	success("OK");
695*053f45beSAndroid Build Coastguard Worker 
696*053f45beSAndroid Build Coastguard Worker 	printf("Opening %s read only for collapse...", finfo.path);
697*053f45beSAndroid Build Coastguard Worker 	finfo.fd = open(finfo.path, O_RDONLY, 777);
698*053f45beSAndroid Build Coastguard Worker 	if (finfo.fd < 0) {
699*053f45beSAndroid Build Coastguard Worker 		perror("open()");
700*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
701*053f45beSAndroid Build Coastguard Worker 	}
702*053f45beSAndroid Build Coastguard Worker 	p = mmap(BASE_ADDR, size, PROT_READ | PROT_EXEC,
703*053f45beSAndroid Build Coastguard Worker 		 MAP_PRIVATE, finfo.fd, 0);
704*053f45beSAndroid Build Coastguard Worker 	if (p == MAP_FAILED || p != BASE_ADDR) {
705*053f45beSAndroid Build Coastguard Worker 		perror("mmap()");
706*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
707*053f45beSAndroid Build Coastguard Worker 	}
708*053f45beSAndroid Build Coastguard Worker 
709*053f45beSAndroid Build Coastguard Worker 	/* Drop page cache */
710*053f45beSAndroid Build Coastguard Worker 	write_file("/proc/sys/vm/drop_caches", "3", 2);
711*053f45beSAndroid Build Coastguard Worker 	success("OK");
712*053f45beSAndroid Build Coastguard Worker 	return p;
713*053f45beSAndroid Build Coastguard Worker }
714*053f45beSAndroid Build Coastguard Worker 
file_cleanup_area(void * p,unsigned long size)715*053f45beSAndroid Build Coastguard Worker static void file_cleanup_area(void *p, unsigned long size)
716*053f45beSAndroid Build Coastguard Worker {
717*053f45beSAndroid Build Coastguard Worker 	munmap(p, size);
718*053f45beSAndroid Build Coastguard Worker 	close(finfo.fd);
719*053f45beSAndroid Build Coastguard Worker 	unlink(finfo.path);
720*053f45beSAndroid Build Coastguard Worker }
721*053f45beSAndroid Build Coastguard Worker 
file_fault(void * p,unsigned long start,unsigned long end)722*053f45beSAndroid Build Coastguard Worker static void file_fault(void *p, unsigned long start, unsigned long end)
723*053f45beSAndroid Build Coastguard Worker {
724*053f45beSAndroid Build Coastguard Worker 	if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
725*053f45beSAndroid Build Coastguard Worker 		perror("madvise(MADV_POPULATE_READ");
726*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
727*053f45beSAndroid Build Coastguard Worker 	}
728*053f45beSAndroid Build Coastguard Worker }
729*053f45beSAndroid Build Coastguard Worker 
file_check_huge(void * addr,int nr_hpages)730*053f45beSAndroid Build Coastguard Worker static bool file_check_huge(void *addr, int nr_hpages)
731*053f45beSAndroid Build Coastguard Worker {
732*053f45beSAndroid Build Coastguard Worker 	switch (finfo.type) {
733*053f45beSAndroid Build Coastguard Worker 	case VMA_FILE:
734*053f45beSAndroid Build Coastguard Worker 		return check_huge_file(addr, nr_hpages, hpage_pmd_size);
735*053f45beSAndroid Build Coastguard Worker 	case VMA_SHMEM:
736*053f45beSAndroid Build Coastguard Worker 		return check_huge_shmem(addr, nr_hpages, hpage_pmd_size);
737*053f45beSAndroid Build Coastguard Worker 	default:
738*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
739*053f45beSAndroid Build Coastguard Worker 		return false;
740*053f45beSAndroid Build Coastguard Worker 	}
741*053f45beSAndroid Build Coastguard Worker }
742*053f45beSAndroid Build Coastguard Worker 
shmem_setup_area(int nr_hpages)743*053f45beSAndroid Build Coastguard Worker static void *shmem_setup_area(int nr_hpages)
744*053f45beSAndroid Build Coastguard Worker {
745*053f45beSAndroid Build Coastguard Worker 	void *p;
746*053f45beSAndroid Build Coastguard Worker 	unsigned long size = nr_hpages * hpage_pmd_size;
747*053f45beSAndroid Build Coastguard Worker 
748*053f45beSAndroid Build Coastguard Worker 	finfo.fd = memfd_create("khugepaged-selftest-collapse-shmem", 0);
749*053f45beSAndroid Build Coastguard Worker 	if (finfo.fd < 0)  {
750*053f45beSAndroid Build Coastguard Worker 		perror("memfd_create()");
751*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
752*053f45beSAndroid Build Coastguard Worker 	}
753*053f45beSAndroid Build Coastguard Worker 	if (ftruncate(finfo.fd, size)) {
754*053f45beSAndroid Build Coastguard Worker 		perror("ftruncate()");
755*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
756*053f45beSAndroid Build Coastguard Worker 	}
757*053f45beSAndroid Build Coastguard Worker 	p = mmap(BASE_ADDR, size, PROT_READ | PROT_WRITE, MAP_SHARED, finfo.fd,
758*053f45beSAndroid Build Coastguard Worker 		 0);
759*053f45beSAndroid Build Coastguard Worker 	if (p != BASE_ADDR) {
760*053f45beSAndroid Build Coastguard Worker 		perror("mmap()");
761*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
762*053f45beSAndroid Build Coastguard Worker 	}
763*053f45beSAndroid Build Coastguard Worker 	return p;
764*053f45beSAndroid Build Coastguard Worker }
765*053f45beSAndroid Build Coastguard Worker 
shmem_cleanup_area(void * p,unsigned long size)766*053f45beSAndroid Build Coastguard Worker static void shmem_cleanup_area(void *p, unsigned long size)
767*053f45beSAndroid Build Coastguard Worker {
768*053f45beSAndroid Build Coastguard Worker 	munmap(p, size);
769*053f45beSAndroid Build Coastguard Worker 	close(finfo.fd);
770*053f45beSAndroid Build Coastguard Worker }
771*053f45beSAndroid Build Coastguard Worker 
shmem_check_huge(void * addr,int nr_hpages)772*053f45beSAndroid Build Coastguard Worker static bool shmem_check_huge(void *addr, int nr_hpages)
773*053f45beSAndroid Build Coastguard Worker {
774*053f45beSAndroid Build Coastguard Worker 	return check_huge_shmem(addr, nr_hpages, hpage_pmd_size);
775*053f45beSAndroid Build Coastguard Worker }
776*053f45beSAndroid Build Coastguard Worker 
777*053f45beSAndroid Build Coastguard Worker static struct mem_ops __anon_ops = {
778*053f45beSAndroid Build Coastguard Worker 	.setup_area = &anon_setup_area,
779*053f45beSAndroid Build Coastguard Worker 	.cleanup_area = &anon_cleanup_area,
780*053f45beSAndroid Build Coastguard Worker 	.fault = &anon_fault,
781*053f45beSAndroid Build Coastguard Worker 	.check_huge = &anon_check_huge,
782*053f45beSAndroid Build Coastguard Worker 	.name = "anon",
783*053f45beSAndroid Build Coastguard Worker };
784*053f45beSAndroid Build Coastguard Worker 
785*053f45beSAndroid Build Coastguard Worker static struct mem_ops __file_ops = {
786*053f45beSAndroid Build Coastguard Worker 	.setup_area = &file_setup_area,
787*053f45beSAndroid Build Coastguard Worker 	.cleanup_area = &file_cleanup_area,
788*053f45beSAndroid Build Coastguard Worker 	.fault = &file_fault,
789*053f45beSAndroid Build Coastguard Worker 	.check_huge = &file_check_huge,
790*053f45beSAndroid Build Coastguard Worker 	.name = "file",
791*053f45beSAndroid Build Coastguard Worker };
792*053f45beSAndroid Build Coastguard Worker 
793*053f45beSAndroid Build Coastguard Worker static struct mem_ops __shmem_ops = {
794*053f45beSAndroid Build Coastguard Worker 	.setup_area = &shmem_setup_area,
795*053f45beSAndroid Build Coastguard Worker 	.cleanup_area = &shmem_cleanup_area,
796*053f45beSAndroid Build Coastguard Worker 	.fault = &anon_fault,
797*053f45beSAndroid Build Coastguard Worker 	.check_huge = &shmem_check_huge,
798*053f45beSAndroid Build Coastguard Worker 	.name = "shmem",
799*053f45beSAndroid Build Coastguard Worker };
800*053f45beSAndroid Build Coastguard Worker 
__madvise_collapse(const char * msg,char * p,int nr_hpages,struct mem_ops * ops,bool expect)801*053f45beSAndroid Build Coastguard Worker static void __madvise_collapse(const char *msg, char *p, int nr_hpages,
802*053f45beSAndroid Build Coastguard Worker 			       struct mem_ops *ops, bool expect)
803*053f45beSAndroid Build Coastguard Worker {
804*053f45beSAndroid Build Coastguard Worker 	int ret;
805*053f45beSAndroid Build Coastguard Worker 	struct settings settings = *current_settings();
806*053f45beSAndroid Build Coastguard Worker 
807*053f45beSAndroid Build Coastguard Worker 	printf("%s...", msg);
808*053f45beSAndroid Build Coastguard Worker 
809*053f45beSAndroid Build Coastguard Worker 	/*
810*053f45beSAndroid Build Coastguard Worker 	 * Prevent khugepaged interference and tests that MADV_COLLAPSE
811*053f45beSAndroid Build Coastguard Worker 	 * ignores /sys/kernel/mm/transparent_hugepage/enabled
812*053f45beSAndroid Build Coastguard Worker 	 */
813*053f45beSAndroid Build Coastguard Worker 	settings.thp_enabled = THP_NEVER;
814*053f45beSAndroid Build Coastguard Worker 	settings.shmem_enabled = SHMEM_NEVER;
815*053f45beSAndroid Build Coastguard Worker 	push_settings(&settings);
816*053f45beSAndroid Build Coastguard Worker 
817*053f45beSAndroid Build Coastguard Worker 	/* Clear VM_NOHUGEPAGE */
818*053f45beSAndroid Build Coastguard Worker 	madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE);
819*053f45beSAndroid Build Coastguard Worker 	ret = madvise_collapse_retry(p, nr_hpages * hpage_pmd_size);
820*053f45beSAndroid Build Coastguard Worker 	if (((bool)ret) == expect)
821*053f45beSAndroid Build Coastguard Worker 		fail("Fail: Bad return value");
822*053f45beSAndroid Build Coastguard Worker 	else if (!ops->check_huge(p, expect ? nr_hpages : 0))
823*053f45beSAndroid Build Coastguard Worker 		fail("Fail: check_huge()");
824*053f45beSAndroid Build Coastguard Worker 	else
825*053f45beSAndroid Build Coastguard Worker 		success("OK");
826*053f45beSAndroid Build Coastguard Worker 
827*053f45beSAndroid Build Coastguard Worker 	pop_settings();
828*053f45beSAndroid Build Coastguard Worker }
829*053f45beSAndroid Build Coastguard Worker 
madvise_collapse(const char * msg,char * p,int nr_hpages,struct mem_ops * ops,bool expect)830*053f45beSAndroid Build Coastguard Worker static void madvise_collapse(const char *msg, char *p, int nr_hpages,
831*053f45beSAndroid Build Coastguard Worker 			     struct mem_ops *ops, bool expect)
832*053f45beSAndroid Build Coastguard Worker {
833*053f45beSAndroid Build Coastguard Worker 	/* Sanity check */
834*053f45beSAndroid Build Coastguard Worker 	if (!ops->check_huge(p, 0)) {
835*053f45beSAndroid Build Coastguard Worker 		printf("Unexpected huge page\n");
836*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
837*053f45beSAndroid Build Coastguard Worker 	}
838*053f45beSAndroid Build Coastguard Worker 	__madvise_collapse(msg, p, nr_hpages, ops, expect);
839*053f45beSAndroid Build Coastguard Worker }
840*053f45beSAndroid Build Coastguard Worker 
841*053f45beSAndroid Build Coastguard Worker #define TICK 500000
wait_for_scan(const char * msg,char * p,int nr_hpages,struct mem_ops * ops)842*053f45beSAndroid Build Coastguard Worker static bool wait_for_scan(const char *msg, char *p, int nr_hpages,
843*053f45beSAndroid Build Coastguard Worker 			  struct mem_ops *ops)
844*053f45beSAndroid Build Coastguard Worker {
845*053f45beSAndroid Build Coastguard Worker 	int full_scans;
846*053f45beSAndroid Build Coastguard Worker 	int timeout = 6; /* 3 seconds */
847*053f45beSAndroid Build Coastguard Worker 
848*053f45beSAndroid Build Coastguard Worker 	/* Sanity check */
849*053f45beSAndroid Build Coastguard Worker 	if (!ops->check_huge(p, 0)) {
850*053f45beSAndroid Build Coastguard Worker 		printf("Unexpected huge page\n");
851*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
852*053f45beSAndroid Build Coastguard Worker 	}
853*053f45beSAndroid Build Coastguard Worker 
854*053f45beSAndroid Build Coastguard Worker 	madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE);
855*053f45beSAndroid Build Coastguard Worker 
856*053f45beSAndroid Build Coastguard Worker 	/* Wait until the second full_scan completed */
857*053f45beSAndroid Build Coastguard Worker 	full_scans = read_num("khugepaged/full_scans") + 2;
858*053f45beSAndroid Build Coastguard Worker 
859*053f45beSAndroid Build Coastguard Worker 	printf("%s...", msg);
860*053f45beSAndroid Build Coastguard Worker 	while (timeout--) {
861*053f45beSAndroid Build Coastguard Worker 		if (ops->check_huge(p, nr_hpages))
862*053f45beSAndroid Build Coastguard Worker 			break;
863*053f45beSAndroid Build Coastguard Worker 		if (read_num("khugepaged/full_scans") >= full_scans)
864*053f45beSAndroid Build Coastguard Worker 			break;
865*053f45beSAndroid Build Coastguard Worker 		printf(".");
866*053f45beSAndroid Build Coastguard Worker 		usleep(TICK);
867*053f45beSAndroid Build Coastguard Worker 	}
868*053f45beSAndroid Build Coastguard Worker 
869*053f45beSAndroid Build Coastguard Worker 	madvise(p, nr_hpages * hpage_pmd_size, MADV_NOHUGEPAGE);
870*053f45beSAndroid Build Coastguard Worker 
871*053f45beSAndroid Build Coastguard Worker 	return timeout == -1;
872*053f45beSAndroid Build Coastguard Worker }
873*053f45beSAndroid Build Coastguard Worker 
khugepaged_collapse(const char * msg,char * p,int nr_hpages,struct mem_ops * ops,bool expect)874*053f45beSAndroid Build Coastguard Worker static void khugepaged_collapse(const char *msg, char *p, int nr_hpages,
875*053f45beSAndroid Build Coastguard Worker 				struct mem_ops *ops, bool expect)
876*053f45beSAndroid Build Coastguard Worker {
877*053f45beSAndroid Build Coastguard Worker 	if (wait_for_scan(msg, p, nr_hpages, ops)) {
878*053f45beSAndroid Build Coastguard Worker 		if (expect)
879*053f45beSAndroid Build Coastguard Worker 			fail("Timeout");
880*053f45beSAndroid Build Coastguard Worker 		else
881*053f45beSAndroid Build Coastguard Worker 			success("OK");
882*053f45beSAndroid Build Coastguard Worker 		return;
883*053f45beSAndroid Build Coastguard Worker 	}
884*053f45beSAndroid Build Coastguard Worker 
885*053f45beSAndroid Build Coastguard Worker 	/*
886*053f45beSAndroid Build Coastguard Worker 	 * For file and shmem memory, khugepaged only retracts pte entries after
887*053f45beSAndroid Build Coastguard Worker 	 * putting the new hugepage in the page cache. The hugepage must be
888*053f45beSAndroid Build Coastguard Worker 	 * subsequently refaulted to install the pmd mapping for the mm.
889*053f45beSAndroid Build Coastguard Worker 	 */
890*053f45beSAndroid Build Coastguard Worker 	if (ops != &__anon_ops)
891*053f45beSAndroid Build Coastguard Worker 		ops->fault(p, 0, nr_hpages * hpage_pmd_size);
892*053f45beSAndroid Build Coastguard Worker 
893*053f45beSAndroid Build Coastguard Worker 	if (ops->check_huge(p, expect ? nr_hpages : 0))
894*053f45beSAndroid Build Coastguard Worker 		success("OK");
895*053f45beSAndroid Build Coastguard Worker 	else
896*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
897*053f45beSAndroid Build Coastguard Worker }
898*053f45beSAndroid Build Coastguard Worker 
899*053f45beSAndroid Build Coastguard Worker static struct collapse_context __khugepaged_context = {
900*053f45beSAndroid Build Coastguard Worker 	.collapse = &khugepaged_collapse,
901*053f45beSAndroid Build Coastguard Worker 	.enforce_pte_scan_limits = true,
902*053f45beSAndroid Build Coastguard Worker 	.name = "khugepaged",
903*053f45beSAndroid Build Coastguard Worker };
904*053f45beSAndroid Build Coastguard Worker 
905*053f45beSAndroid Build Coastguard Worker static struct collapse_context __madvise_context = {
906*053f45beSAndroid Build Coastguard Worker 	.collapse = &madvise_collapse,
907*053f45beSAndroid Build Coastguard Worker 	.enforce_pte_scan_limits = false,
908*053f45beSAndroid Build Coastguard Worker 	.name = "madvise",
909*053f45beSAndroid Build Coastguard Worker };
910*053f45beSAndroid Build Coastguard Worker 
is_tmpfs(struct mem_ops * ops)911*053f45beSAndroid Build Coastguard Worker static bool is_tmpfs(struct mem_ops *ops)
912*053f45beSAndroid Build Coastguard Worker {
913*053f45beSAndroid Build Coastguard Worker 	return ops == &__file_ops && finfo.type == VMA_SHMEM;
914*053f45beSAndroid Build Coastguard Worker }
915*053f45beSAndroid Build Coastguard Worker 
alloc_at_fault(void)916*053f45beSAndroid Build Coastguard Worker static void alloc_at_fault(void)
917*053f45beSAndroid Build Coastguard Worker {
918*053f45beSAndroid Build Coastguard Worker 	struct settings settings = *current_settings();
919*053f45beSAndroid Build Coastguard Worker 	char *p;
920*053f45beSAndroid Build Coastguard Worker 
921*053f45beSAndroid Build Coastguard Worker 	settings.thp_enabled = THP_ALWAYS;
922*053f45beSAndroid Build Coastguard Worker 	push_settings(&settings);
923*053f45beSAndroid Build Coastguard Worker 
924*053f45beSAndroid Build Coastguard Worker 	p = alloc_mapping(1);
925*053f45beSAndroid Build Coastguard Worker 	*p = 1;
926*053f45beSAndroid Build Coastguard Worker 	printf("Allocate huge page on fault...");
927*053f45beSAndroid Build Coastguard Worker 	if (check_huge_anon(p, 1, hpage_pmd_size))
928*053f45beSAndroid Build Coastguard Worker 		success("OK");
929*053f45beSAndroid Build Coastguard Worker 	else
930*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
931*053f45beSAndroid Build Coastguard Worker 
932*053f45beSAndroid Build Coastguard Worker 	pop_settings();
933*053f45beSAndroid Build Coastguard Worker 
934*053f45beSAndroid Build Coastguard Worker 	madvise(p, page_size, MADV_DONTNEED);
935*053f45beSAndroid Build Coastguard Worker 	printf("Split huge PMD on MADV_DONTNEED...");
936*053f45beSAndroid Build Coastguard Worker 	if (check_huge_anon(p, 0, hpage_pmd_size))
937*053f45beSAndroid Build Coastguard Worker 		success("OK");
938*053f45beSAndroid Build Coastguard Worker 	else
939*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
940*053f45beSAndroid Build Coastguard Worker 	munmap(p, hpage_pmd_size);
941*053f45beSAndroid Build Coastguard Worker }
942*053f45beSAndroid Build Coastguard Worker 
collapse_full(struct collapse_context * c,struct mem_ops * ops)943*053f45beSAndroid Build Coastguard Worker static void collapse_full(struct collapse_context *c, struct mem_ops *ops)
944*053f45beSAndroid Build Coastguard Worker {
945*053f45beSAndroid Build Coastguard Worker 	void *p;
946*053f45beSAndroid Build Coastguard Worker 	int nr_hpages = 4;
947*053f45beSAndroid Build Coastguard Worker 	unsigned long size = nr_hpages * hpage_pmd_size;
948*053f45beSAndroid Build Coastguard Worker 
949*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(nr_hpages);
950*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, size);
951*053f45beSAndroid Build Coastguard Worker 	c->collapse("Collapse multiple fully populated PTE table", p, nr_hpages,
952*053f45beSAndroid Build Coastguard Worker 		    ops, true);
953*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, size);
954*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, size);
955*053f45beSAndroid Build Coastguard Worker }
956*053f45beSAndroid Build Coastguard Worker 
collapse_empty(struct collapse_context * c,struct mem_ops * ops)957*053f45beSAndroid Build Coastguard Worker static void collapse_empty(struct collapse_context *c, struct mem_ops *ops)
958*053f45beSAndroid Build Coastguard Worker {
959*053f45beSAndroid Build Coastguard Worker 	void *p;
960*053f45beSAndroid Build Coastguard Worker 
961*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
962*053f45beSAndroid Build Coastguard Worker 	c->collapse("Do not collapse empty PTE table", p, 1, ops, false);
963*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
964*053f45beSAndroid Build Coastguard Worker }
965*053f45beSAndroid Build Coastguard Worker 
collapse_single_pte_entry(struct collapse_context * c,struct mem_ops * ops)966*053f45beSAndroid Build Coastguard Worker static void collapse_single_pte_entry(struct collapse_context *c, struct mem_ops *ops)
967*053f45beSAndroid Build Coastguard Worker {
968*053f45beSAndroid Build Coastguard Worker 	void *p;
969*053f45beSAndroid Build Coastguard Worker 
970*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
971*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, page_size);
972*053f45beSAndroid Build Coastguard Worker 	c->collapse("Collapse PTE table with single PTE entry present", p,
973*053f45beSAndroid Build Coastguard Worker 		    1, ops, true);
974*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
975*053f45beSAndroid Build Coastguard Worker }
976*053f45beSAndroid Build Coastguard Worker 
collapse_max_ptes_none(struct collapse_context * c,struct mem_ops * ops)977*053f45beSAndroid Build Coastguard Worker static void collapse_max_ptes_none(struct collapse_context *c, struct mem_ops *ops)
978*053f45beSAndroid Build Coastguard Worker {
979*053f45beSAndroid Build Coastguard Worker 	int max_ptes_none = hpage_pmd_nr / 2;
980*053f45beSAndroid Build Coastguard Worker 	struct settings settings = *current_settings();
981*053f45beSAndroid Build Coastguard Worker 	void *p;
982*053f45beSAndroid Build Coastguard Worker 
983*053f45beSAndroid Build Coastguard Worker 	settings.khugepaged.max_ptes_none = max_ptes_none;
984*053f45beSAndroid Build Coastguard Worker 	push_settings(&settings);
985*053f45beSAndroid Build Coastguard Worker 
986*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
987*053f45beSAndroid Build Coastguard Worker 
988*053f45beSAndroid Build Coastguard Worker 	if (is_tmpfs(ops)) {
989*053f45beSAndroid Build Coastguard Worker 		/* shmem pages always in the page cache */
990*053f45beSAndroid Build Coastguard Worker 		printf("tmpfs...");
991*053f45beSAndroid Build Coastguard Worker 		skip("Skip");
992*053f45beSAndroid Build Coastguard Worker 		goto skip;
993*053f45beSAndroid Build Coastguard Worker 	}
994*053f45beSAndroid Build Coastguard Worker 
995*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, (hpage_pmd_nr - max_ptes_none - 1) * page_size);
996*053f45beSAndroid Build Coastguard Worker 	c->collapse("Maybe collapse with max_ptes_none exceeded", p, 1,
997*053f45beSAndroid Build Coastguard Worker 		    ops, !c->enforce_pte_scan_limits);
998*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, (hpage_pmd_nr - max_ptes_none - 1) * page_size);
999*053f45beSAndroid Build Coastguard Worker 
1000*053f45beSAndroid Build Coastguard Worker 	if (c->enforce_pte_scan_limits) {
1001*053f45beSAndroid Build Coastguard Worker 		ops->fault(p, 0, (hpage_pmd_nr - max_ptes_none) * page_size);
1002*053f45beSAndroid Build Coastguard Worker 		c->collapse("Collapse with max_ptes_none PTEs empty", p, 1, ops,
1003*053f45beSAndroid Build Coastguard Worker 			    true);
1004*053f45beSAndroid Build Coastguard Worker 		validate_memory(p, 0,
1005*053f45beSAndroid Build Coastguard Worker 				(hpage_pmd_nr - max_ptes_none) * page_size);
1006*053f45beSAndroid Build Coastguard Worker 	}
1007*053f45beSAndroid Build Coastguard Worker skip:
1008*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1009*053f45beSAndroid Build Coastguard Worker 	pop_settings();
1010*053f45beSAndroid Build Coastguard Worker }
1011*053f45beSAndroid Build Coastguard Worker 
collapse_swapin_single_pte(struct collapse_context * c,struct mem_ops * ops)1012*053f45beSAndroid Build Coastguard Worker static void collapse_swapin_single_pte(struct collapse_context *c, struct mem_ops *ops)
1013*053f45beSAndroid Build Coastguard Worker {
1014*053f45beSAndroid Build Coastguard Worker 	void *p;
1015*053f45beSAndroid Build Coastguard Worker 
1016*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
1017*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, hpage_pmd_size);
1018*053f45beSAndroid Build Coastguard Worker 
1019*053f45beSAndroid Build Coastguard Worker 	printf("Swapout one page...");
1020*053f45beSAndroid Build Coastguard Worker 	if (madvise(p, page_size, MADV_PAGEOUT)) {
1021*053f45beSAndroid Build Coastguard Worker 		perror("madvise(MADV_PAGEOUT)");
1022*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
1023*053f45beSAndroid Build Coastguard Worker 	}
1024*053f45beSAndroid Build Coastguard Worker 	if (check_swap(p, page_size)) {
1025*053f45beSAndroid Build Coastguard Worker 		success("OK");
1026*053f45beSAndroid Build Coastguard Worker 	} else {
1027*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1028*053f45beSAndroid Build Coastguard Worker 		goto out;
1029*053f45beSAndroid Build Coastguard Worker 	}
1030*053f45beSAndroid Build Coastguard Worker 
1031*053f45beSAndroid Build Coastguard Worker 	c->collapse("Collapse with swapping in single PTE entry", p, 1, ops,
1032*053f45beSAndroid Build Coastguard Worker 		    true);
1033*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1034*053f45beSAndroid Build Coastguard Worker out:
1035*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1036*053f45beSAndroid Build Coastguard Worker }
1037*053f45beSAndroid Build Coastguard Worker 
collapse_max_ptes_swap(struct collapse_context * c,struct mem_ops * ops)1038*053f45beSAndroid Build Coastguard Worker static void collapse_max_ptes_swap(struct collapse_context *c, struct mem_ops *ops)
1039*053f45beSAndroid Build Coastguard Worker {
1040*053f45beSAndroid Build Coastguard Worker 	int max_ptes_swap = read_num("khugepaged/max_ptes_swap");
1041*053f45beSAndroid Build Coastguard Worker 	void *p;
1042*053f45beSAndroid Build Coastguard Worker 
1043*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
1044*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, hpage_pmd_size);
1045*053f45beSAndroid Build Coastguard Worker 
1046*053f45beSAndroid Build Coastguard Worker 	printf("Swapout %d of %d pages...", max_ptes_swap + 1, hpage_pmd_nr);
1047*053f45beSAndroid Build Coastguard Worker 	if (madvise(p, (max_ptes_swap + 1) * page_size, MADV_PAGEOUT)) {
1048*053f45beSAndroid Build Coastguard Worker 		perror("madvise(MADV_PAGEOUT)");
1049*053f45beSAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
1050*053f45beSAndroid Build Coastguard Worker 	}
1051*053f45beSAndroid Build Coastguard Worker 	if (check_swap(p, (max_ptes_swap + 1) * page_size)) {
1052*053f45beSAndroid Build Coastguard Worker 		success("OK");
1053*053f45beSAndroid Build Coastguard Worker 	} else {
1054*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1055*053f45beSAndroid Build Coastguard Worker 		goto out;
1056*053f45beSAndroid Build Coastguard Worker 	}
1057*053f45beSAndroid Build Coastguard Worker 
1058*053f45beSAndroid Build Coastguard Worker 	c->collapse("Maybe collapse with max_ptes_swap exceeded", p, 1, ops,
1059*053f45beSAndroid Build Coastguard Worker 		    !c->enforce_pte_scan_limits);
1060*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1061*053f45beSAndroid Build Coastguard Worker 
1062*053f45beSAndroid Build Coastguard Worker 	if (c->enforce_pte_scan_limits) {
1063*053f45beSAndroid Build Coastguard Worker 		ops->fault(p, 0, hpage_pmd_size);
1064*053f45beSAndroid Build Coastguard Worker 		printf("Swapout %d of %d pages...", max_ptes_swap,
1065*053f45beSAndroid Build Coastguard Worker 		       hpage_pmd_nr);
1066*053f45beSAndroid Build Coastguard Worker 		if (madvise(p, max_ptes_swap * page_size, MADV_PAGEOUT)) {
1067*053f45beSAndroid Build Coastguard Worker 			perror("madvise(MADV_PAGEOUT)");
1068*053f45beSAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1069*053f45beSAndroid Build Coastguard Worker 		}
1070*053f45beSAndroid Build Coastguard Worker 		if (check_swap(p, max_ptes_swap * page_size)) {
1071*053f45beSAndroid Build Coastguard Worker 			success("OK");
1072*053f45beSAndroid Build Coastguard Worker 		} else {
1073*053f45beSAndroid Build Coastguard Worker 			fail("Fail");
1074*053f45beSAndroid Build Coastguard Worker 			goto out;
1075*053f45beSAndroid Build Coastguard Worker 		}
1076*053f45beSAndroid Build Coastguard Worker 
1077*053f45beSAndroid Build Coastguard Worker 		c->collapse("Collapse with max_ptes_swap pages swapped out", p,
1078*053f45beSAndroid Build Coastguard Worker 			    1, ops, true);
1079*053f45beSAndroid Build Coastguard Worker 		validate_memory(p, 0, hpage_pmd_size);
1080*053f45beSAndroid Build Coastguard Worker 	}
1081*053f45beSAndroid Build Coastguard Worker out:
1082*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1083*053f45beSAndroid Build Coastguard Worker }
1084*053f45beSAndroid Build Coastguard Worker 
collapse_single_pte_entry_compound(struct collapse_context * c,struct mem_ops * ops)1085*053f45beSAndroid Build Coastguard Worker static void collapse_single_pte_entry_compound(struct collapse_context *c, struct mem_ops *ops)
1086*053f45beSAndroid Build Coastguard Worker {
1087*053f45beSAndroid Build Coastguard Worker 	void *p;
1088*053f45beSAndroid Build Coastguard Worker 
1089*053f45beSAndroid Build Coastguard Worker 	p = alloc_hpage(ops);
1090*053f45beSAndroid Build Coastguard Worker 
1091*053f45beSAndroid Build Coastguard Worker 	if (is_tmpfs(ops)) {
1092*053f45beSAndroid Build Coastguard Worker 		/* MADV_DONTNEED won't evict tmpfs pages */
1093*053f45beSAndroid Build Coastguard Worker 		printf("tmpfs...");
1094*053f45beSAndroid Build Coastguard Worker 		skip("Skip");
1095*053f45beSAndroid Build Coastguard Worker 		goto skip;
1096*053f45beSAndroid Build Coastguard Worker 	}
1097*053f45beSAndroid Build Coastguard Worker 
1098*053f45beSAndroid Build Coastguard Worker 	madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE);
1099*053f45beSAndroid Build Coastguard Worker 	printf("Split huge page leaving single PTE mapping compound page...");
1100*053f45beSAndroid Build Coastguard Worker 	madvise(p + page_size, hpage_pmd_size - page_size, MADV_DONTNEED);
1101*053f45beSAndroid Build Coastguard Worker 	if (ops->check_huge(p, 0))
1102*053f45beSAndroid Build Coastguard Worker 		success("OK");
1103*053f45beSAndroid Build Coastguard Worker 	else
1104*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1105*053f45beSAndroid Build Coastguard Worker 
1106*053f45beSAndroid Build Coastguard Worker 	c->collapse("Collapse PTE table with single PTE mapping compound page",
1107*053f45beSAndroid Build Coastguard Worker 		    p, 1, ops, true);
1108*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, page_size);
1109*053f45beSAndroid Build Coastguard Worker skip:
1110*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1111*053f45beSAndroid Build Coastguard Worker }
1112*053f45beSAndroid Build Coastguard Worker 
collapse_full_of_compound(struct collapse_context * c,struct mem_ops * ops)1113*053f45beSAndroid Build Coastguard Worker static void collapse_full_of_compound(struct collapse_context *c, struct mem_ops *ops)
1114*053f45beSAndroid Build Coastguard Worker {
1115*053f45beSAndroid Build Coastguard Worker 	void *p;
1116*053f45beSAndroid Build Coastguard Worker 
1117*053f45beSAndroid Build Coastguard Worker 	p = alloc_hpage(ops);
1118*053f45beSAndroid Build Coastguard Worker 	printf("Split huge page leaving single PTE page table full of compound pages...");
1119*053f45beSAndroid Build Coastguard Worker 	madvise(p, page_size, MADV_NOHUGEPAGE);
1120*053f45beSAndroid Build Coastguard Worker 	madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE);
1121*053f45beSAndroid Build Coastguard Worker 	if (ops->check_huge(p, 0))
1122*053f45beSAndroid Build Coastguard Worker 		success("OK");
1123*053f45beSAndroid Build Coastguard Worker 	else
1124*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1125*053f45beSAndroid Build Coastguard Worker 
1126*053f45beSAndroid Build Coastguard Worker 	c->collapse("Collapse PTE table full of compound pages", p, 1, ops,
1127*053f45beSAndroid Build Coastguard Worker 		    true);
1128*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1129*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1130*053f45beSAndroid Build Coastguard Worker }
1131*053f45beSAndroid Build Coastguard Worker 
collapse_compound_extreme(struct collapse_context * c,struct mem_ops * ops)1132*053f45beSAndroid Build Coastguard Worker static void collapse_compound_extreme(struct collapse_context *c, struct mem_ops *ops)
1133*053f45beSAndroid Build Coastguard Worker {
1134*053f45beSAndroid Build Coastguard Worker 	void *p;
1135*053f45beSAndroid Build Coastguard Worker 	int i;
1136*053f45beSAndroid Build Coastguard Worker 
1137*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
1138*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < hpage_pmd_nr; i++) {
1139*053f45beSAndroid Build Coastguard Worker 		printf("\rConstruct PTE page table full of different PTE-mapped compound pages %3d/%d...",
1140*053f45beSAndroid Build Coastguard Worker 				i + 1, hpage_pmd_nr);
1141*053f45beSAndroid Build Coastguard Worker 
1142*053f45beSAndroid Build Coastguard Worker 		madvise(BASE_ADDR, hpage_pmd_size, MADV_HUGEPAGE);
1143*053f45beSAndroid Build Coastguard Worker 		ops->fault(BASE_ADDR, 0, hpage_pmd_size);
1144*053f45beSAndroid Build Coastguard Worker 		if (!ops->check_huge(BASE_ADDR, 1)) {
1145*053f45beSAndroid Build Coastguard Worker 			printf("Failed to allocate huge page\n");
1146*053f45beSAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1147*053f45beSAndroid Build Coastguard Worker 		}
1148*053f45beSAndroid Build Coastguard Worker 		madvise(BASE_ADDR, hpage_pmd_size, MADV_NOHUGEPAGE);
1149*053f45beSAndroid Build Coastguard Worker 
1150*053f45beSAndroid Build Coastguard Worker 		p = mremap(BASE_ADDR - i * page_size,
1151*053f45beSAndroid Build Coastguard Worker 				i * page_size + hpage_pmd_size,
1152*053f45beSAndroid Build Coastguard Worker 				(i + 1) * page_size,
1153*053f45beSAndroid Build Coastguard Worker 				MREMAP_MAYMOVE | MREMAP_FIXED,
1154*053f45beSAndroid Build Coastguard Worker 				BASE_ADDR + 2 * hpage_pmd_size);
1155*053f45beSAndroid Build Coastguard Worker 		if (p == MAP_FAILED) {
1156*053f45beSAndroid Build Coastguard Worker 			perror("mremap+unmap");
1157*053f45beSAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1158*053f45beSAndroid Build Coastguard Worker 		}
1159*053f45beSAndroid Build Coastguard Worker 
1160*053f45beSAndroid Build Coastguard Worker 		p = mremap(BASE_ADDR + 2 * hpage_pmd_size,
1161*053f45beSAndroid Build Coastguard Worker 				(i + 1) * page_size,
1162*053f45beSAndroid Build Coastguard Worker 				(i + 1) * page_size + hpage_pmd_size,
1163*053f45beSAndroid Build Coastguard Worker 				MREMAP_MAYMOVE | MREMAP_FIXED,
1164*053f45beSAndroid Build Coastguard Worker 				BASE_ADDR - (i + 1) * page_size);
1165*053f45beSAndroid Build Coastguard Worker 		if (p == MAP_FAILED) {
1166*053f45beSAndroid Build Coastguard Worker 			perror("mremap+alloc");
1167*053f45beSAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1168*053f45beSAndroid Build Coastguard Worker 		}
1169*053f45beSAndroid Build Coastguard Worker 	}
1170*053f45beSAndroid Build Coastguard Worker 
1171*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(BASE_ADDR, hpage_pmd_size);
1172*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, hpage_pmd_size);
1173*053f45beSAndroid Build Coastguard Worker 	if (!ops->check_huge(p, 1))
1174*053f45beSAndroid Build Coastguard Worker 		success("OK");
1175*053f45beSAndroid Build Coastguard Worker 	else
1176*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1177*053f45beSAndroid Build Coastguard Worker 
1178*053f45beSAndroid Build Coastguard Worker 	c->collapse("Collapse PTE table full of different compound pages", p, 1,
1179*053f45beSAndroid Build Coastguard Worker 		    ops, true);
1180*053f45beSAndroid Build Coastguard Worker 
1181*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1182*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1183*053f45beSAndroid Build Coastguard Worker }
1184*053f45beSAndroid Build Coastguard Worker 
collapse_fork(struct collapse_context * c,struct mem_ops * ops)1185*053f45beSAndroid Build Coastguard Worker static void collapse_fork(struct collapse_context *c, struct mem_ops *ops)
1186*053f45beSAndroid Build Coastguard Worker {
1187*053f45beSAndroid Build Coastguard Worker 	int wstatus;
1188*053f45beSAndroid Build Coastguard Worker 	void *p;
1189*053f45beSAndroid Build Coastguard Worker 
1190*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
1191*053f45beSAndroid Build Coastguard Worker 
1192*053f45beSAndroid Build Coastguard Worker 	printf("Allocate small page...");
1193*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, page_size);
1194*053f45beSAndroid Build Coastguard Worker 	if (ops->check_huge(p, 0))
1195*053f45beSAndroid Build Coastguard Worker 		success("OK");
1196*053f45beSAndroid Build Coastguard Worker 	else
1197*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1198*053f45beSAndroid Build Coastguard Worker 
1199*053f45beSAndroid Build Coastguard Worker 	printf("Share small page over fork()...");
1200*053f45beSAndroid Build Coastguard Worker 	if (!fork()) {
1201*053f45beSAndroid Build Coastguard Worker 		/* Do not touch settings on child exit */
1202*053f45beSAndroid Build Coastguard Worker 		skip_settings_restore = true;
1203*053f45beSAndroid Build Coastguard Worker 		exit_status = 0;
1204*053f45beSAndroid Build Coastguard Worker 
1205*053f45beSAndroid Build Coastguard Worker 		if (ops->check_huge(p, 0))
1206*053f45beSAndroid Build Coastguard Worker 			success("OK");
1207*053f45beSAndroid Build Coastguard Worker 		else
1208*053f45beSAndroid Build Coastguard Worker 			fail("Fail");
1209*053f45beSAndroid Build Coastguard Worker 
1210*053f45beSAndroid Build Coastguard Worker 		ops->fault(p, page_size, 2 * page_size);
1211*053f45beSAndroid Build Coastguard Worker 		c->collapse("Collapse PTE table with single page shared with parent process",
1212*053f45beSAndroid Build Coastguard Worker 			    p, 1, ops, true);
1213*053f45beSAndroid Build Coastguard Worker 
1214*053f45beSAndroid Build Coastguard Worker 		validate_memory(p, 0, page_size);
1215*053f45beSAndroid Build Coastguard Worker 		ops->cleanup_area(p, hpage_pmd_size);
1216*053f45beSAndroid Build Coastguard Worker 		exit(exit_status);
1217*053f45beSAndroid Build Coastguard Worker 	}
1218*053f45beSAndroid Build Coastguard Worker 
1219*053f45beSAndroid Build Coastguard Worker 	wait(&wstatus);
1220*053f45beSAndroid Build Coastguard Worker 	exit_status += WEXITSTATUS(wstatus);
1221*053f45beSAndroid Build Coastguard Worker 
1222*053f45beSAndroid Build Coastguard Worker 	printf("Check if parent still has small page...");
1223*053f45beSAndroid Build Coastguard Worker 	if (ops->check_huge(p, 0))
1224*053f45beSAndroid Build Coastguard Worker 		success("OK");
1225*053f45beSAndroid Build Coastguard Worker 	else
1226*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1227*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, page_size);
1228*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1229*053f45beSAndroid Build Coastguard Worker }
1230*053f45beSAndroid Build Coastguard Worker 
collapse_fork_compound(struct collapse_context * c,struct mem_ops * ops)1231*053f45beSAndroid Build Coastguard Worker static void collapse_fork_compound(struct collapse_context *c, struct mem_ops *ops)
1232*053f45beSAndroid Build Coastguard Worker {
1233*053f45beSAndroid Build Coastguard Worker 	int wstatus;
1234*053f45beSAndroid Build Coastguard Worker 	void *p;
1235*053f45beSAndroid Build Coastguard Worker 
1236*053f45beSAndroid Build Coastguard Worker 	p = alloc_hpage(ops);
1237*053f45beSAndroid Build Coastguard Worker 	printf("Share huge page over fork()...");
1238*053f45beSAndroid Build Coastguard Worker 	if (!fork()) {
1239*053f45beSAndroid Build Coastguard Worker 		/* Do not touch settings on child exit */
1240*053f45beSAndroid Build Coastguard Worker 		skip_settings_restore = true;
1241*053f45beSAndroid Build Coastguard Worker 		exit_status = 0;
1242*053f45beSAndroid Build Coastguard Worker 
1243*053f45beSAndroid Build Coastguard Worker 		if (ops->check_huge(p, 1))
1244*053f45beSAndroid Build Coastguard Worker 			success("OK");
1245*053f45beSAndroid Build Coastguard Worker 		else
1246*053f45beSAndroid Build Coastguard Worker 			fail("Fail");
1247*053f45beSAndroid Build Coastguard Worker 
1248*053f45beSAndroid Build Coastguard Worker 		printf("Split huge page PMD in child process...");
1249*053f45beSAndroid Build Coastguard Worker 		madvise(p, page_size, MADV_NOHUGEPAGE);
1250*053f45beSAndroid Build Coastguard Worker 		madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE);
1251*053f45beSAndroid Build Coastguard Worker 		if (ops->check_huge(p, 0))
1252*053f45beSAndroid Build Coastguard Worker 			success("OK");
1253*053f45beSAndroid Build Coastguard Worker 		else
1254*053f45beSAndroid Build Coastguard Worker 			fail("Fail");
1255*053f45beSAndroid Build Coastguard Worker 		ops->fault(p, 0, page_size);
1256*053f45beSAndroid Build Coastguard Worker 
1257*053f45beSAndroid Build Coastguard Worker 		write_num("khugepaged/max_ptes_shared", hpage_pmd_nr - 1);
1258*053f45beSAndroid Build Coastguard Worker 		c->collapse("Collapse PTE table full of compound pages in child",
1259*053f45beSAndroid Build Coastguard Worker 			    p, 1, ops, true);
1260*053f45beSAndroid Build Coastguard Worker 		write_num("khugepaged/max_ptes_shared",
1261*053f45beSAndroid Build Coastguard Worker 			  current_settings()->khugepaged.max_ptes_shared);
1262*053f45beSAndroid Build Coastguard Worker 
1263*053f45beSAndroid Build Coastguard Worker 		validate_memory(p, 0, hpage_pmd_size);
1264*053f45beSAndroid Build Coastguard Worker 		ops->cleanup_area(p, hpage_pmd_size);
1265*053f45beSAndroid Build Coastguard Worker 		exit(exit_status);
1266*053f45beSAndroid Build Coastguard Worker 	}
1267*053f45beSAndroid Build Coastguard Worker 
1268*053f45beSAndroid Build Coastguard Worker 	wait(&wstatus);
1269*053f45beSAndroid Build Coastguard Worker 	exit_status += WEXITSTATUS(wstatus);
1270*053f45beSAndroid Build Coastguard Worker 
1271*053f45beSAndroid Build Coastguard Worker 	printf("Check if parent still has huge page...");
1272*053f45beSAndroid Build Coastguard Worker 	if (ops->check_huge(p, 1))
1273*053f45beSAndroid Build Coastguard Worker 		success("OK");
1274*053f45beSAndroid Build Coastguard Worker 	else
1275*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1276*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1277*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1278*053f45beSAndroid Build Coastguard Worker }
1279*053f45beSAndroid Build Coastguard Worker 
collapse_max_ptes_shared(struct collapse_context * c,struct mem_ops * ops)1280*053f45beSAndroid Build Coastguard Worker static void collapse_max_ptes_shared(struct collapse_context *c, struct mem_ops *ops)
1281*053f45beSAndroid Build Coastguard Worker {
1282*053f45beSAndroid Build Coastguard Worker 	int max_ptes_shared = read_num("khugepaged/max_ptes_shared");
1283*053f45beSAndroid Build Coastguard Worker 	int wstatus;
1284*053f45beSAndroid Build Coastguard Worker 	void *p;
1285*053f45beSAndroid Build Coastguard Worker 
1286*053f45beSAndroid Build Coastguard Worker 	p = alloc_hpage(ops);
1287*053f45beSAndroid Build Coastguard Worker 	printf("Share huge page over fork()...");
1288*053f45beSAndroid Build Coastguard Worker 	if (!fork()) {
1289*053f45beSAndroid Build Coastguard Worker 		/* Do not touch settings on child exit */
1290*053f45beSAndroid Build Coastguard Worker 		skip_settings_restore = true;
1291*053f45beSAndroid Build Coastguard Worker 		exit_status = 0;
1292*053f45beSAndroid Build Coastguard Worker 
1293*053f45beSAndroid Build Coastguard Worker 		if (ops->check_huge(p, 1))
1294*053f45beSAndroid Build Coastguard Worker 			success("OK");
1295*053f45beSAndroid Build Coastguard Worker 		else
1296*053f45beSAndroid Build Coastguard Worker 			fail("Fail");
1297*053f45beSAndroid Build Coastguard Worker 
1298*053f45beSAndroid Build Coastguard Worker 		printf("Trigger CoW on page %d of %d...",
1299*053f45beSAndroid Build Coastguard Worker 				hpage_pmd_nr - max_ptes_shared - 1, hpage_pmd_nr);
1300*053f45beSAndroid Build Coastguard Worker 		ops->fault(p, 0, (hpage_pmd_nr - max_ptes_shared - 1) * page_size);
1301*053f45beSAndroid Build Coastguard Worker 		if (ops->check_huge(p, 0))
1302*053f45beSAndroid Build Coastguard Worker 			success("OK");
1303*053f45beSAndroid Build Coastguard Worker 		else
1304*053f45beSAndroid Build Coastguard Worker 			fail("Fail");
1305*053f45beSAndroid Build Coastguard Worker 
1306*053f45beSAndroid Build Coastguard Worker 		c->collapse("Maybe collapse with max_ptes_shared exceeded", p,
1307*053f45beSAndroid Build Coastguard Worker 			    1, ops, !c->enforce_pte_scan_limits);
1308*053f45beSAndroid Build Coastguard Worker 
1309*053f45beSAndroid Build Coastguard Worker 		if (c->enforce_pte_scan_limits) {
1310*053f45beSAndroid Build Coastguard Worker 			printf("Trigger CoW on page %d of %d...",
1311*053f45beSAndroid Build Coastguard Worker 			       hpage_pmd_nr - max_ptes_shared, hpage_pmd_nr);
1312*053f45beSAndroid Build Coastguard Worker 			ops->fault(p, 0, (hpage_pmd_nr - max_ptes_shared) *
1313*053f45beSAndroid Build Coastguard Worker 				    page_size);
1314*053f45beSAndroid Build Coastguard Worker 			if (ops->check_huge(p, 0))
1315*053f45beSAndroid Build Coastguard Worker 				success("OK");
1316*053f45beSAndroid Build Coastguard Worker 			else
1317*053f45beSAndroid Build Coastguard Worker 				fail("Fail");
1318*053f45beSAndroid Build Coastguard Worker 
1319*053f45beSAndroid Build Coastguard Worker 			c->collapse("Collapse with max_ptes_shared PTEs shared",
1320*053f45beSAndroid Build Coastguard Worker 				    p, 1, ops, true);
1321*053f45beSAndroid Build Coastguard Worker 		}
1322*053f45beSAndroid Build Coastguard Worker 
1323*053f45beSAndroid Build Coastguard Worker 		validate_memory(p, 0, hpage_pmd_size);
1324*053f45beSAndroid Build Coastguard Worker 		ops->cleanup_area(p, hpage_pmd_size);
1325*053f45beSAndroid Build Coastguard Worker 		exit(exit_status);
1326*053f45beSAndroid Build Coastguard Worker 	}
1327*053f45beSAndroid Build Coastguard Worker 
1328*053f45beSAndroid Build Coastguard Worker 	wait(&wstatus);
1329*053f45beSAndroid Build Coastguard Worker 	exit_status += WEXITSTATUS(wstatus);
1330*053f45beSAndroid Build Coastguard Worker 
1331*053f45beSAndroid Build Coastguard Worker 	printf("Check if parent still has huge page...");
1332*053f45beSAndroid Build Coastguard Worker 	if (ops->check_huge(p, 1))
1333*053f45beSAndroid Build Coastguard Worker 		success("OK");
1334*053f45beSAndroid Build Coastguard Worker 	else
1335*053f45beSAndroid Build Coastguard Worker 		fail("Fail");
1336*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1337*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1338*053f45beSAndroid Build Coastguard Worker }
1339*053f45beSAndroid Build Coastguard Worker 
madvise_collapse_existing_thps(struct collapse_context * c,struct mem_ops * ops)1340*053f45beSAndroid Build Coastguard Worker static void madvise_collapse_existing_thps(struct collapse_context *c,
1341*053f45beSAndroid Build Coastguard Worker 					   struct mem_ops *ops)
1342*053f45beSAndroid Build Coastguard Worker {
1343*053f45beSAndroid Build Coastguard Worker 	void *p;
1344*053f45beSAndroid Build Coastguard Worker 
1345*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(1);
1346*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, hpage_pmd_size);
1347*053f45beSAndroid Build Coastguard Worker 	c->collapse("Collapse fully populated PTE table...", p, 1, ops, true);
1348*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1349*053f45beSAndroid Build Coastguard Worker 
1350*053f45beSAndroid Build Coastguard Worker 	/* c->collapse() will find a hugepage and complain - call directly. */
1351*053f45beSAndroid Build Coastguard Worker 	__madvise_collapse("Re-collapse PMD-mapped hugepage", p, 1, ops, true);
1352*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, hpage_pmd_size);
1353*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, hpage_pmd_size);
1354*053f45beSAndroid Build Coastguard Worker }
1355*053f45beSAndroid Build Coastguard Worker 
1356*053f45beSAndroid Build Coastguard Worker /*
1357*053f45beSAndroid Build Coastguard Worker  * Test race with khugepaged where page tables have been retracted and
1358*053f45beSAndroid Build Coastguard Worker  * pmd cleared.
1359*053f45beSAndroid Build Coastguard Worker  */
madvise_retracted_page_tables(struct collapse_context * c,struct mem_ops * ops)1360*053f45beSAndroid Build Coastguard Worker static void madvise_retracted_page_tables(struct collapse_context *c,
1361*053f45beSAndroid Build Coastguard Worker 					  struct mem_ops *ops)
1362*053f45beSAndroid Build Coastguard Worker {
1363*053f45beSAndroid Build Coastguard Worker 	void *p;
1364*053f45beSAndroid Build Coastguard Worker 	int nr_hpages = 1;
1365*053f45beSAndroid Build Coastguard Worker 	unsigned long size = nr_hpages * hpage_pmd_size;
1366*053f45beSAndroid Build Coastguard Worker 
1367*053f45beSAndroid Build Coastguard Worker 	p = ops->setup_area(nr_hpages);
1368*053f45beSAndroid Build Coastguard Worker 	ops->fault(p, 0, size);
1369*053f45beSAndroid Build Coastguard Worker 
1370*053f45beSAndroid Build Coastguard Worker 	/* Let khugepaged collapse and leave pmd cleared */
1371*053f45beSAndroid Build Coastguard Worker 	if (wait_for_scan("Collapse and leave PMD cleared", p, nr_hpages,
1372*053f45beSAndroid Build Coastguard Worker 			  ops)) {
1373*053f45beSAndroid Build Coastguard Worker 		fail("Timeout");
1374*053f45beSAndroid Build Coastguard Worker 		return;
1375*053f45beSAndroid Build Coastguard Worker 	}
1376*053f45beSAndroid Build Coastguard Worker 	success("OK");
1377*053f45beSAndroid Build Coastguard Worker 	c->collapse("Install huge PMD from page cache", p, nr_hpages, ops,
1378*053f45beSAndroid Build Coastguard Worker 		    true);
1379*053f45beSAndroid Build Coastguard Worker 	validate_memory(p, 0, size);
1380*053f45beSAndroid Build Coastguard Worker 	ops->cleanup_area(p, size);
1381*053f45beSAndroid Build Coastguard Worker }
1382*053f45beSAndroid Build Coastguard Worker 
usage(void)1383*053f45beSAndroid Build Coastguard Worker static void usage(void)
1384*053f45beSAndroid Build Coastguard Worker {
1385*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr, "\nUsage: ./khugepaged <test type> [dir]\n\n");
1386*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr, "\t<test type>\t: <context>:<mem_type>\n");
1387*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr, "\t<context>\t: [all|khugepaged|madvise]\n");
1388*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr, "\t<mem_type>\t: [all|anon|file|shmem]\n");
1389*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr, "\n\t\"file,all\" mem_type requires [dir] argument\n");
1390*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr, "\n\t\"file,all\" mem_type requires kernel built with\n");
1391*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr,	"\tCONFIG_READ_ONLY_THP_FOR_FS=y\n");
1392*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr, "\n\tif [dir] is a (sub)directory of a tmpfs mount, tmpfs must be\n");
1393*053f45beSAndroid Build Coastguard Worker 	fprintf(stderr,	"\tmounted with huge=madvise option for khugepaged tests to work\n");
1394*053f45beSAndroid Build Coastguard Worker 	exit(1);
1395*053f45beSAndroid Build Coastguard Worker }
1396*053f45beSAndroid Build Coastguard Worker 
parse_test_type(int argc,const char ** argv)1397*053f45beSAndroid Build Coastguard Worker static void parse_test_type(int argc, const char **argv)
1398*053f45beSAndroid Build Coastguard Worker {
1399*053f45beSAndroid Build Coastguard Worker 	char *buf;
1400*053f45beSAndroid Build Coastguard Worker 	const char *token;
1401*053f45beSAndroid Build Coastguard Worker 
1402*053f45beSAndroid Build Coastguard Worker 	if (argc == 1) {
1403*053f45beSAndroid Build Coastguard Worker 		/* Backwards compatibility */
1404*053f45beSAndroid Build Coastguard Worker 		khugepaged_context =  &__khugepaged_context;
1405*053f45beSAndroid Build Coastguard Worker 		madvise_context =  &__madvise_context;
1406*053f45beSAndroid Build Coastguard Worker 		anon_ops = &__anon_ops;
1407*053f45beSAndroid Build Coastguard Worker 		return;
1408*053f45beSAndroid Build Coastguard Worker 	}
1409*053f45beSAndroid Build Coastguard Worker 
1410*053f45beSAndroid Build Coastguard Worker 	buf = strdup(argv[1]);
1411*053f45beSAndroid Build Coastguard Worker 	token = strsep(&buf, ":");
1412*053f45beSAndroid Build Coastguard Worker 
1413*053f45beSAndroid Build Coastguard Worker 	if (!strcmp(token, "all")) {
1414*053f45beSAndroid Build Coastguard Worker 		khugepaged_context =  &__khugepaged_context;
1415*053f45beSAndroid Build Coastguard Worker 		madvise_context =  &__madvise_context;
1416*053f45beSAndroid Build Coastguard Worker 	} else if (!strcmp(token, "khugepaged")) {
1417*053f45beSAndroid Build Coastguard Worker 		khugepaged_context =  &__khugepaged_context;
1418*053f45beSAndroid Build Coastguard Worker 	} else if (!strcmp(token, "madvise")) {
1419*053f45beSAndroid Build Coastguard Worker 		madvise_context =  &__madvise_context;
1420*053f45beSAndroid Build Coastguard Worker 	} else {
1421*053f45beSAndroid Build Coastguard Worker 		usage();
1422*053f45beSAndroid Build Coastguard Worker 	}
1423*053f45beSAndroid Build Coastguard Worker 
1424*053f45beSAndroid Build Coastguard Worker 	if (!buf)
1425*053f45beSAndroid Build Coastguard Worker 		usage();
1426*053f45beSAndroid Build Coastguard Worker 
1427*053f45beSAndroid Build Coastguard Worker 	if (!strcmp(buf, "all")) {
1428*053f45beSAndroid Build Coastguard Worker 		file_ops =  &__file_ops;
1429*053f45beSAndroid Build Coastguard Worker 		anon_ops = &__anon_ops;
1430*053f45beSAndroid Build Coastguard Worker 		shmem_ops = &__shmem_ops;
1431*053f45beSAndroid Build Coastguard Worker 	} else if (!strcmp(buf, "anon")) {
1432*053f45beSAndroid Build Coastguard Worker 		anon_ops = &__anon_ops;
1433*053f45beSAndroid Build Coastguard Worker 	} else if (!strcmp(buf, "file")) {
1434*053f45beSAndroid Build Coastguard Worker 		file_ops =  &__file_ops;
1435*053f45beSAndroid Build Coastguard Worker 	} else if (!strcmp(buf, "shmem")) {
1436*053f45beSAndroid Build Coastguard Worker 		shmem_ops = &__shmem_ops;
1437*053f45beSAndroid Build Coastguard Worker 	} else {
1438*053f45beSAndroid Build Coastguard Worker 		usage();
1439*053f45beSAndroid Build Coastguard Worker 	}
1440*053f45beSAndroid Build Coastguard Worker 
1441*053f45beSAndroid Build Coastguard Worker 	if (!file_ops)
1442*053f45beSAndroid Build Coastguard Worker 		return;
1443*053f45beSAndroid Build Coastguard Worker 
1444*053f45beSAndroid Build Coastguard Worker 	if (argc != 3)
1445*053f45beSAndroid Build Coastguard Worker 		usage();
1446*053f45beSAndroid Build Coastguard Worker }
1447*053f45beSAndroid Build Coastguard Worker 
main(int argc,const char ** argv)1448*053f45beSAndroid Build Coastguard Worker int main(int argc, const char **argv)
1449*053f45beSAndroid Build Coastguard Worker {
1450*053f45beSAndroid Build Coastguard Worker 	struct settings default_settings = {
1451*053f45beSAndroid Build Coastguard Worker 		.thp_enabled = THP_MADVISE,
1452*053f45beSAndroid Build Coastguard Worker 		.thp_defrag = THP_DEFRAG_ALWAYS,
1453*053f45beSAndroid Build Coastguard Worker 		.shmem_enabled = SHMEM_ADVISE,
1454*053f45beSAndroid Build Coastguard Worker 		.use_zero_page = 0,
1455*053f45beSAndroid Build Coastguard Worker 		.khugepaged = {
1456*053f45beSAndroid Build Coastguard Worker 			.defrag = 1,
1457*053f45beSAndroid Build Coastguard Worker 			.alloc_sleep_millisecs = 10,
1458*053f45beSAndroid Build Coastguard Worker 			.scan_sleep_millisecs = 10,
1459*053f45beSAndroid Build Coastguard Worker 		},
1460*053f45beSAndroid Build Coastguard Worker 		/*
1461*053f45beSAndroid Build Coastguard Worker 		 * When testing file-backed memory, the collapse path
1462*053f45beSAndroid Build Coastguard Worker 		 * looks at how many pages are found in the page cache, not
1463*053f45beSAndroid Build Coastguard Worker 		 * what pages are mapped. Disable read ahead optimization so
1464*053f45beSAndroid Build Coastguard Worker 		 * pages don't find their way into the page cache unless
1465*053f45beSAndroid Build Coastguard Worker 		 * we mem_ops->fault() them in.
1466*053f45beSAndroid Build Coastguard Worker 		 */
1467*053f45beSAndroid Build Coastguard Worker 		.read_ahead_kb = 0,
1468*053f45beSAndroid Build Coastguard Worker 	};
1469*053f45beSAndroid Build Coastguard Worker 
1470*053f45beSAndroid Build Coastguard Worker 	parse_test_type(argc, argv);
1471*053f45beSAndroid Build Coastguard Worker 
1472*053f45beSAndroid Build Coastguard Worker 	if (file_ops)
1473*053f45beSAndroid Build Coastguard Worker 		get_finfo(argv[2]);
1474*053f45beSAndroid Build Coastguard Worker 
1475*053f45beSAndroid Build Coastguard Worker 	setbuf(stdout, NULL);
1476*053f45beSAndroid Build Coastguard Worker 
1477*053f45beSAndroid Build Coastguard Worker 	page_size = getpagesize();
1478*053f45beSAndroid Build Coastguard Worker 	hpage_pmd_size = read_pmd_pagesize();
1479*053f45beSAndroid Build Coastguard Worker 	hpage_pmd_nr = hpage_pmd_size / page_size;
1480*053f45beSAndroid Build Coastguard Worker 
1481*053f45beSAndroid Build Coastguard Worker 	default_settings.khugepaged.max_ptes_none = hpage_pmd_nr - 1;
1482*053f45beSAndroid Build Coastguard Worker 	default_settings.khugepaged.max_ptes_swap = hpage_pmd_nr / 8;
1483*053f45beSAndroid Build Coastguard Worker 	default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2;
1484*053f45beSAndroid Build Coastguard Worker 	default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8;
1485*053f45beSAndroid Build Coastguard Worker 
1486*053f45beSAndroid Build Coastguard Worker 	save_settings();
1487*053f45beSAndroid Build Coastguard Worker 	push_settings(&default_settings);
1488*053f45beSAndroid Build Coastguard Worker 
1489*053f45beSAndroid Build Coastguard Worker 	alloc_at_fault();
1490*053f45beSAndroid Build Coastguard Worker 
1491*053f45beSAndroid Build Coastguard Worker #define TEST(t, c, o) do { \
1492*053f45beSAndroid Build Coastguard Worker 	if (c && o) { \
1493*053f45beSAndroid Build Coastguard Worker 		printf("\nRun test: " #t " (%s:%s)\n", c->name, o->name); \
1494*053f45beSAndroid Build Coastguard Worker 		t(c, o); \
1495*053f45beSAndroid Build Coastguard Worker 	} \
1496*053f45beSAndroid Build Coastguard Worker 	} while (0)
1497*053f45beSAndroid Build Coastguard Worker 
1498*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full, khugepaged_context, anon_ops);
1499*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full, khugepaged_context, file_ops);
1500*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full, khugepaged_context, shmem_ops);
1501*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full, madvise_context, anon_ops);
1502*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full, madvise_context, file_ops);
1503*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full, madvise_context, shmem_ops);
1504*053f45beSAndroid Build Coastguard Worker 
1505*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_empty, khugepaged_context, anon_ops);
1506*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_empty, madvise_context, anon_ops);
1507*053f45beSAndroid Build Coastguard Worker 
1508*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry, khugepaged_context, anon_ops);
1509*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry, khugepaged_context, file_ops);
1510*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry, khugepaged_context, shmem_ops);
1511*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry, madvise_context, anon_ops);
1512*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry, madvise_context, file_ops);
1513*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry, madvise_context, shmem_ops);
1514*053f45beSAndroid Build Coastguard Worker 
1515*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_none, khugepaged_context, anon_ops);
1516*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_none, khugepaged_context, file_ops);
1517*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_none, madvise_context, anon_ops);
1518*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_none, madvise_context, file_ops);
1519*053f45beSAndroid Build Coastguard Worker 
1520*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry_compound, khugepaged_context, anon_ops);
1521*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry_compound, khugepaged_context, file_ops);
1522*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry_compound, madvise_context, anon_ops);
1523*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_single_pte_entry_compound, madvise_context, file_ops);
1524*053f45beSAndroid Build Coastguard Worker 
1525*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full_of_compound, khugepaged_context, anon_ops);
1526*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full_of_compound, khugepaged_context, file_ops);
1527*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full_of_compound, khugepaged_context, shmem_ops);
1528*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full_of_compound, madvise_context, anon_ops);
1529*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full_of_compound, madvise_context, file_ops);
1530*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_full_of_compound, madvise_context, shmem_ops);
1531*053f45beSAndroid Build Coastguard Worker 
1532*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_compound_extreme, khugepaged_context, anon_ops);
1533*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_compound_extreme, madvise_context, anon_ops);
1534*053f45beSAndroid Build Coastguard Worker 
1535*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_swapin_single_pte, khugepaged_context, anon_ops);
1536*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_swapin_single_pte, madvise_context, anon_ops);
1537*053f45beSAndroid Build Coastguard Worker 
1538*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_swap, khugepaged_context, anon_ops);
1539*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_swap, madvise_context, anon_ops);
1540*053f45beSAndroid Build Coastguard Worker 
1541*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_fork, khugepaged_context, anon_ops);
1542*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_fork, madvise_context, anon_ops);
1543*053f45beSAndroid Build Coastguard Worker 
1544*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_fork_compound, khugepaged_context, anon_ops);
1545*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_fork_compound, madvise_context, anon_ops);
1546*053f45beSAndroid Build Coastguard Worker 
1547*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_shared, khugepaged_context, anon_ops);
1548*053f45beSAndroid Build Coastguard Worker 	TEST(collapse_max_ptes_shared, madvise_context, anon_ops);
1549*053f45beSAndroid Build Coastguard Worker 
1550*053f45beSAndroid Build Coastguard Worker 	TEST(madvise_collapse_existing_thps, madvise_context, anon_ops);
1551*053f45beSAndroid Build Coastguard Worker 	TEST(madvise_collapse_existing_thps, madvise_context, file_ops);
1552*053f45beSAndroid Build Coastguard Worker 	TEST(madvise_collapse_existing_thps, madvise_context, shmem_ops);
1553*053f45beSAndroid Build Coastguard Worker 
1554*053f45beSAndroid Build Coastguard Worker 	TEST(madvise_retracted_page_tables, madvise_context, file_ops);
1555*053f45beSAndroid Build Coastguard Worker 	TEST(madvise_retracted_page_tables, madvise_context, shmem_ops);
1556*053f45beSAndroid Build Coastguard Worker 
1557*053f45beSAndroid Build Coastguard Worker 	restore_settings(0);
1558*053f45beSAndroid Build Coastguard Worker }
1559