xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/memfd_create/memfd_create03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  *  Copyright (c) Zilogic Systems Pvt. Ltd., 2018
5  *  Email: [email protected]
6  */
7 
8 /*
9  * Test: Validating memfd_create() with MFD_HUGETLB flag.
10  *
11  * Test case 1: --WRITE CALL IN HUGEPAGES TEST--
12  *              Huge pages are write protected. Any writes to
13  *              the file should return EINVAL error.
14  *
15  * Test case 2: --PAGE SIZE OF CREATED FILE TEST--
16  *              Default huge page sized pages are created with
17  *              MFD_HUGETLB flag. Any attempt to unmap memory-mapped
18  *              huge pages with an unmapping length less than
19  *              huge page size should return EINVAL error.
20  *
21  * Test case 3: --HUGEPAGE ALLOCATION LIMIT TEST--
22  *              Number of huge pages currently available to use should be
23  *              atmost total number of allowed huge pages. Memory-mapping
24  *              more than allowed huge pages should return ENOMEM error.
25  */
26 
27 #define _GNU_SOURCE
28 
29 #include "tst_test.h"
30 #include "memfd_create_common.h"
31 
32 #include <stdio.h>
33 #include <errno.h>
34 
check_huge_mmapable(int fd,unsigned long size)35 static void *check_huge_mmapable(int fd, unsigned long size)
36 {
37 	void *mem;
38 
39 	mem = SAFE_MMAP(NULL, size, PROT_WRITE, MAP_PRIVATE, fd, 0);
40 
41 	memset((char *)mem, 0, 1);
42 
43 	tst_res(TINFO,
44 		"mmap(%p, %lu, %d, %d, %d, %d) succeeded",
45 		NULL, size, PROT_WRITE, MAP_PRIVATE, fd, 0);
46 
47 	return mem;
48 }
49 
test_write_protect(int fd)50 static void test_write_protect(int fd)
51 {
52 	ssize_t ret;
53 	char test_str[] = "LTP";
54 
55 	ret = write(fd, test_str, strlen(test_str));
56 	if (ret < 0) {
57 		if (errno != EINVAL) {
58 			tst_res(TFAIL | TERRNO,
59 				"write(%d, \"%s\", %zu) didn't fail as expected\n",
60 				fd, test_str, strlen(test_str));
61 			return;
62 		}
63 	} else {
64 		tst_res(TFAIL,
65 			"write(%d, \"%s\", %zu) succeeded unexpectedly\n",
66 			fd, test_str, strlen(test_str));
67 		return;
68 	}
69 
70 	tst_res(TPASS,
71 		"write(%d, \"%s\", %zu) failed as expected\n",
72 		fd, test_str, strlen(test_str));
73 }
74 
test_def_pagesize(int fd)75 static void test_def_pagesize(int fd)
76 {
77 	unsigned int i;
78 	int unmap_size;
79 	int ret;
80 	long hps;
81 	void *mem;
82 
83 	hps = SAFE_READ_MEMINFO("Hugepagesize:");
84 	hps = hps << 10;
85 	unmap_size = hps / 4;
86 	mem = check_huge_mmapable(fd, hps);
87 
88 	for (i = unmap_size; i < hps; i += unmap_size) {
89 		ret = munmap(mem, i);
90 		if (ret == -1) {
91 			if (errno == EINVAL) {
92 				tst_res(TINFO,
93 					"munmap(%p, %dkB) failed as expected",
94 					mem, i/1024);
95 			} else {
96 				tst_res(TFAIL | TERRNO,
97 					"munmap(%p, %dkB) failed unexpectedly",
98 					mem, i/1024);
99 				return;
100 			}
101 		} else {
102 			tst_res(TFAIL,
103 				"munmap(%p, %dkB) suceeded unexpectedly\n",
104 				mem, i/1024);
105 			return;
106 		}
107 	}
108 
109 	SAFE_MUNMAP(mem, hps);
110 
111 	tst_res(TPASS,
112 		"munmap() fails for page sizes less than %ldkB\n", hps/1024);
113 }
114 
test_max_hugepages(int fd)115 static void test_max_hugepages(int fd)
116 {
117 	int new_fd;
118 	long hps;
119 	long free_pages;
120 	void *mem;
121 	void *new_mem;
122 
123 	free_pages = SAFE_READ_MEMINFO("HugePages_Free:");
124 	hps = SAFE_READ_MEMINFO("Hugepagesize:");
125 	hps = hps << 10;
126 	mem = check_huge_mmapable(fd, free_pages * hps);
127 
128 	new_fd = sys_memfd_create("new_file", MFD_HUGETLB);
129 	if (new_fd < 0)
130 		tst_brk(TFAIL | TERRNO, "memfd_create() failed");
131 	tst_res(TINFO, "memfd_create() succeeded");
132 
133 	new_mem = mmap(NULL, hps, 0, MAP_PRIVATE, new_fd, 0);
134 	if (new_mem == MAP_FAILED) {
135 		if (errno == ENOMEM)
136 			tst_res(TPASS,
137 				"mmap(%p, %lu, %d, %d, %d, %d) failed as expected",
138 				NULL, hps, 0, MAP_PRIVATE, new_fd, 0);
139 		else
140 			tst_res(TFAIL | TERRNO,
141 				"mmap(%p, %lu, %d, %d, %d, %d) failed unexpectedly",
142 				NULL, hps, 0, MAP_PRIVATE, new_fd, 0);
143 	} else {
144 		tst_res(TFAIL,
145 			"mmap(%p, %lu, %d, %d, %d, %d) succeeded",
146 			NULL, hps, 0, MAP_PRIVATE, new_fd, 0);
147 		SAFE_MUNMAP(new_mem, hps);
148 	}
149 
150 	SAFE_CLOSE(new_fd);
151 
152 	SAFE_MUNMAP(mem, free_pages * hps);
153 }
154 
155 static const struct tcase {
156 	void (*func)(int fd);
157 	const char *desc;
158 } tcases[] = {
159 	{&test_write_protect,   "--TESTING WRITE CALL IN HUGEPAGES--"},
160 	{&test_def_pagesize,  "--TESTING PAGE SIZE OF CREATED FILE--"},
161 	{&test_max_hugepages, "--TESTING HUGEPAGE ALLOCATION LIMIT--"},
162 };
163 
memfd_huge_controller(unsigned int n)164 static void memfd_huge_controller(unsigned int n)
165 {
166 	int fd;
167 	const struct tcase *tc;
168 
169 	tc = &tcases[n];
170 
171 	tst_res(TINFO, "%s", tc->desc);
172 
173 	fd = sys_memfd_create("test_file", MFD_HUGETLB);
174 	if (fd < 0)
175 		tst_brk(TFAIL | TERRNO, "memfd_create() failed");
176 	tst_res(TINFO, "memfd_create() succeeded");
177 
178 	tc->func(fd);
179 
180 	SAFE_CLOSE(fd);
181 }
182 
183 static struct tst_test test = {
184 	.test = memfd_huge_controller,
185 	.tcnt = ARRAY_SIZE(tcases),
186 	.needs_root = 1,
187 	.min_kver = "4.14",
188 	.hugepages = {1, TST_NEEDS},
189 };
190