Home | History | Annotate | Download | only in remap_file_pages
      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 (at) elte.hu> wrote this test case
     65  *                - Nick Piggin, <nickpiggin (at) yahoo.com.au> did the following cleanup
     66  *
     67  *     11/10/2007 - Port to LTP format by Subrata Modak, <subrata (at) linux.vnet.ibm.com>
     68  *                  and Ricardo Salveti de Araujo, <rsalveti (at) linux.vnet.ibm.com>
     69  *     25/02/2008 - Renaud Lottiaux, <Renaud.Lottiaux (at) 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 
    112 int 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 */
    147 static 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 
    175 again:
    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 */
    221 void 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 */
    264 void 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