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
94static int page_sz;
95size_t page_words;
96size_t cache_pages;
97size_t cache_sz;
98size_t window_pages;
99size_t window_sz;
100
101static void setup();
102static void cleanup();
103static void test_nonlinear(int fd);
104
105char *TCID = "remap_file_pages01";
106int TST_TOTAL = 2;
107
108static char *cache_contents;
109int fd1, fd2;			/* File descriptors used at the test */
110char fname[255];
111
112int main(int ac, char **av)
113{
114	int lc;
115
116#if defined (__s390__) || (__s390x__) || (__ia64__)
117	/* Disables the test in case the kernel version is lower than 2.6.12 and arch is s390 */
118	if ((tst_kvercmp(2, 6, 12)) < 0) {
119		tst_resm(TWARN,
120			 "This test can only run on kernels that are 2.6.12 and higher");
121		exit(0);
122	}
123#endif
124
125	tst_parse_opts(ac, av, NULL, NULL);
126
127	setup();
128
129	for (lc = 0; TEST_LOOPING(lc); lc++) {
130
131		tst_count = 0;
132
133		test_nonlinear(fd1);
134		tst_resm(TPASS, "Non-Linear shm file OK");
135
136		test_nonlinear(fd2);
137		tst_resm(TPASS, "Non-Linear /tmp/ file OK");
138	}
139
140	/* clean up and exit */
141	cleanup();
142	tst_exit();
143
144}
145
146/* test case function, that runs remap_file_pages */
147static void test_nonlinear(int fd)
148{
149	char *data = NULL;
150	int i, j, repeat = 2;
151
152	for (i = 0; i < cache_pages; i++) {
153		char *page = cache_contents + i * page_sz;
154
155		for (j = 0; j < page_words; j++)
156			page[j] = i;
157	}
158
159	if (write(fd, cache_contents, cache_sz) != cache_sz) {
160		tst_resm(TFAIL,
161			 "Write Error for \"cache_contents\" to \"cache_sz\" of %zu (errno=%d : %s)",
162			 cache_sz, errno, strerror(errno));
163		cleanup(NULL);
164	}
165
166	data = mmap((void *)WINDOW_START,
167		    window_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
168
169	if (data == MAP_FAILED) {
170		tst_resm(TFAIL, "mmap Error, errno=%d : %s", errno,
171			 strerror(errno));
172		cleanup(NULL);
173	}
174
175again:
176	for (i = 0; i < window_pages; i += 2) {
177		char *page = data + i * page_sz;
178
179		if (remap_file_pages(page, page_sz * 2, 0,
180				     (window_pages - i - 2), 0) == -1) {
181			tst_resm(TFAIL | TERRNO,
182				 "remap_file_pages error for page=%p, "
183				 "page_sz=%d, window_pages=%zu",
184				 page, (page_sz * 2), (window_pages - i - 2));
185			cleanup(data);
186		}
187	}
188
189	for (i = 0; i < window_pages; i++) {
190		/*
191		 * Double-check the correctness of the mapping:
192		 */
193		if (i & 1) {
194			if (data[i * page_sz] != window_pages - i) {
195				tst_resm(TFAIL,
196					 "hm, mapped incorrect data, "
197					 "data[%d]=%d, (window_pages-%d)=%zu",
198					 (i * page_sz), data[i * page_sz], i,
199					 (window_pages - i));
200				cleanup(data);
201			}
202		} else {
203			if (data[i * page_sz] != window_pages - i - 2) {
204				tst_resm(TFAIL,
205					 "hm, mapped incorrect data, "
206					 "data[%d]=%d, (window_pages-%d-2)=%zu",
207					 (i * page_sz), data[i * page_sz], i,
208					 (window_pages - i - 2));
209				cleanup(data);
210			}
211		}
212	}
213
214	if (--repeat)
215		goto again;
216
217	munmap(data, window_sz);
218}
219
220/* setup() - performs all ONE TIME setup for this test */
221void setup(void)
222{
223
224	tst_sig(FORK, DEF_HANDLER, cleanup);
225
226	tst_tmpdir();
227
228	TEST_PAUSE;
229
230	/* Get page size */
231	page_sz = getpagesize();
232
233	page_words = page_sz;
234
235	/* Set the cache size */
236	cache_pages = 1024;
237	cache_sz = cache_pages * page_sz;
238	cache_contents = malloc(cache_sz * sizeof(char));
239
240	/* Set the window size */
241	window_pages = 16;
242	window_sz = window_pages * page_sz;
243
244	sprintf(fname, "/dev/shm/cache_%d", getpid());
245
246	if ((fd1 = open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
247		tst_brkm(TBROK, cleanup,
248			 "open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
249			 fname, errno, strerror(errno));
250	}
251
252	if ((fd2 = open("cache", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
253		tst_brkm(TBROK, cleanup,
254			 "open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
255			 "cache", errno, strerror(errno));
256	}
257
258}
259
260/*
261* cleanup() - Performs one time cleanup for this test at
262* completion or premature exit
263*/
264void cleanup(char *data)
265{
266	/* Close the file descriptors */
267	close(fd1);
268	close(fd2);
269
270	if (data)
271		munmap(data, window_sz);
272
273	/* Remove the /dev/shm/cache_<pid> file */
274	unlink(fname);
275
276	tst_rmdir();
277
278}
279