Home | History | Annotate | Download | only in remap_file_pages
      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 (at) gmail.com>
     65  *
     66  *     19/10/2007 - Created by Ricardo Salveti de Araujo, <rsalvetidev (at) 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 <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 
    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  */
    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  */
    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  */
    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  */
    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  */
    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 */
    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