1/* IBM Corporation */ 2/* 01/03/2003 Port to LTP avenkat@us.ibm.com */ 3/* 06/30/2001 Port to Linux nsharoff@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 43static 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 59extern time_t time(time_t *); 60extern char *ctime(const time_t *); 61extern void exit(int); 62static int checkchars(int fd, char val, int n); 63 64char *TCID = "mmapstress07"; 65 66int local_flag = PASSED; 67int block_number; 68FILE *temp; 69int TST_TOTAL = 1; 70 71int anyfail(); 72void ok_exit(); 73 74 /*ARGSUSED*/ static 75void 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 85int 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 */ 302static 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 ** *****/ 314int anyfail(void) 315{ 316 tst_brkm(TFAIL, tst_rmdir, "Test failed\n"); 317} 318 319void ok_exit(void) 320{ 321 tst_resm(TPASS, "Test passed\n"); 322 tst_rmdir(); 323 tst_exit(); 324} 325 326/***** ** ****** ** *****/ 327