• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) Ricardo Salveti de Araujo, 2007
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 /*
25  * NAME
26  *     remap_file_pages02
27  *
28  * DESCRIPTION
29  *     The remap_file_pages() system call is used to create a non-linear
30  *     mapping, that is, a mapping in which the pages of the file are mapped
31  *     into a non-sequential order in memory.  The advantage of using
32  *     remap_file_pages() over using repeated calls to mmap(2) is that
33  *     the former  approach  does  not require the kernel to create
34  *     additional VMA (Virtual Memory Area) data structures.
35  *
36  *     Runs remap_file_pages with wrong values and see if got the expected error
37  *
38  *     Setup:
39  *       1. Global:
40  *       2. Create a file, do a normal mmap with MAP_SHARED flag
41  *
42  *     Test:
43  *       1. Test with a valid mmap but without MAP_SHARED flag
44  *       2. Test with a invalid start argument
45  *       3. Test with a invalid size argument
46  *       4. Test with a invalid prot argument
47  *
48  *     Cleanup:
49  *       Remove the file and erase the tmp directory
50  *
51  * Usage:  <for command-line>
52  *  remap_file_pages02 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
53  *     where,  -c n : Run n copies concurrently.
54  *             -f   : Turn off functionality Testing.
55  *             -i n : Execute test n times.
56  *             -I x : Execute test for x seconds.
57  *             -P x : Pause for x seconds between iterations.
58  *             -t   : Turn on syscall timing.
59  *
60  * HISTORY
61  *
62  *     02/11/2008 - Removed the pgoff test case, as the latest kernels doesn't
63  *     verify the page offset (http://lkml.org/lkml/2007/11/29/325) - Ricardo
64  *     Salveti de Araujo, <rsalvetidev@gmail.com>
65  *
66  *     19/10/2007 - Created by Ricardo Salveti de Araujo, <rsalvetidev@gmail.com>
67  */
68 
69 #define _GNU_SOURCE
70 #include <sys/mman.h>
71 #include <sys/types.h>
72 #include <sys/stat.h>
73 #include <fcntl.h>
74 #include <stdio.h>
75 #include <unistd.h>
76 #include <errno.h>
77 #include <sys/syscall.h>
78 #include <linux/unistd.h>
79 
80 #include "test.h"		/*LTP Specific Include File */
81 
82 /* Test case defines */
83 #define WINDOW_START 0x48000000
84 
85 static int page_sz;
86 size_t page_words;
87 size_t cache_pages;
88 size_t cache_sz;
89 size_t window_pages;
90 size_t window_sz;
91 
92 static void setup();
93 static int setup01(int test);
94 static int setup02(int test);
95 static int setup03(int test);
96 static int setup04(int test);
97 static void cleanup();
98 
99 char *TCID = "remap_file_pages02";
100 int TST_TOTAL = 4;
101 
102 static char *cache_contents;
103 int fd;				/* File descriptor used at the test */
104 char *data = NULL;
105 char *data01 = NULL;
106 
107 static struct test_case_t {
108 	char *err_desc;		/* Error description */
109 	int exp_errno;		/* Expected error number */
110 	char *exp_errval;	/* Expected error value string */
111 	int (*setupfunc) (int);	/* Test setup function */
112 	int (*cleanfunc) (int);	/* Test clean function */
113 	void *start;		/* Start argument */
114 	size_t size;		/* Size argument */
115 	int prot;		/* Prot argument */
116 	ssize_t pgoff;		/* Pgoff argument */
117 	int flags;		/* Flags argument */
118 } testcase[] = {
119 	{
120 	"start does not refer to a valid mapping created with the "
121 		    "MAP_SHARED flag", EINVAL, "EINVAL", setup01, NULL,
122 		    NULL, 0, 0, 2, 0}, {
123 	"start is invalid", EINVAL, "EINVAL", setup02, NULL, NULL, 0, 0, 2, 0},
124 	{
125 	"size is invalid", EINVAL, "EINVAL", setup03, NULL, NULL, 0, 0, 0, 0},
126 	{
127 	"prot is invalid", EINVAL, "EINVAL", setup04, NULL, NULL, 0, 0,
128 		    2, 0}
129 };
130 
main(int ac,char ** av)131 int main(int ac, char **av)
132 {
133 	int lc, i;
134 
135 #if defined (__s390__) || (__s390x__) || (__ia64__)
136 	/* Disables the test in case the kernel version is lower than 2.6.12 and arch is s390 */
137 	if ((tst_kvercmp(2, 6, 12)) < 0) {
138 		tst_resm(TWARN,
139 			 "This test can only run on kernels that are 2.6.12 and higher");
140 		exit(0);
141 	}
142 #endif
143 
144 	tst_parse_opts(ac, av, NULL, NULL);
145 
146 	setup();
147 
148 	for (lc = 0; TEST_LOOPING(lc); lc++) {
149 
150 		tst_count = 0;
151 
152 		for (i = 0; i < TST_TOTAL; i++) {
153 			/* do the setup if the test have one */
154 			if (testcase[i].setupfunc
155 			    && testcase[i].setupfunc(i) == -1) {
156 				tst_resm(TWARN,
157 					 "Failed to setup test %d"
158 					 " Skipping test", i);
159 				continue;
160 			}
161 
162 			/* run the test */
163 			TEST(remap_file_pages
164 			     (testcase[i].start, testcase[i].size,
165 			      testcase[i].prot, testcase[i].pgoff,
166 			      testcase[i].flags));
167 
168 			/* do the cleanup if the test have one */
169 			if (testcase[i].cleanfunc
170 			    && testcase[i].cleanfunc(i) == -1) {
171 				tst_brkm(TBROK, cleanup,
172 					 "Failed to cleanup test %d,"
173 					 " quitting the test", i);
174 			}
175 
176 			/* verify the return code */
177 			if ((TEST_RETURN == -1)
178 			    && (TEST_ERRNO == testcase[i].exp_errno)) {
179 				tst_resm(TPASS,
180 					 "remap_file_pages(2) expected failure;"
181 					 " Got errno - %s : %s",
182 					 testcase[i].exp_errval,
183 					 testcase[i].err_desc);
184 			} else {
185 				tst_resm(TFAIL,
186 					 "remap_file_pages(2) failed to produce"
187 					 " expected error: %d, errno: %s."
188 					 " because got error %d",
189 					 testcase[i].exp_errno,
190 					 testcase[i].exp_errval, TEST_ERRNO);
191 			}
192 		}		/* end of test loops */
193 	}			/* end of  test looping */
194 
195 	/* clean up and exit */
196 	cleanup();
197 
198 	tst_exit();
199 }
200 
201 /*
202  * setup01() - create a mmap area without MAP_SHARED flag
203  * - it uses the fd created at the main setup function
204  */
setup01(int test)205 int setup01(int test)
206 {
207 	data01 = mmap(NULL, cache_sz, PROT_READ | PROT_WRITE,
208 		      MAP_PRIVATE, fd, 0);
209 
210 	if (data01 == MAP_FAILED) {
211 		tst_resm(TWARN, "mmap Error, errno=%d : %s", errno,
212 			 strerror(errno));
213 		return -1;
214 	}
215 
216 	/* set up the test case struct for this test */
217 	testcase[test].start = data01;
218 	testcase[test].size = page_sz;
219 
220 	return 0;
221 }
222 
223 /*
224  * setup02() - start is invalid
225  */
setup02(int test)226 int setup02(int test)
227 {
228 	/* set up the test case struct for this test */
229 	testcase[test].start = data + cache_sz;
230 	testcase[test].size = page_sz;
231 
232 	return 0;
233 }
234 
235 /*
236  * setup03() - size is invalid
237  */
setup03(int test)238 int setup03(int test)
239 {
240 	/* set up the test case struct for this test */
241 	testcase[test].start = data;
242 	testcase[test].size = cache_sz + page_sz;
243 
244 	return 0;
245 }
246 
247 /*
248  * setup04() - prot is invalid
249  */
setup04(int test)250 int setup04(int test)
251 {
252 	/* set up the test case struct for this test */
253 	testcase[test].start = data;
254 	testcase[test].size = page_sz;
255 	testcase[test].prot = -1;
256 
257 	return 0;
258 }
259 
260 /*
261  * setup() - performs all ONE TIME setup for this test
262  * - creates a defaul mmaped area to be able to run remap_file_pages
263  */
setup(void)264 void setup(void)
265 {
266 	int i, j;
267 
268 	tst_sig(FORK, DEF_HANDLER, cleanup);
269 
270 	TEST_PAUSE;
271 
272 	tst_tmpdir();
273 
274 	/* Get page size */
275 	if ((page_sz = getpagesize()) < 0) {
276 		tst_brkm(TFAIL, cleanup,
277 			 "getpagesize() fails to get system page size");
278 	}
279 
280 	page_words = (page_sz / sizeof(char));
281 
282 	/* Set the cache size */
283 	cache_pages = 32;
284 	cache_sz = cache_pages * page_sz;
285 	cache_contents = malloc(cache_sz * sizeof(char));
286 
287 	for (i = 0; i < cache_pages; i++) {
288 		char *page = cache_contents + i * page_sz;
289 
290 		for (j = 0; j < page_words; j++)
291 			page[j] = i;
292 	}
293 
294 	if ((fd = open("cache", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
295 		tst_brkm(TBROK, cleanup,
296 			 "open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
297 			 "cache", errno, strerror(errno));
298 	}
299 
300 	if (write(fd, cache_contents, cache_sz) != cache_sz) {
301 		tst_resm(TFAIL,
302 			 "Write Error for \"cache_contents\" to \"cache_sz\" of %zu (errno=%d : %s)",
303 			 cache_sz, errno, strerror(errno));
304 		cleanup();
305 	}
306 
307 	data = mmap((void *)WINDOW_START,
308 		    cache_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
309 
310 	if (data == MAP_FAILED) {
311 		tst_resm(TFAIL, "mmap Error, errno=%d : %s", errno,
312 			 strerror(errno));
313 		cleanup();
314 	}
315 
316 }
317 
318 /*
319 * cleanup() - Performs one time cleanup for this test at
320 * completion or premature exit
321 */
cleanup(void)322 void cleanup(void)
323 {
324 	/* Close the file descriptor */
325 	close(fd);
326 
327 	if (data)
328 		munmap(data, cache_sz);
329 	if (data01)
330 		munmap(data01, cache_sz);
331 
332 	tst_rmdir();
333 
334 }
335