1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: LGPL-2.1-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (C) 2005-2007 IBM Corporation.
4f08c3bdfSopenharmony_ci * Author: David Gibson & Adam Litke
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*\
8f08c3bdfSopenharmony_ci * [Description]
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * This Test perform mmap, munmap and write operation on hugetlb file
11f08c3bdfSopenharmony_ci * based mapping. Mapping can be shared or private. and it checks for
12f08c3bdfSopenharmony_ci * Hugetlb counter (Total, Free, Reserve, Surplus) in /proc/meminfo and
13f08c3bdfSopenharmony_ci * compare them with expected (calculated) value. if all checks are
14f08c3bdfSopenharmony_ci * successful, the test passes.
15f08c3bdfSopenharmony_ci */
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci#define _GNU_SOURCE
18f08c3bdfSopenharmony_ci#include <unistd.h>
19f08c3bdfSopenharmony_ci#include <stdio.h>
20f08c3bdfSopenharmony_ci#include <sys/mount.h>
21f08c3bdfSopenharmony_ci#include <limits.h>
22f08c3bdfSopenharmony_ci#include <sys/param.h>
23f08c3bdfSopenharmony_ci#include <sys/types.h>
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_ci#include "hugetlb.h"
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_ci#define MNTPOINT "hugetlbfs/"
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_cistatic long hpage_size;
30f08c3bdfSopenharmony_cistatic int private_resv;
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_ci#define NR_SLOTS	2
33f08c3bdfSopenharmony_ci#define SL_SETUP	0
34f08c3bdfSopenharmony_ci#define SL_TEST		1
35f08c3bdfSopenharmony_cistatic int map_fd[NR_SLOTS];
36f08c3bdfSopenharmony_cistatic char *map_addr[NR_SLOTS];
37f08c3bdfSopenharmony_cistatic unsigned long map_size[NR_SLOTS];
38f08c3bdfSopenharmony_cistatic unsigned int touched[NR_SLOTS];
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_cistatic long prev_total;
41f08c3bdfSopenharmony_cistatic long prev_free;
42f08c3bdfSopenharmony_cistatic long prev_resv;
43f08c3bdfSopenharmony_cistatic long prev_surp;
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_cistatic void read_meminfo_huge(long *total, long *free, long *resv, long *surp)
46f08c3bdfSopenharmony_ci{
47f08c3bdfSopenharmony_ci	*total = SAFE_READ_MEMINFO(MEMINFO_HPAGE_TOTAL);
48f08c3bdfSopenharmony_ci	*free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
49f08c3bdfSopenharmony_ci	*resv = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
50f08c3bdfSopenharmony_ci	*surp = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP);
51f08c3bdfSopenharmony_ci}
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_cistatic int kernel_has_private_reservations(void)
54f08c3bdfSopenharmony_ci{
55f08c3bdfSopenharmony_ci	int fd;
56f08c3bdfSopenharmony_ci	long t, f, r, s;
57f08c3bdfSopenharmony_ci	long nt, nf, nr, ns;
58f08c3bdfSopenharmony_ci	void *p;
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci	read_meminfo_huge(&t, &f, &r, &s);
61f08c3bdfSopenharmony_ci	fd = tst_creat_unlinked(MNTPOINT, 0);
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	read_meminfo_huge(&nt, &nf, &nr, &ns);
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci	SAFE_MUNMAP(p, hpage_size);
68f08c3bdfSopenharmony_ci	SAFE_CLOSE(fd);
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci	/*
71f08c3bdfSopenharmony_ci	 * There are only three valid cases:
72f08c3bdfSopenharmony_ci	 * 1) If a surplus page was allocated to create a reservation, all
73f08c3bdfSopenharmony_ci	 *    four pool counters increment
74f08c3bdfSopenharmony_ci	 * 2) All counters remain the same except for Hugepages_Rsvd, then
75f08c3bdfSopenharmony_ci	 *    a reservation was created using an existing pool page.
76f08c3bdfSopenharmony_ci	 * 3) All counters remain the same, indicates that no reservation has
77f08c3bdfSopenharmony_ci	 *    been created
78f08c3bdfSopenharmony_ci	 */
79f08c3bdfSopenharmony_ci	if ((nt == t + 1) && (nf == f + 1) && (ns == s + 1) && (nr == r + 1))
80f08c3bdfSopenharmony_ci		return 1;
81f08c3bdfSopenharmony_ci	else if ((nt == t) && (nf == f) && (ns == s)) {
82f08c3bdfSopenharmony_ci		if (nr == r + 1)
83f08c3bdfSopenharmony_ci			return 1;
84f08c3bdfSopenharmony_ci		else if (nr == r)
85f08c3bdfSopenharmony_ci			return 0;
86f08c3bdfSopenharmony_ci	}
87f08c3bdfSopenharmony_ci	tst_brk(TCONF, "bad counter state - "
88f08c3bdfSopenharmony_ci	      "T:%li F:%li R:%li S:%li -> T:%li F:%li R:%li S:%li",
89f08c3bdfSopenharmony_ci		  t, f, r, s, nt, nf, nr, ns);
90f08c3bdfSopenharmony_ci	return -1;
91f08c3bdfSopenharmony_ci}
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_cistatic int verify_counters(int line, char *desc, long et, long ef, long er, long es)
94f08c3bdfSopenharmony_ci{
95f08c3bdfSopenharmony_ci	long t, f, r, s;
96f08c3bdfSopenharmony_ci	long fail = 0;
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	read_meminfo_huge(&t, &f, &r, &s);
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci	if (t != et) {
101f08c3bdfSopenharmony_ci		tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_TOTAL
102f08c3bdfSopenharmony_ci				" expected %li, actual %li", desc, et, t);
103f08c3bdfSopenharmony_ci		fail++;
104f08c3bdfSopenharmony_ci	}
105f08c3bdfSopenharmony_ci	if (f != ef) {
106f08c3bdfSopenharmony_ci		tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_FREE
107f08c3bdfSopenharmony_ci				" expected %li, actual %li", desc, ef, f);
108f08c3bdfSopenharmony_ci		fail++;
109f08c3bdfSopenharmony_ci	}
110f08c3bdfSopenharmony_ci	if (r != er) {
111f08c3bdfSopenharmony_ci		tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_RSVD
112f08c3bdfSopenharmony_ci				" expected %li, actual %li", desc, er, r);
113f08c3bdfSopenharmony_ci		fail++;
114f08c3bdfSopenharmony_ci	}
115f08c3bdfSopenharmony_ci	if (s != es) {
116f08c3bdfSopenharmony_ci		tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_SURP
117f08c3bdfSopenharmony_ci				" expected %li, actual %li", desc, es, s);
118f08c3bdfSopenharmony_ci		fail++;
119f08c3bdfSopenharmony_ci	}
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_ci	if (fail)
122f08c3bdfSopenharmony_ci		return -1;
123f08c3bdfSopenharmony_ci
124f08c3bdfSopenharmony_ci	prev_total = t;
125f08c3bdfSopenharmony_ci	prev_free = f;
126f08c3bdfSopenharmony_ci	prev_resv = r;
127f08c3bdfSopenharmony_ci	prev_surp = s;
128f08c3bdfSopenharmony_ci	return 0;
129f08c3bdfSopenharmony_ci}
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ci/* Memory operations:
132f08c3bdfSopenharmony_ci * Each of these has a predefined effect on the counters
133f08c3bdfSopenharmony_ci */
134f08c3bdfSopenharmony_cistatic int set_nr_hugepages_(long count, char *desc, int line)
135f08c3bdfSopenharmony_ci{
136f08c3bdfSopenharmony_ci	long min_size;
137f08c3bdfSopenharmony_ci	long et, ef, er, es;
138f08c3bdfSopenharmony_ci
139f08c3bdfSopenharmony_ci	SAFE_FILE_PRINTF(PATH_NR_HPAGES, "%lu", count);
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci	/* The code below is based on set_max_huge_pages in mm/hugetlb.c */
142f08c3bdfSopenharmony_ci	es = prev_surp;
143f08c3bdfSopenharmony_ci	et = prev_total;
144f08c3bdfSopenharmony_ci	ef = prev_free;
145f08c3bdfSopenharmony_ci	er = prev_resv;
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	/*
148f08c3bdfSopenharmony_ci	 * Increase the pool size
149f08c3bdfSopenharmony_ci	 * First take pages out of surplus state.  Then make up the
150f08c3bdfSopenharmony_ci	 * remaining difference by allocating fresh huge pages.
151f08c3bdfSopenharmony_ci	 */
152f08c3bdfSopenharmony_ci	while (es && count > et - es)
153f08c3bdfSopenharmony_ci		es--;
154f08c3bdfSopenharmony_ci	while (count > et - es) {
155f08c3bdfSopenharmony_ci		et++;
156f08c3bdfSopenharmony_ci		ef++;
157f08c3bdfSopenharmony_ci	}
158f08c3bdfSopenharmony_ci	if (count >= et - es)
159f08c3bdfSopenharmony_ci		goto out;
160f08c3bdfSopenharmony_ci
161f08c3bdfSopenharmony_ci	/*
162f08c3bdfSopenharmony_ci	 * Decrease the pool size
163f08c3bdfSopenharmony_ci	 * First return free pages to the buddy allocator (being careful
164f08c3bdfSopenharmony_ci	 * to keep enough around to satisfy reservations).  Then place
165f08c3bdfSopenharmony_ci	 * pages into surplus state as needed so the pool will shrink
166f08c3bdfSopenharmony_ci	 * to the desired size as pages become free.
167f08c3bdfSopenharmony_ci	 */
168f08c3bdfSopenharmony_ci	min_size = MAX(count, er + et - ef);
169f08c3bdfSopenharmony_ci	while (min_size < et - es) {
170f08c3bdfSopenharmony_ci		ef--;
171f08c3bdfSopenharmony_ci		et--;
172f08c3bdfSopenharmony_ci	}
173f08c3bdfSopenharmony_ci	while (count < et - es)
174f08c3bdfSopenharmony_ci		es++;
175f08c3bdfSopenharmony_ci
176f08c3bdfSopenharmony_ciout:
177f08c3bdfSopenharmony_ci	return verify_counters(line, desc, et, ef, er, es);
178f08c3bdfSopenharmony_ci}
179f08c3bdfSopenharmony_ci#define SET_NR_HUGEPAGES(c, d) set_nr_hugepages_(c, d, __LINE__)
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_cistatic int map_(int s, int hpages, int flags, char *desc, int line)
182f08c3bdfSopenharmony_ci{
183f08c3bdfSopenharmony_ci	long et, ef, er, es;
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_ci	map_fd[s] = tst_creat_unlinked(MNTPOINT, 0);
186f08c3bdfSopenharmony_ci	map_size[s] = hpages * hpage_size;
187f08c3bdfSopenharmony_ci	map_addr[s] = SAFE_MMAP(NULL, map_size[s], PROT_READ|PROT_WRITE, flags,
188f08c3bdfSopenharmony_ci				map_fd[s], 0);
189f08c3bdfSopenharmony_ci	touched[s] = 0;
190f08c3bdfSopenharmony_ci
191f08c3bdfSopenharmony_ci	et = prev_total;
192f08c3bdfSopenharmony_ci	ef = prev_free;
193f08c3bdfSopenharmony_ci	er = prev_resv;
194f08c3bdfSopenharmony_ci	es = prev_surp;
195f08c3bdfSopenharmony_ci	/*
196f08c3bdfSopenharmony_ci	 * When using MAP_SHARED, a reservation will be created to guarantee
197f08c3bdfSopenharmony_ci	 * pages to the process.  If not enough pages are available to
198f08c3bdfSopenharmony_ci	 * satisfy the reservation, surplus pages are added to the pool.
199f08c3bdfSopenharmony_ci	 * NOTE: This code assumes that the whole mapping needs to be
200f08c3bdfSopenharmony_ci	 * reserved and hence, will not work with partial reservations.
201f08c3bdfSopenharmony_ci	 *
202f08c3bdfSopenharmony_ci	 * If the kernel supports private reservations, then MAP_PRIVATE
203f08c3bdfSopenharmony_ci	 * mappings behave like MAP_SHARED at mmap time.  Otherwise,
204f08c3bdfSopenharmony_ci	 * no counter updates will occur.
205f08c3bdfSopenharmony_ci	 */
206f08c3bdfSopenharmony_ci	if ((flags & MAP_SHARED) || private_resv) {
207f08c3bdfSopenharmony_ci		unsigned long shortfall = 0;
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_ci		if (hpages + prev_resv > prev_free)
210f08c3bdfSopenharmony_ci			shortfall = hpages - prev_free + prev_resv;
211f08c3bdfSopenharmony_ci		et += shortfall;
212f08c3bdfSopenharmony_ci		ef += shortfall;
213f08c3bdfSopenharmony_ci		er += hpages;
214f08c3bdfSopenharmony_ci		es += shortfall;
215f08c3bdfSopenharmony_ci	}
216f08c3bdfSopenharmony_ci
217f08c3bdfSopenharmony_ci	return verify_counters(line, desc, et, ef, er, es);
218f08c3bdfSopenharmony_ci}
219f08c3bdfSopenharmony_ci#define MAP(s, h, f, d) map_(s, h, f, d, __LINE__)
220f08c3bdfSopenharmony_ci
221f08c3bdfSopenharmony_cistatic int unmap_(int s, int hpages, int flags, char *desc, int line)
222f08c3bdfSopenharmony_ci{
223f08c3bdfSopenharmony_ci	long et, ef, er, es;
224f08c3bdfSopenharmony_ci	unsigned long i;
225f08c3bdfSopenharmony_ci
226f08c3bdfSopenharmony_ci	SAFE_MUNMAP(map_addr[s], map_size[s]);
227f08c3bdfSopenharmony_ci	SAFE_CLOSE(map_fd[s]);
228f08c3bdfSopenharmony_ci	map_addr[s] = NULL;
229f08c3bdfSopenharmony_ci	map_size[s] = 0;
230f08c3bdfSopenharmony_ci
231f08c3bdfSopenharmony_ci	et = prev_total;
232f08c3bdfSopenharmony_ci	ef = prev_free;
233f08c3bdfSopenharmony_ci	er = prev_resv;
234f08c3bdfSopenharmony_ci	es = prev_surp;
235f08c3bdfSopenharmony_ci
236f08c3bdfSopenharmony_ci	/*
237f08c3bdfSopenharmony_ci	 * When a VMA is unmapped, the instantiated (touched) pages are
238f08c3bdfSopenharmony_ci	 * freed.  If the pool is in a surplus state, pages are freed to the
239f08c3bdfSopenharmony_ci	 * buddy allocator, otherwise they go back into the hugetlb pool.
240f08c3bdfSopenharmony_ci	 * NOTE: This code assumes touched pages have only one user.
241f08c3bdfSopenharmony_ci	 */
242f08c3bdfSopenharmony_ci	for (i = 0; i < touched[s]; i++) {
243f08c3bdfSopenharmony_ci		if (es) {
244f08c3bdfSopenharmony_ci			et--;
245f08c3bdfSopenharmony_ci			es--;
246f08c3bdfSopenharmony_ci		} else
247f08c3bdfSopenharmony_ci			ef++;
248f08c3bdfSopenharmony_ci	}
249f08c3bdfSopenharmony_ci
250f08c3bdfSopenharmony_ci	/*
251f08c3bdfSopenharmony_ci	 * mmap may have created some surplus pages to accommodate a
252f08c3bdfSopenharmony_ci	 * reservation.  If those pages were not touched, then they will
253f08c3bdfSopenharmony_ci	 * not have been freed by the code above.  Free them here.
254f08c3bdfSopenharmony_ci	 */
255f08c3bdfSopenharmony_ci	if ((flags & MAP_SHARED) || private_resv) {
256f08c3bdfSopenharmony_ci		int unused_surplus = MIN(hpages - touched[s], es);
257f08c3bdfSopenharmony_ci
258f08c3bdfSopenharmony_ci		et -= unused_surplus;
259f08c3bdfSopenharmony_ci		ef -= unused_surplus;
260f08c3bdfSopenharmony_ci		er -= hpages - touched[s];
261f08c3bdfSopenharmony_ci		es -= unused_surplus;
262f08c3bdfSopenharmony_ci	}
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci	return verify_counters(line, desc, et, ef, er, es);
265f08c3bdfSopenharmony_ci}
266f08c3bdfSopenharmony_ci#define UNMAP(s, h, f, d) unmap_(s, h, f, d, __LINE__)
267f08c3bdfSopenharmony_ci
268f08c3bdfSopenharmony_cistatic int touch_(int s, int hpages, int flags, char *desc, int line)
269f08c3bdfSopenharmony_ci{
270f08c3bdfSopenharmony_ci	long et, ef, er, es;
271f08c3bdfSopenharmony_ci	int nr;
272f08c3bdfSopenharmony_ci	char *c;
273f08c3bdfSopenharmony_ci
274f08c3bdfSopenharmony_ci	for (c = map_addr[s], nr = hpages;
275f08c3bdfSopenharmony_ci			hpages && c < map_addr[s] + map_size[s];
276f08c3bdfSopenharmony_ci			c += hpage_size, nr--)
277f08c3bdfSopenharmony_ci		*c = (char) (nr % 2);
278f08c3bdfSopenharmony_ci	/*
279f08c3bdfSopenharmony_ci	 * Keep track of how many pages were touched since we can't easily
280f08c3bdfSopenharmony_ci	 * detect that from user space.
281f08c3bdfSopenharmony_ci	 * NOTE: Calling this function more than once for a mmap may yield
282f08c3bdfSopenharmony_ci	 * results you don't expect.  Be careful :)
283f08c3bdfSopenharmony_ci	 */
284f08c3bdfSopenharmony_ci	touched[s] = MAX(touched[s], hpages);
285f08c3bdfSopenharmony_ci
286f08c3bdfSopenharmony_ci	/*
287f08c3bdfSopenharmony_ci	 * Shared (and private when supported) mappings and consume resv pages
288f08c3bdfSopenharmony_ci	 * that were previously allocated. Also deduct them from the free count.
289f08c3bdfSopenharmony_ci	 *
290f08c3bdfSopenharmony_ci	 * Unreserved private mappings may need to allocate surplus pages to
291f08c3bdfSopenharmony_ci	 * satisfy the fault.  The surplus pages become part of the pool
292f08c3bdfSopenharmony_ci	 * which could elevate total, free, and surplus counts.  resv is
293f08c3bdfSopenharmony_ci	 * unchanged but free must be decreased.
294f08c3bdfSopenharmony_ci	 */
295f08c3bdfSopenharmony_ci	if (flags & MAP_SHARED || private_resv) {
296f08c3bdfSopenharmony_ci		et = prev_total;
297f08c3bdfSopenharmony_ci		ef = prev_free - hpages;
298f08c3bdfSopenharmony_ci		er = prev_resv - hpages;
299f08c3bdfSopenharmony_ci		es = prev_surp;
300f08c3bdfSopenharmony_ci	} else {
301f08c3bdfSopenharmony_ci		if (hpages + prev_resv > prev_free)
302f08c3bdfSopenharmony_ci			et = prev_total + (hpages - prev_free + prev_resv);
303f08c3bdfSopenharmony_ci		else
304f08c3bdfSopenharmony_ci			et = prev_total;
305f08c3bdfSopenharmony_ci		er = prev_resv;
306f08c3bdfSopenharmony_ci		es = prev_surp + et - prev_total;
307f08c3bdfSopenharmony_ci		ef = prev_free - hpages + et - prev_total;
308f08c3bdfSopenharmony_ci	}
309f08c3bdfSopenharmony_ci	return verify_counters(line, desc, et, ef, er, es);
310f08c3bdfSopenharmony_ci}
311f08c3bdfSopenharmony_ci#define TOUCH(s, h, f, d) touch_(s, h, f, d, __LINE__)
312f08c3bdfSopenharmony_ci
313f08c3bdfSopenharmony_cistatic int test_counters(char *desc, int base_nr)
314f08c3bdfSopenharmony_ci{
315f08c3bdfSopenharmony_ci	tst_res(TINFO, "%s...", desc);
316f08c3bdfSopenharmony_ci
317f08c3bdfSopenharmony_ci	if (SET_NR_HUGEPAGES(base_nr, "initializing hugepages pool"))
318f08c3bdfSopenharmony_ci		return -1;
319f08c3bdfSopenharmony_ci
320f08c3bdfSopenharmony_ci	/* untouched, shared mmap */
321f08c3bdfSopenharmony_ci	if (MAP(SL_TEST, 1, MAP_SHARED, "doing mmap shared with no touch") ||
322f08c3bdfSopenharmony_ci		UNMAP(SL_TEST, 1, MAP_SHARED, "doing munmap on shared with no touch"))
323f08c3bdfSopenharmony_ci		return -1;
324f08c3bdfSopenharmony_ci
325f08c3bdfSopenharmony_ci	/* untouched, private mmap */
326f08c3bdfSopenharmony_ci	if (MAP(SL_TEST, 1, MAP_PRIVATE, "doing mmap private with no touch") ||
327f08c3bdfSopenharmony_ci		UNMAP(SL_TEST, 1, MAP_PRIVATE, "doing munmap private with on touch"))
328f08c3bdfSopenharmony_ci		return -1;
329f08c3bdfSopenharmony_ci
330f08c3bdfSopenharmony_ci	/* touched, shared mmap */
331f08c3bdfSopenharmony_ci	if (MAP(SL_TEST, 1, MAP_SHARED, "doing mmap shared followed by touch") ||
332f08c3bdfSopenharmony_ci		TOUCH(SL_TEST, 1, MAP_SHARED, "touching the addr after mmap shared") ||
333f08c3bdfSopenharmony_ci		UNMAP(SL_TEST, 1, MAP_SHARED, "doing munmap shared after touch"))
334f08c3bdfSopenharmony_ci		return -1;
335f08c3bdfSopenharmony_ci
336f08c3bdfSopenharmony_ci	/* touched, private mmap */
337f08c3bdfSopenharmony_ci	if (MAP(SL_TEST, 1, MAP_PRIVATE, "doing mmap private followed by touch") ||
338f08c3bdfSopenharmony_ci		TOUCH(SL_TEST, 1, MAP_PRIVATE, "touching the addr after mmap private") ||
339f08c3bdfSopenharmony_ci		UNMAP(SL_TEST, 1, MAP_PRIVATE, "doing munmap private after touch"))
340f08c3bdfSopenharmony_ci		return -1;
341f08c3bdfSopenharmony_ci
342f08c3bdfSopenharmony_ci	/*
343f08c3bdfSopenharmony_ci	 * Explicit resizing during outstanding surplus
344f08c3bdfSopenharmony_ci	 * Consume surplus when growing pool
345f08c3bdfSopenharmony_ci	 */
346f08c3bdfSopenharmony_ci	if (MAP(SL_TEST, 2, MAP_SHARED, "doing mmap to consume surplus") ||
347f08c3bdfSopenharmony_ci		SET_NR_HUGEPAGES(MAX(base_nr, 1), "setting hugepages pool to consume surplus"))
348f08c3bdfSopenharmony_ci		return -1;
349f08c3bdfSopenharmony_ci
350f08c3bdfSopenharmony_ci	/* Add pages once surplus is consumed */
351f08c3bdfSopenharmony_ci	if (SET_NR_HUGEPAGES(MAX(base_nr, 3), "adding more pages after consuming surplus"))
352f08c3bdfSopenharmony_ci		return -1;
353f08c3bdfSopenharmony_ci
354f08c3bdfSopenharmony_ci	/* Release free huge pages first */
355f08c3bdfSopenharmony_ci	if (SET_NR_HUGEPAGES(MAX(base_nr, 2), "releasing free huge pages"))
356f08c3bdfSopenharmony_ci		return -1;
357f08c3bdfSopenharmony_ci
358f08c3bdfSopenharmony_ci	/* When shrinking beyond committed level, increase surplus */
359f08c3bdfSopenharmony_ci	if (SET_NR_HUGEPAGES(base_nr, "increasing surplus counts"))
360f08c3bdfSopenharmony_ci		return -1;
361f08c3bdfSopenharmony_ci
362f08c3bdfSopenharmony_ci	/* Upon releasing the reservation, reduce surplus counts */
363f08c3bdfSopenharmony_ci	if (UNMAP(SL_TEST, 2, MAP_SHARED, "reducing surplus counts"))
364f08c3bdfSopenharmony_ci		return -1;
365f08c3bdfSopenharmony_ci
366f08c3bdfSopenharmony_ci	tst_res(TINFO, "OK");
367f08c3bdfSopenharmony_ci	return 0;
368f08c3bdfSopenharmony_ci}
369f08c3bdfSopenharmony_ci
370f08c3bdfSopenharmony_cistatic void per_iteration_cleanup(void)
371f08c3bdfSopenharmony_ci{
372f08c3bdfSopenharmony_ci	int nr;
373f08c3bdfSopenharmony_ci
374f08c3bdfSopenharmony_ci	prev_total = 0;
375f08c3bdfSopenharmony_ci	prev_free = 0;
376f08c3bdfSopenharmony_ci	prev_resv = 0;
377f08c3bdfSopenharmony_ci	prev_surp = 0;
378f08c3bdfSopenharmony_ci	for (nr = 0; nr < NR_SLOTS; nr++) {
379f08c3bdfSopenharmony_ci		if (map_addr[nr])
380f08c3bdfSopenharmony_ci			SAFE_MUNMAP(map_addr[nr], map_size[nr]);
381f08c3bdfSopenharmony_ci		if (map_fd[nr] > 0)
382f08c3bdfSopenharmony_ci			SAFE_CLOSE(map_fd[nr]);
383f08c3bdfSopenharmony_ci	}
384f08c3bdfSopenharmony_ci}
385f08c3bdfSopenharmony_ci
386f08c3bdfSopenharmony_cistatic int test_per_base_nr(int base_nr)
387f08c3bdfSopenharmony_ci{
388f08c3bdfSopenharmony_ci	tst_res(TINFO, "Base pool size: %i", base_nr);
389f08c3bdfSopenharmony_ci
390f08c3bdfSopenharmony_ci	/* Run the tests with a clean slate */
391f08c3bdfSopenharmony_ci	if (test_counters("Clean", base_nr))
392f08c3bdfSopenharmony_ci		return -1;
393f08c3bdfSopenharmony_ci
394f08c3bdfSopenharmony_ci	/* Now with a pre-existing untouched, shared mmap */
395f08c3bdfSopenharmony_ci	if (MAP(SL_SETUP, 1, MAP_SHARED, "mmap for test having prior untouched shared mmap") ||
396f08c3bdfSopenharmony_ci		test_counters("Untouched, shared", base_nr) ||
397f08c3bdfSopenharmony_ci		UNMAP(SL_SETUP, 1, MAP_SHARED, "unmap after test having prior untouched shared mmap"))
398f08c3bdfSopenharmony_ci		return -1;
399f08c3bdfSopenharmony_ci
400f08c3bdfSopenharmony_ci	/* Now with a pre-existing untouched, private mmap */
401f08c3bdfSopenharmony_ci	if (MAP(SL_SETUP, 1, MAP_PRIVATE, "mmap for test having prior untouched private mmap") ||
402f08c3bdfSopenharmony_ci		test_counters("Untouched, private", base_nr) ||
403f08c3bdfSopenharmony_ci		UNMAP(SL_SETUP, 1, MAP_PRIVATE, "unmap after test having prior untouched private mmap"))
404f08c3bdfSopenharmony_ci		return -1;
405f08c3bdfSopenharmony_ci
406f08c3bdfSopenharmony_ci	/* Now with a pre-existing touched, shared mmap */
407f08c3bdfSopenharmony_ci	if (MAP(SL_SETUP, 1, MAP_SHARED, "mmap for test having prior touched shared mmap") ||
408f08c3bdfSopenharmony_ci		TOUCH(SL_SETUP, 1, MAP_SHARED, "touching for test having prior touched shared mmap") ||
409f08c3bdfSopenharmony_ci		test_counters("Touched, shared", base_nr) ||
410f08c3bdfSopenharmony_ci		UNMAP(SL_SETUP, 1, MAP_SHARED, "unmap after test having prior touched shared mmap"))
411f08c3bdfSopenharmony_ci		return -1;
412f08c3bdfSopenharmony_ci
413f08c3bdfSopenharmony_ci	/* Now with a pre-existing touched, private mmap */
414f08c3bdfSopenharmony_ci	if (MAP(SL_SETUP, 1, MAP_PRIVATE, "mmap for test with having touched private mmap") ||
415f08c3bdfSopenharmony_ci		TOUCH(SL_SETUP, 1, MAP_PRIVATE, "touching for test with having touched private mmap") ||
416f08c3bdfSopenharmony_ci		test_counters("Touched, private", base_nr) ||
417f08c3bdfSopenharmony_ci		UNMAP(SL_SETUP, 1, MAP_PRIVATE,	"unmap after test having prior touched private mmap"))
418f08c3bdfSopenharmony_ci		return -1;
419f08c3bdfSopenharmony_ci	return 0;
420f08c3bdfSopenharmony_ci}
421f08c3bdfSopenharmony_ci
422f08c3bdfSopenharmony_cistatic void run_test(void)
423f08c3bdfSopenharmony_ci{
424f08c3bdfSopenharmony_ci	int base_nr;
425f08c3bdfSopenharmony_ci
426f08c3bdfSopenharmony_ci	for (base_nr = 0; base_nr <= 3; base_nr++) {
427f08c3bdfSopenharmony_ci		if (test_per_base_nr(base_nr))
428f08c3bdfSopenharmony_ci			break;
429f08c3bdfSopenharmony_ci	}
430f08c3bdfSopenharmony_ci	if (base_nr > 3)
431f08c3bdfSopenharmony_ci		tst_res(TPASS, "Hugepages Counters works as expected.");
432f08c3bdfSopenharmony_ci	per_iteration_cleanup();
433f08c3bdfSopenharmony_ci}
434f08c3bdfSopenharmony_ci
435f08c3bdfSopenharmony_cistatic void setup(void)
436f08c3bdfSopenharmony_ci{
437f08c3bdfSopenharmony_ci	hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024;
438f08c3bdfSopenharmony_ci	SAFE_FILE_PRINTF(PATH_OC_HPAGES, "%lu", tst_hugepages);
439f08c3bdfSopenharmony_ci	private_resv = kernel_has_private_reservations();
440f08c3bdfSopenharmony_ci}
441f08c3bdfSopenharmony_ci
442f08c3bdfSopenharmony_cistatic void cleanup(void)
443f08c3bdfSopenharmony_ci{
444f08c3bdfSopenharmony_ci	per_iteration_cleanup();
445f08c3bdfSopenharmony_ci}
446f08c3bdfSopenharmony_ci
447f08c3bdfSopenharmony_cistatic struct tst_test test = {
448f08c3bdfSopenharmony_ci	.needs_root = 1,
449f08c3bdfSopenharmony_ci	.mntpoint = MNTPOINT,
450f08c3bdfSopenharmony_ci	.needs_hugetlbfs = 1,
451f08c3bdfSopenharmony_ci	.save_restore = (const struct tst_path_val[]) {
452f08c3bdfSopenharmony_ci		{PATH_OC_HPAGES, NULL},
453f08c3bdfSopenharmony_ci		{PATH_NR_HPAGES, NULL},
454f08c3bdfSopenharmony_ci		{}
455f08c3bdfSopenharmony_ci	},
456f08c3bdfSopenharmony_ci	.setup = setup,
457f08c3bdfSopenharmony_ci	.cleanup = cleanup,
458f08c3bdfSopenharmony_ci	.test_all = run_test,
459f08c3bdfSopenharmony_ci	.hugepages = {3, TST_NEEDS},
460f08c3bdfSopenharmony_ci};
461