1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) International Business Machines  Corp., 2004
4 * Copyright (c) Linux Test Project, 2004-2017
5 *
6 * Test Name: hugemmap04
7 *
8 * Test Description:
9 *  Verify that, a hugetlb mmap() succeeds when used to map the largest
10 *  size possible.
11 *
12 * Expected Result:
13 *  mmap() should succeed returning the address of the hugetlb mapped region.
14 *  The number of free huge pages should decrease.
15 *
16 * Test:
17 *  Loop if the proper options are given.
18 *  Execute system call
19 *  Check return code, if system call failed (return=-1)
20 *  Log the errno and Issue a FAIL message.
21 *
22 * HISTORY
23 *  04/2004 Written by Robbie Williamson
24 */
25
26#include <sys/mount.h>
27#include <stdio.h>
28#include <limits.h>
29#include <sys/param.h>
30#include "lapi/abisize.h"
31#include "hugetlb.h"
32
33static char TEMPFILE[MAXPATHLEN];
34
35static long *addr;
36static long long mapsize;
37static int fildes;
38static long freepages;
39static long beforetest;
40static long aftertest;
41static long hugepagesmapped;
42
43static void test_hugemmap(void)
44{
45	int huge_pagesize = 0;
46
47	/* Creat a temporary file used for huge mapping */
48	fildes = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666);
49
50	freepages = SAFE_READ_MEMINFO("HugePages_Free:");
51	beforetest = freepages;
52
53	huge_pagesize = SAFE_READ_MEMINFO("Hugepagesize:");
54	tst_res(TINFO, "Size of huge pages is %d KB", huge_pagesize);
55
56#ifdef TST_ABI32
57	tst_res(TINFO, "Total amount of free huge pages is %ld",
58			freepages);
59	tst_res(TINFO, "Max number allowed for 1 mmap file in"
60			" 32-bits is 128");
61	if (freepages > 128)
62		freepages = 128;
63#endif
64	mapsize = (long long)freepages * huge_pagesize * 1024;
65	addr = mmap(NULL, mapsize, PROT_READ | PROT_WRITE,
66			MAP_SHARED, fildes, 0);
67	if (addr == MAP_FAILED) {
68		tst_res(TFAIL | TERRNO, "mmap() Failed on %s",
69				TEMPFILE);
70	} else {
71		tst_res(TPASS,
72				"Succeeded mapping file using %ld pages",
73				freepages);
74
75		/* force to allocate page and change HugePages_Free */
76		*(int *)addr = 0;
77		/* Make sure the number of free huge pages AFTER testing decreased */
78		aftertest = SAFE_READ_MEMINFO("HugePages_Free:");
79		hugepagesmapped = beforetest - aftertest;
80		if (hugepagesmapped < 1)
81			tst_res(TWARN, "Number of HUGEPAGES_FREE stayed the"
82					" same. Okay if multiple copies running due"
83					" to test collision.");
84	}
85
86	munmap(addr, mapsize);
87	close(fildes);
88}
89
90void setup(void)
91{
92	if (tst_hugepages == 0)
93		tst_brk(TCONF, "Not enough hugepages for testing!");
94
95	if (!Hopt)
96		Hopt = tst_get_tmpdir();
97	SAFE_MOUNT("none", Hopt, "hugetlbfs", 0, NULL);
98
99	snprintf(TEMPFILE, sizeof(TEMPFILE), "%s/mmapfile%d", Hopt, getpid());
100}
101
102void cleanup(void)
103{
104	unlink(TEMPFILE);
105	umount(Hopt);
106}
107
108static struct tst_test test = {
109	.needs_root = 1,
110	.needs_tmpdir = 1,
111	.options = (struct tst_option[]) {
112		{"H:", &Hopt,   "Location of hugetlbfs, i.e.  -H /var/hugetlbfs"},
113		{"s:", &nr_opt, "Set the number of the been allocated hugepages"},
114		{}
115	},
116	.setup = setup,
117	.cleanup = cleanup,
118	.test_all = test_hugemmap,
119	.hugepages = {128, TST_REQUEST},
120};
121