xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 /*
2  * Copyright (C) Ingo Molnar, 2002
3  * Copyright (C) Ricardo Salveti de Araujo, 2007
4  * Copyright (C) International Business Machines  Corp., 2007
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of version 2 of the GNU General Public License as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it would be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  *
14  * Further, this software is distributed without any warranty that it is
15  * free of the rightful claim of any third person regarding infringement
16  * or the like.  Any license provided herein, whether implied or
17  * otherwise, applies only to this software file.  Patent licenses, if
18  * any, provided herein do not apply to combinations of this program with
19  * other software, or any other product whatsoever.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 
26 /*
27  * NAME
28  *     remap_file_pages01
29  *
30  * DESCRIPTION
31  *     The remap_file_pages() system call is used to create a non-linear
32  *     mapping, that is, a mapping in which the pages of the file are mapped
33  *     into a non-sequential order in memory.  The advantage of using
34  *     remap_file_pages() over using repeated calls to mmap(2) is that
35  *     the former  approach  does  not require the kernel to create
36  *     additional VMA (Virtual Memory Area) data structures.
37  *
38  *     Runs remap_file_pages agains a mmaped area and check the results
39  *
40  *     Setup:
41  *       Create a temp directory, open a file and get the file descriptor
42  *
43  *     Test:
44  *       Test with a normal file and with /dev/shm/cache_<pid>
45  *       1. Set up the cache
46  *       2. Write the cache to the file
47  *       3. Runs mmap at the same file
48  *       4. Runs remap_file_pages at the mapped memory
49  *       5. Check the results
50  *   $
51  *     Cleanup:
52  *       Remove the file and erase the tmp directory
53  *
54  * Usage:  <for command-line>
55  *  remap_file_pages01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
56  *     where,  -c n : Run n copies concurrently.
57  *             -f   : Turn off functionality Testing.
58  *             -i n : Execute test n times.
59  *             -I x : Execute test for x seconds.
60  *             -P x : Pause for x seconds between iterations.
61  *             -t   : Turn on syscall timing.
62  *
63  * HISTORY
64  *                - Ingo Molnar, <[email protected]> wrote this test case
65  *                - Nick Piggin, <[email protected]> did the following cleanup
66  *
67  *     11/10/2007 - Port to LTP format by Subrata Modak, <[email protected]>
68  *                  and Ricardo Salveti de Araujo, <[email protected]>
69  *     25/02/2008 - Renaud Lottiaux, <[email protected]>
70  *                  Fix NFS remove tmpdir issue due to non unmapped files.
71  *                  Fix concurrency issue on the file /dev/shm/cache.
72  */
73 
74 #define _GNU_SOURCE
75 #include <stdio.h>
76 #include <unistd.h>
77 #include <sys/mman.h>
78 #include <sys/stat.h>
79 #include <sys/types.h>
80 #include <fcntl.h>
81 #include <errno.h>
82 #include <stdlib.h>
83 #include <sys/times.h>
84 #include <sys/wait.h>
85 #include <sys/ioctl.h>
86 #include <sys/syscall.h>
87 #include <linux/unistd.h>
88 #include <lapi/mmap.h>
89 
90 #include "test.h"		/*LTP Specific Include File */
91 
92 /* Test case defines */
93 #define WINDOW_START 0x48000000
94 
95 static int page_sz;
96 static int granula;
97 size_t page_words;
98 size_t cache_pages;
99 size_t cache_sz;
100 size_t window_pages;
101 size_t window_sz;
102 
103 static void setup();
104 static void cleanup();
105 static void test_nonlinear(int fd);
106 
107 char *TCID = "remap_file_pages01";
108 int TST_TOTAL = 2;
109 
110 static char *cache_contents;
111 int fd1, fd2;			/* File descriptors used at the test */
112 char fname[255];
113 
main(int ac,char ** av)114 int main(int ac, char **av)
115 {
116 	int lc;
117 
118 	tst_parse_opts(ac, av, NULL, NULL);
119 
120 	setup();
121 
122 	for (lc = 0; TEST_LOOPING(lc); lc++) {
123 
124 		tst_count = 0;
125 
126 		test_nonlinear(fd1);
127 		tst_resm(TPASS, "Non-Linear shm file OK");
128 
129 		test_nonlinear(fd2);
130 		tst_resm(TPASS, "Non-Linear /tmp/ file OK");
131 	}
132 
133 	/* clean up and exit */
134 	cleanup();
135 	tst_exit();
136 
137 }
138 
139 /* test case function, that runs remap_file_pages */
test_nonlinear(int fd)140 static void test_nonlinear(int fd)
141 {
142 	char *data = NULL;
143 	int i, j, repeat = 2;
144 
145 	for (i = 0; i < (int)cache_pages; i += granula) {
146 		char *page = cache_contents + i * page_sz;
147 
148 		for (j = 0; j < (int)page_words * granula; j++)
149 			page[j] = i;
150 	}
151 
152 	if (write(fd, cache_contents, cache_sz) != (int)cache_sz) {
153 		tst_resm(TFAIL,
154 			 "Write Error for \"cache_contents\" to \"cache_sz\" of %zu (errno=%d : %s)",
155 			 cache_sz, errno, strerror(errno));
156 		cleanup(NULL);
157 	}
158 
159 	data = mmap((void *)WINDOW_START,
160 		    window_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
161 
162 	if (data == MAP_FAILED) {
163 		tst_resm(TFAIL, "mmap Error, errno=%d : %s", errno,
164 			 strerror(errno));
165 		cleanup(NULL);
166 	}
167 
168 again:
169 	for (i = 0; i < (int)window_pages; i += 2 * granula) {
170 		char *page = data + i * page_sz;
171 
172 		if (remap_file_pages(page, 2 * MMAP_GRANULARITY, 0,
173 				     (window_pages - i - 2 * granula), 0) == -1) {
174 			tst_resm(TFAIL | TERRNO,
175 				 "remap_file_pages error for page=%p, "
176 				 "remap_sz=%d, window_pages=%zu",
177 				 page, 2 * MMAP_GRANULARITY, (window_pages - i - 2 * granula));
178 			cleanup(data);
179 		}
180 	}
181 
182 	for (i = 0, j = 0; i < (int)window_pages; i += granula, j++) {
183 		/*
184 		 * Double-check the correctness of the mapping:
185 		 */
186 		if (j & 1) {
187 			if (data[i * page_sz] != ((int)window_pages) - i) {
188 				tst_resm(TFAIL,
189 					 "hm, mapped incorrect data, "
190 					 "data[%d]=%d, (window_pages-%d)=%zu",
191 					 (i * page_sz), data[i * page_sz], i,
192 					 (window_pages - i));
193 				cleanup(data);
194 			}
195 		} else {
196 			if (data[i * page_sz] != ((int)window_pages) - i - 2 * granula) {
197 				tst_resm(TFAIL,
198 					 "hm, mapped incorrect data, "
199 					 "data[%d]=%d, (window_pages-%d-2 * min_pages)=%zu",
200 					 (i * page_sz), data[i * page_sz], i,
201 					 (window_pages - i - 2 * granula));
202 				cleanup(data);
203 			}
204 		}
205 	}
206 
207 	if (--repeat)
208 		goto again;
209 
210 	munmap(data, window_sz);
211 }
212 
213 /* setup() - performs all ONE TIME setup for this test */
setup(void)214 void setup(void)
215 {
216 
217 	tst_sig(FORK, DEF_HANDLER, cleanup);
218 
219 	tst_tmpdir();
220 
221 	TEST_PAUSE;
222 
223 	/* Get page size */
224 	page_sz = getpagesize();
225 
226 	page_words = page_sz;
227 
228 	granula = MMAP_GRANULARITY / page_sz;
229 
230 	/* Set the cache size */
231 	cache_pages = 1024 * granula;
232 	cache_sz = cache_pages * page_sz;
233 	cache_contents = malloc(cache_sz * sizeof(char));
234 
235 	/* Set the window size */
236 	window_pages = 16 * granula;
237 	window_sz = window_pages * page_sz;
238 
239 	sprintf(fname, "/dev/shm/cache_%d", getpid());
240 
241 	if ((fd1 = open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
242 		tst_brkm(TBROK, cleanup,
243 			 "open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
244 			 fname, errno, strerror(errno));
245 	}
246 
247 	if ((fd2 = open("cache", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
248 		tst_brkm(TBROK, cleanup,
249 			 "open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
250 			 "cache", errno, strerror(errno));
251 	}
252 
253 }
254 
255 /*
256 * cleanup() - Performs one time cleanup for this test at
257 * completion or premature exit
258 */
cleanup(char * data)259 void cleanup(char *data)
260 {
261 	/* Close the file descriptors */
262 	close(fd1);
263 	close(fd2);
264 
265 	if (data)
266 		munmap(data, window_sz);
267 
268 	/* Remove the /dev/shm/cache_<pid> file */
269 	unlink(fname);
270 
271 	tst_rmdir();
272 
273 }
274