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