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