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 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