1 /* IBM Corporation */ 2 /* 01/03/2003 Port to LTP avenkat (at) us.ibm.com */ 3 /* 06/30/2001 Port to Linux nsharoff (at) us.ibm.com */ 4 5 /* 6 * Copyright (c) International Business Machines Corp., 2003 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 16 * the GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23 /* 24 * Mmap a sparse file and then fiddle with the hole in the middle. 25 * Then check the file contents. 26 * 27 * Usage: mmapstress07 filename holesize e_pageskip sparseoff 28 * EXAMPLE: mmapstress07 myfile 4096 1 4096 29 */ 30 #include <stdio.h> 31 #include <sys/types.h> 32 #include <sys/mman.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <signal.h> 37 #include <errno.h> 38 #include <sys/wait.h> 39 #include "test.h" 40 #define FAILED 0 41 #define PASSED 1 42 43 static char *tmpname; 44 45 #define ERROR(M) (void)fprintf(stderr, "%s: errno = %d: " M "\n", \ 46 argv[0], errno) 47 48 #define CLEANERROR(M) (void)close(rofd); \ 49 (void)close(rwfd); \ 50 (void)unlink(tmpname); \ 51 ERROR(M) 52 53 #define CATCH_SIG(SIG) \ 54 if (sigaction(SIG, &sa, 0) == -1) { \ 55 ERROR("couldn't catch signal " #SIG); \ 56 exit(1); \ 57 } 58 59 extern time_t time(time_t *); 60 extern char *ctime(const time_t *); 61 extern void exit(int); 62 static int checkchars(int fd, char val, int n); 63 64 char *TCID = "mmapstress07"; 65 66 int local_flag = PASSED; 67 int block_number; 68 FILE *temp; 69 int TST_TOTAL = 1; 70 71 int anyfail(); 72 void ok_exit(); 73 74 /*ARGSUSED*/ static 75 void cleanup(int sig) 76 { 77 /* 78 * Don't check error codes - we could be signaled before the file is 79 * created. 80 */ 81 (void)unlink(tmpname); 82 exit(1); 83 } 84 85 int main(int argc, char **argv) 86 { 87 size_t pagesize = (size_t) sysconf(_SC_PAGE_SIZE); 88 caddr_t mapaddr; 89 time_t t; 90 int rofd, rwfd, i; 91 struct sigaction sa; 92 int e_pageskip; 93 #ifdef LARGE_FILE 94 off64_t holesize; 95 off64_t sparseoff; 96 #else /* LARGE_FILE */ 97 off_t holesize; 98 off_t sparseoff; 99 #endif /* LARGE_FILE */ 100 101 (void)time(&t); 102 // (void)printf("%s: Started %s", argv[0], ctime(&t)); 103 /* Test fsync & mmap over a hole in a sparse file & extend fragment */ 104 if (argc < 2 || argc > 5) { 105 fprintf(stderr, 106 "Usage: mmapstress07 filename holesize e_pageskip sparseoff\n"); 107 /***** ** LTP Port 02/01/03 ** **** */ 108 fprintf(stderr, 109 "\t*holesize should be a multiple of pagesize\n"); 110 fprintf(stderr, "\t*e_pageskip should be 1 always \n"); 111 fprintf(stderr, 112 "\t*sparseoff should be a multiple of pagesize\n"); 113 fprintf(stderr, "Example: mmapstress07 myfile 4096 1 8192\n"); 114 /***** ** ****** ***** ***** ** 02/01/03 */ 115 anyfail(); /* LTP Port */ 116 } 117 tst_tmpdir(); 118 tmpname = argv[1]; 119 120 if (argc >= 3) { 121 #ifdef LARGE_FILE 122 holesize = atoll(argv[2]); 123 #else /* LARGE_FILE */ 124 holesize = atoi(argv[2]); 125 #endif /* LARGE_FILE */ 126 } else 127 holesize = pagesize; 128 129 if (argc >= 4) 130 e_pageskip = atoi(argv[3]); 131 else 132 e_pageskip = 1; 133 134 if (argc >= 5) { 135 #ifdef LARGE_FILE 136 sparseoff = atoll(argv[4]); 137 #else /* LARGE_FILE */ 138 sparseoff = atoi(argv[4]); 139 #endif /* LARGE_FILE */ 140 } else 141 sparseoff = pagesize * 2; 142 143 sa.sa_handler = cleanup; 144 sa.sa_flags = 0; 145 if (sigemptyset(&sa.sa_mask)) { 146 ERROR("sigemptyset failed"); 147 return 1; 148 } 149 CATCH_SIG(SIGINT); 150 CATCH_SIG(SIGQUIT); 151 CATCH_SIG(SIGTERM); 152 #ifdef LARGE_FILE 153 if ((rofd = open64(tmpname, O_RDONLY | O_CREAT, 0777)) == -1) { 154 #else /* LARGE_FILE */ 155 if ((rofd = open(tmpname, O_RDONLY | O_CREAT, 0777)) == -1) { 156 #endif /* LARGE_FILE */ 157 ERROR("couldn't reopen rofd for reading"); 158 anyfail(); /* LTP Port */ 159 } 160 #ifdef LARGE_FILE 161 if ((rwfd = open64(tmpname, O_RDWR)) == -1) { 162 #else /* LARGE_FILE */ 163 if ((rwfd = open(tmpname, O_RDWR)) == -1) { 164 #endif /* LARGE_FILE */ 165 CLEANERROR("couldn't reopen rwfd for read/write"); 166 anyfail(); /* LTP Port */ 167 } 168 #ifdef LARGE_FILE 169 if (lseek64(rwfd, sparseoff, SEEK_SET) < 0) { 170 #else /* LARGE_FILE */ 171 if (lseek(rwfd, sparseoff, SEEK_SET) < 0) { 172 #endif /* LARGE_FILE */ 173 perror("lseek"); 174 anyfail(); /* LTP Port */ 175 } 176 /* fill file with junk. */ 177 i = 0; 178 while (i < pagesize && write(rwfd, "a", 1) == 1) 179 i++; 180 if (i != pagesize) { 181 CLEANERROR("couldn't fill first part of file with junk"); 182 anyfail(); /* LTP Port */ 183 } 184 #ifdef LARGE_FILE 185 if (lseek64(rwfd, holesize, SEEK_CUR) == -1) { 186 #else /* LARGE_FILE */ 187 if (lseek(rwfd, holesize, SEEK_CUR) == -1) { 188 #endif /* LARGE_FILE */ 189 CLEANERROR("couldn't create hole in file"); 190 anyfail(); /* LTP Port */ 191 } 192 /* create fragment */ 193 i = 0; 194 while (i < (pagesize >> 1) && write(rwfd, "b", 1) == 1) 195 i++; 196 if (i != (pagesize >> 1)) { 197 CLEANERROR("couldn't fill second part of file with junk"); 198 anyfail(); /* LTP Port */ 199 } 200 /* At this point fd contains 1 page of a's, holesize bytes skipped, 201 * 1/2 page of b's. 202 */ 203 204 #ifdef LARGE_FILE 205 if ((mapaddr = mmap64((caddr_t) 0, pagesize * 2 + holesize, PROT_READ, 206 MAP_SHARED | MAP_FILE, rofd, 207 sparseoff)) == (caddr_t) - 1) { 208 #else /* LARGE_FILE */ 209 if ((mapaddr = mmap((caddr_t) 0, pagesize * 2 + holesize, PROT_READ, 210 MAP_SHARED | MAP_FILE, rofd, 211 sparseoff)) == (caddr_t) - 1) { 212 #endif /* LARGE_FILE */ 213 CLEANERROR("mmap tmp file failed"); 214 anyfail(); /* LTP Port */ 215 } 216 /* fill out remainder of page + one more page to extend mmapped flag */ 217 while (i < 2 * pagesize && write(rwfd, "c", 1) == 1) 218 i++; 219 if (i != 2 * pagesize) { 220 CLEANERROR("couldn't fill second part of file with junk"); 221 anyfail(); /* LTP Port */ 222 } 223 /* fiddle with mmapped hole */ 224 if (*(mapaddr + pagesize + (holesize >> 1)) != 0) { 225 CLEANERROR("hole not filled with 0's"); 226 anyfail(); /* LTP Port */ 227 } 228 #ifdef LARGE_FILE 229 if (lseek64(rwfd, sparseoff + e_pageskip * pagesize, SEEK_SET) == -1) { 230 #else /* LARGE_FILE */ 231 if (lseek(rwfd, sparseoff + e_pageskip * pagesize, SEEK_SET) == -1) { 232 #endif /* LARGE_FILE */ 233 CLEANERROR("couldn't lseek back to put e's in hole"); 234 anyfail(); /*LTP Port */ 235 } 236 i = 0; 237 while (i < pagesize && write(rwfd, "e", 1) == 1) 238 i++; 239 if (i != pagesize) { 240 CLEANERROR("couldn't part of hole with e's"); 241 anyfail(); /*LTP Port */ 242 } 243 if (fsync(rwfd) == -1) { 244 CLEANERROR("fsync failed"); 245 anyfail(); /* LTP Port */ 246 } 247 #ifdef LARGE_FILE 248 if (lseek64(rofd, sparseoff, SEEK_SET) == -1) { 249 #else /* LARGE_FILE */ 250 if (lseek(rofd, sparseoff, SEEK_SET) == -1) { 251 #endif /* LARGE_FILE */ 252 CLEANERROR("couldn't lseek to begining to verify contents"); 253 anyfail(); /* LTP Port */ 254 } 255 if (munmap(mapaddr, holesize + 2 * pagesize) == -1) { 256 CLEANERROR("munmap of tmp file failed"); 257 anyfail(); /* LTP Port */ 258 } 259 /* check file's contents */ 260 if (checkchars(rofd, 'a', pagesize)) { 261 CLEANERROR("first page not filled with a's"); 262 anyfail(); /* LTP Port */ 263 } 264 if (checkchars(rofd, '\0', (e_pageskip - 1) * pagesize)) { 265 CLEANERROR("e_skip not filled with 0's"); 266 anyfail(); /* LTP Port */ 267 } 268 if (checkchars(rofd, 'e', pagesize)) { 269 CLEANERROR("part after first 0's not filled with e's"); 270 anyfail(); /* LTP Port */ 271 } 272 if (checkchars(rofd, '\0', holesize - e_pageskip * pagesize)) { 273 CLEANERROR("second hole section not filled with 0's"); 274 anyfail(); /* LTP Port */ 275 } 276 if (checkchars(rofd, 'b', (pagesize >> 1))) { 277 CLEANERROR("next to last half page not filled with b's"); 278 anyfail(); /* LTP Port */ 279 } 280 if (checkchars(rofd, 'c', pagesize + (pagesize >> 1))) { 281 CLEANERROR("extended fragment not filled with c's"); 282 anyfail(); /* LTP Port */ 283 } 284 if (close(rofd) == -1) { 285 CLEANERROR("second close of rofd failed"); 286 anyfail(); /* LTP Port */ 287 } 288 if (unlink(tmpname) == -1) { 289 CLEANERROR("unlink failed"); 290 anyfail(); /* LTP Port */ 291 } 292 (void)time(&t); 293 // (void)printf("%s: Finished %s", argv[0], ctime(&t)); 294 ok_exit(); 295 tst_exit(); 296 } 297 298 /* checkchars 299 * verrify that the next n characters of file fd are of value val. 300 * 0 = success; -1 = failure 301 */ 302 static int checkchars(int fd, char val, int n) 303 { 304 int i; 305 char buf; 306 307 for (i = 0; i < n && read(fd, &buf, 1) == 1; i++) 308 if (buf != val) 309 return -1; 310 return 0; 311 } 312 313 /***** ** LTP Port ** *****/ 314 int anyfail(void) 315 { 316 tst_brkm(TFAIL, tst_rmdir, "Test failed\n"); 317 } 318 319 void ok_exit(void) 320 { 321 tst_resm(TPASS, "Test passed\n"); 322 tst_rmdir(); 323 tst_exit(); 324 } 325 326 /***** ** ****** ** *****/ 327