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, <mingo@elte.hu> wrote this test case
65 * - Nick Piggin, <nickpiggin@yahoo.com.au> did the following cleanup
66 *
67 * 11/10/2007 - Port to LTP format by Subrata Modak, <subrata@linux.vnet.ibm.com>
68 * and Ricardo Salveti de Araujo, <rsalveti@linux.vnet.ibm.com>
69 * 25/02/2008 - Renaud Lottiaux, <Renaud.Lottiaux@kerlabs.com>
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
89 #include "test.h" /*LTP Specific Include File */
90
91 /* Test case defines */
92 #define WINDOW_START 0x48000000
93
94 static int page_sz;
95 size_t page_words;
96 size_t cache_pages;
97 size_t cache_sz;
98 size_t window_pages;
99 size_t window_sz;
100
101 static void setup();
102 static void cleanup();
103 static void test_nonlinear(int fd);
104
105 char *TCID = "remap_file_pages01";
106 int TST_TOTAL = 2;
107
108 static char *cache_contents;
109 int fd1, fd2; /* File descriptors used at the test */
110 char fname[255];
111
main(int ac, char **av)112 int main(int ac, char **av)
113 {
114 int lc;
115
116 tst_parse_opts(ac, av, NULL, NULL);
117
118 setup();
119
120 for (lc = 0; TEST_LOOPING(lc); lc++) {
121
122 tst_count = 0;
123
124 test_nonlinear(fd1);
125 tst_resm(TPASS, "Non-Linear shm file OK");
126
127 test_nonlinear(fd2);
128 tst_resm(TPASS, "Non-Linear /tmp/ file OK");
129 }
130
131 /* clean up and exit */
132 cleanup();
133 tst_exit();
134
135 }
136
137 /* test case function, that runs remap_file_pages */
test_nonlinear(int fd)138 static void test_nonlinear(int fd)
139 {
140 char *data = NULL;
141 int i, j, repeat = 2;
142
143 for (i = 0; i < (int)cache_pages; i++) {
144 char *page = cache_contents + i * page_sz;
145
146 for (j = 0; j < (int)page_words; j++)
147 page[j] = i;
148 }
149
150 if (write(fd, cache_contents, cache_sz) != (int)cache_sz) {
151 tst_resm(TFAIL,
152 "Write Error for \"cache_contents\" to \"cache_sz\" of %zu (errno=%d : %s)",
153 cache_sz, errno, strerror(errno));
154 cleanup(NULL);
155 }
156
157 data = mmap((void *)WINDOW_START,
158 window_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
159
160 if (data == MAP_FAILED) {
161 tst_resm(TFAIL, "mmap Error, errno=%d : %s", errno,
162 strerror(errno));
163 cleanup(NULL);
164 }
165
166 again:
167 for (i = 0; i < (int)window_pages; i += 2) {
168 char *page = data + i * page_sz;
169
170 if (remap_file_pages(page, page_sz * 2, 0,
171 (window_pages - i - 2), 0) == -1) {
172 tst_resm(TFAIL | TERRNO,
173 "remap_file_pages error for page=%p, "
174 "page_sz=%d, window_pages=%zu",
175 page, (page_sz * 2), (window_pages - i - 2));
176 cleanup(data);
177 }
178 }
179
180 for (i = 0; i < (int)window_pages; i++) {
181 /*
182 * Double-check the correctness of the mapping:
183 */
184 if (i & 1) {
185 if (data[i * page_sz] != ((int)window_pages) - i) {
186 tst_resm(TFAIL,
187 "hm, mapped incorrect data, "
188 "data[%d]=%d, (window_pages-%d)=%zu",
189 (i * page_sz), data[i * page_sz], i,
190 (window_pages - i));
191 cleanup(data);
192 }
193 } else {
194 if (data[i * page_sz] != ((int)window_pages) - i - 2) {
195 tst_resm(TFAIL,
196 "hm, mapped incorrect data, "
197 "data[%d]=%d, (window_pages-%d-2)=%zu",
198 (i * page_sz), data[i * page_sz], i,
199 (window_pages - i - 2));
200 cleanup(data);
201 }
202 }
203 }
204
205 if (--repeat)
206 goto again;
207
208 munmap(data, window_sz);
209 }
210
211 /* setup() - performs all ONE TIME setup for this test */
setup(void)212 void setup(void)
213 {
214
215 tst_sig(FORK, DEF_HANDLER, cleanup);
216
217 tst_tmpdir();
218
219 TEST_PAUSE;
220
221 /* Get page size */
222 page_sz = getpagesize();
223
224 page_words = page_sz;
225
226 /* Set the cache size */
227 cache_pages = 1024;
228 cache_sz = cache_pages * page_sz;
229 cache_contents = malloc(cache_sz * sizeof(char));
230
231 /* Set the window size */
232 window_pages = 16;
233 window_sz = window_pages * page_sz;
234
235 sprintf(fname, "/dev/shm/cache_%d", getpid());
236
237 if ((fd1 = open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
238 tst_brkm(TBROK, cleanup,
239 "open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
240 fname, errno, strerror(errno));
241 }
242
243 if ((fd2 = open("cache", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
244 tst_brkm(TBROK, cleanup,
245 "open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
246 "cache", errno, strerror(errno));
247 }
248
249 }
250
251 /*
252 * cleanup() - Performs one time cleanup for this test at
253 * completion or premature exit
254 */
cleanup(char *data)255 void cleanup(char *data)
256 {
257 /* Close the file descriptors */
258 close(fd1);
259 close(fd2);
260
261 if (data)
262 munmap(data, window_sz);
263
264 /* Remove the /dev/shm/cache_<pid> file */
265 unlink(fname);
266
267 tst_rmdir();
268
269 }
270