1 /* IBM Corporation */ 2 /* 01/02/2003 Port to LTP avenkat (at) us.ibm.com */ 3 /* 06/30/2001 Port to Linux nsharoff (at) us.ibm.com */ 4 /* 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #define _GNU_SOURCE 1 21 #include <stdio.h> 22 #include <fcntl.h> 23 #include <signal.h> 24 #include <sys/mman.h> 25 #include <sys/wait.h> 26 #include <sys/stat.h> 27 #include <unistd.h> 28 #include <stdlib.h> 29 #include <errno.h> 30 #include <sys/types.h> 31 #include <limits.h> 32 /***** LTP Port *****/ 33 #include "test.h" 34 #define FAILED 0 35 #define PASSED 1 36 37 int local_flag = PASSED; 38 char *TCID = "mmapstress10"; 39 FILE *temp; 40 int TST_TOTAL = 1; 41 42 int anyfail(); 43 void ok_exit(); 44 /***** ** ** *****/ 45 46 /* 47 * This test stresses mmaps, specifically the code dealing with 48 * mapping of fragments. It forks a specified number of children, 49 * all of whom mmap the same file, make a given number of accesses 50 * to random pages in the map (reading & writing and comparing data). 51 * Then the child exits and the parent forks another to take its place. 52 * Each time a child is forked, it stats the file and maps the full 53 * length of the file. Meanwhile, another child is forked which 54 * continually writes to the file. It loops writing some bytes (default 55 * 20), then sleeps some seconds (default 1). This causes the file 56 * to gradually grow, crossing fragment boundaries, etc. 57 * Then it forks yet *another* child who maps the file in extend 58 * mode, just to check out interaction. (Because this will cause 59 * 0 padding at end of file, children can't test as exactly as in tmmap - 60 * have to check for zero or pattern...) 61 * 62 * This program continues to run until it either receives a SIGINT, 63 * or times out (if a timeout value is specified). When either of 64 * these things happens, it cleans up its kids, then checks the 65 * file to make sure it has the correct data. 66 * 67 * usage: 68 * mmapstress10 -p nprocs [-t minutes -w nbytes -s secs -f filesize 69 * -S sparseoffset -r -o -m -l -d] 70 * where: 71 * -p nprocs - specifies the number of mapping children 72 * to create. (nprocs + 1 children actually 73 * get created, since one is the writer child) 74 * -t minutes - specifies minutes to run. If not specified, 75 * default is to run forever until a SIGINT 76 * is received. 77 * -w nbytes - specifies number of bytes for writer process 78 * to write at a time (i.e. between sleeps). 79 * defaults to GROWSIZE bytes. 80 * -s secs - specifies number of seconds for writer process 81 * to sleep between writes. Defaults to 82 * SLEEPTIME seconds. 83 * -f filesize - initial filesize (defaults to FILESIZE) 84 * -S sparseoffset - when non-zero, causes a sparse area to 85 * be left before the data, meaning that the 86 * actual initial file size is sparseoffset + 87 * filesize. Useful for testing large files. 88 * (default is 0). 89 * -r - randomize number of pages map children check. 90 * (random % MAXLOOPS). If not specified, each 91 * child checks MAXLOOPS pages. 92 * -o - randomize offset of file to map. (default is 0) 93 * -m - do random msync/fsyncs as well 94 * -l - if set, the output file is not removed on 95 * program exit. 96 * -d - enable debug outputd 97 * 98 * Compile with -DLARGE_FILE to enable file sizes > 2 GB. 99 */ 100 101 #define MAXLOOPS 500 /* max pages for map children to write */ 102 #define GROWSIZE 20 /* # bytes to write per write call */ 103 #define SLEEPTIME 1 /* # secs to sleep between writes */ 104 #define FILESIZE 4096 /* initial filesize set up by parent */ 105 #ifdef roundup 106 #undef roundup 107 #endif 108 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 109 #define min(x, y) (((x) < (y)) ? (x) : (y)) 110 111 #define SIZE_MAX UINT_MAX 112 113 extern time_t time(time_t *); 114 extern char *ctime(const time_t *); 115 extern void *malloc(size_t); 116 extern void exit(int); 117 extern long lrand48(void); 118 extern void srand(unsigned); 119 extern void srand48(long); 120 extern int rand(void); 121 extern int atoi(const char *); 122 123 char *usage = 124 "-p nprocs [-t minutes -w nbytes -s secs -f fsize -S sparseoffset -r -o -m -l -d]"; 125 126 typedef unsigned char uchar_t; //Ananda 12/17/02 127 128 void child_mapper(char *file, unsigned procno, unsigned nprocs); 129 void child_writer(char *file, uchar_t * buf); 130 int fileokay(char *file, uchar_t * expbuf); 131 unsigned int initrand(void); 132 void finish(int sig); 133 void clean_up_file(int sig); 134 int finished = 0; 135 int leavefile = 0; 136 137 int debug = 0; 138 int growsize = GROWSIZE; 139 int sleeptime = SLEEPTIME; 140 #ifdef LARGE_FILE 141 off64_t filesize = FILESIZE; 142 off64_t sparseoffset = 0; 143 #else /* LARGE_FILE */ 144 off_t filesize = FILESIZE; 145 off_t sparseoffset = 0; 146 #endif /* LARGE_FILE */ 147 unsigned randloops = 0; 148 unsigned dosync = 0; 149 unsigned do_offset = 0; 150 unsigned pattern = 0; 151 static const char *filename = "mmapstress10.out"; 152 153 void clean_mapper(int sig); 154 void clean_writer(int sig); 155 156 int fd_mapper = 0; 157 caddr_t maddr_mapper; 158 size_t mapsize_mapper; 159 160 int fd_writer = 0; 161 162 int main(int argc, char *argv[]) 163 { 164 char *progname; 165 int fd; 166 int c; 167 extern char *optarg; 168 unsigned nprocs = 0; 169 unsigned procno; 170 pid_t *pidarray = NULL; 171 pid_t pid; 172 pid_t wr_pid = 0; 173 uchar_t *buf = NULL; 174 unsigned int seed; 175 int pagesize = sysconf(_SC_PAGE_SIZE); 176 float alarmtime = 0; 177 struct sigaction sa; 178 unsigned i; 179 int write_cnt; 180 uchar_t data; 181 int no_prob = 0; 182 int wait_stat; 183 time_t t; 184 #ifdef LARGE_FILE 185 off64_t bytes_left; 186 #else /* LARGE_FILE */ 187 off_t bytes_left; 188 #endif /* LARGE_FILE */ 189 190 progname = *argv; 191 tst_tmpdir(); 192 if (argc < 2) { 193 (void)fprintf(stderr, "usage: %s %s\n", progname, usage); 194 exit(1); 195 } 196 197 while ((c = getopt(argc, argv, "S:omdlrf:p:t:w:s:")) != -1) { 198 switch (c) { 199 case 'd': 200 debug = 1; 201 break; 202 case 't': 203 alarmtime = atof(optarg) * 60; 204 break; 205 case 'p': 206 nprocs = atoi(optarg); 207 break; 208 case 'l': 209 leavefile = 1; 210 break; 211 case 's': 212 sleeptime = atoi(optarg); 213 if (sleeptime < 0) { 214 (void)fprintf(stderr, "error: negative " 215 "sleeptime\n"); 216 anyfail(); 217 } 218 break; 219 case 'w': 220 growsize = atoi(optarg); 221 if (growsize < 0) { 222 (void)fprintf(stderr, "error: negative write " 223 "size\n"); 224 anyfail(); 225 } 226 break; 227 case 'f': 228 #ifdef LARGE_FILE 229 filesize = atoll(optarg); 230 #else /* LARGE_FILE */ 231 filesize = atoi(optarg); 232 #endif /* LARGE_FILE */ 233 if (filesize < 0) { 234 (void)fprintf(stderr, "error: negative " 235 "filesize\n"); 236 anyfail(); 237 } 238 break; 239 case 'r': 240 randloops = 1; 241 break; 242 case 'm': 243 dosync = 1; 244 break; 245 case 'o': 246 do_offset = 1; 247 break; 248 case 'S': 249 #ifdef LARGE_FILE 250 sparseoffset = atoll(optarg); 251 #else /* LARGE_FILE */ 252 sparseoffset = atoi(optarg); 253 #endif /* LARGE_FILE */ 254 if (sparseoffset % pagesize != 0) { 255 fprintf(stderr, 256 "sparseoffset must be pagesize multiple\n"); 257 anyfail(); 258 } 259 break; 260 default: 261 (void)fprintf(stderr, "usage: %s %s\n", progname, 262 usage); 263 anyfail(); 264 } 265 } 266 267 if (nprocs > 255) { 268 (void)fprintf(stderr, "invalid nprocs %d - (range 0-255)\n", 269 nprocs); 270 anyfail(); 271 } 272 (void)time(&t); 273 274 seed = initrand(); 275 pattern = seed & 0xff; 276 277 if (debug) { 278 #ifdef LARGE_FILE 279 (void)printf("creating file <%s> with %Ld bytes, pattern %d\n", 280 filename, filesize, pattern); 281 #else /* LARGE_FILE */ 282 (void)printf("creating file <%s> with %ld bytes, pattern %d\n", 283 filename, filesize, pattern); 284 #endif /* LARGE_FILE */ 285 if (alarmtime) 286 (void)printf("running for %f minutes\n", 287 alarmtime / 60); 288 else 289 (void)printf("running with no time limit\n"); 290 } 291 292 /* 293 * Plan for death by signal. User may have specified 294 * a time limit, in which case set an alarm and catch SIGALRM. 295 * Also catch and cleanup with SIGINT, SIGQUIT, and SIGTERM. 296 */ 297 sa.sa_handler = finish; 298 sa.sa_flags = 0; 299 if (sigemptyset(&sa.sa_mask)) { 300 perror("sigempty error"); 301 goto cleanup; 302 } 303 304 if (sigaction(SIGINT, &sa, 0) == -1) { 305 perror("sigaction error SIGINT"); 306 goto cleanup; 307 } 308 if (alarmtime) { 309 if (sigaction(SIGALRM, &sa, 0) == -1) { 310 perror("sigaction error"); 311 goto cleanup; 312 } 313 (void)alarm(alarmtime); 314 } 315 /* If we get a SIGQUIT or SIGTERM, clean up and exit immediately. */ 316 sa.sa_handler = clean_up_file; 317 if (sigaction(SIGQUIT, &sa, 0) == -1) { 318 perror("sigaction error SIGQUIT"); 319 goto cleanup; 320 } 321 if (sigaction(SIGTERM, &sa, 0) == -1) { 322 perror("sigaction error SIGTERM"); 323 goto cleanup; 324 } 325 #ifdef LARGE_FILE 326 if ((fd = open64(filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) { 327 #else /* LARGE_FILE */ 328 if ((fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) { 329 #endif /* LARGE_FILE */ 330 perror("open error"); 331 anyfail(); 332 } 333 334 if ((buf = malloc(pagesize + growsize)) == NULL 335 || (pidarray = malloc(nprocs * sizeof(pid_t))) == NULL) { 336 perror("malloc error"); 337 anyfail(); 338 } 339 340 for (i = 0; i < nprocs; i++) 341 *(pidarray + i) = 0; 342 343 for (i = 0, data = 0; i < pagesize; i++) { 344 *(buf + i) = (data + pattern) & 0xff; 345 if (++data == nprocs) 346 data = 0; 347 } 348 for (data = 0; i < pagesize + growsize; i++) { 349 *(buf + i) = (data + pattern) & 0xff; 350 if (++data == nprocs) 351 data = 0; 352 } 353 354 #ifdef LARGE_FILE 355 if (lseek64(fd, sparseoffset, SEEK_SET) < 0) { 356 #else /* LARGE_FILE */ 357 if (lseek(fd, sparseoffset, SEEK_SET) < 0) { 358 #endif /* LARGE_FILE */ 359 perror("lseek"); 360 anyfail(); 361 } 362 363 for (bytes_left = filesize; bytes_left; bytes_left -= c) { 364 write_cnt = min(pagesize, bytes_left); 365 if ((c = write(fd, (char *)buf, write_cnt)) != write_cnt) { 366 if (c == -1) { 367 perror("write error"); 368 } else { 369 (void)fprintf(stderr, "write: wrote %d of %d " 370 "bytes\n", c, write_cnt); 371 } 372 (void)close(fd); 373 (void)unlink(filename); 374 anyfail(); 375 } 376 } 377 378 (void)close(fd); 379 380 /* 381 * Fork off mmap children. 382 */ 383 for (procno = 0; procno < nprocs; procno++) { 384 switch (pid = fork()) { 385 386 case -1: 387 perror("fork error"); 388 goto cleanup; 389 390 case 0: 391 child_mapper(filename, procno, nprocs); 392 exit(0); 393 394 default: 395 pidarray[procno] = pid; 396 } 397 } 398 399 /* 400 * Now fork off an additional process to continually 401 * write to (and grow) the file. 402 */ 403 if ((wr_pid = fork()) == -1) { 404 perror("fork error"); 405 goto cleanup; 406 } else if (wr_pid == 0) { /* child */ 407 child_writer(filename, buf); 408 exit(0); 409 } 410 411 /* 412 * Now wait for children and refork them as needed. 413 */ 414 415 while (!finished) { 416 pid = wait(&wait_stat); 417 /* 418 * Block signals while processing child exit. 419 */ 420 421 if (sighold(SIGALRM) || sighold(SIGINT)) { 422 perror("sighold error"); 423 goto cleanup; 424 } 425 426 if (pid != -1) { 427 /* 428 * Check exit status, then refork with the 429 * appropriate procno. 430 */ 431 if (!WIFEXITED(wait_stat) 432 || WEXITSTATUS(wait_stat) != 0) { 433 (void)fprintf(stderr, "child exit with err " 434 "<x%x>\n", wait_stat); 435 goto cleanup; 436 } 437 for (i = 0; i < nprocs; i++) 438 if (pid == pidarray[i]) 439 break; 440 if (i == nprocs) { 441 if (pid == wr_pid) { 442 (void)fprintf(stderr, 443 "writer child unexpected exit <x%x>\n", 444 wait_stat); 445 wr_pid = 0; 446 } else 447 (void)fprintf(stderr, "unknown child " 448 "pid %d, <x%x>\n", 449 pid, wait_stat); 450 goto cleanup; 451 } 452 453 if ((pid = fork()) == -1) { 454 perror("fork error"); 455 pidarray[i] = 0; 456 goto cleanup; 457 } else if (pid == 0) { /* child */ 458 child_mapper(filename, i, nprocs); 459 exit(0); 460 } else 461 pidarray[i] = pid; 462 } else { 463 /* 464 * wait returned an error. If EINTR, then 465 * normal finish, else it's an unexpected 466 * error... 467 */ 468 if (errno != EINTR || !finished) { 469 perror("unexpected wait error"); 470 goto cleanup; 471 } 472 } 473 if (sigrelse(SIGALRM) || sigrelse(SIGINT)) { 474 perror("sigrelse error"); 475 goto cleanup; 476 } 477 } 478 479 /* 480 * Finished! Check the file for sanity, then kill all 481 * the children and done!. 482 */ 483 484 (void)alarm(0); 485 no_prob = 1; 486 487 cleanup: 488 for (i = 0; i < nprocs; i++) 489 (void)kill(pidarray[i], SIGUSR1); 490 (void)kill(wr_pid, SIGUSR1); 491 492 while (wait(&wait_stat) != -1 || errno != ECHILD) 493 continue; 494 495 if (no_prob) { /* only check file if no errors */ 496 if (!fileokay(filename, buf)) { 497 (void)fprintf(stderr, "file data incorrect!\n"); 498 (void)printf(" leaving file <%s>\n", filename); 499 anyfail(); 500 501 } else { 502 (void)printf("file data okay\n"); 503 if (!leavefile) 504 (void)unlink(filename); 505 } 506 } else 507 (void)printf(" leaving file <%s>\n", filename); 508 509 (void)time(&t); 510 // (void)printf("%s: Finished %s", argv[0], ctime(&t)); LTP Port 511 ok_exit(); 512 tst_exit(); 513 } 514 515 /* 516 * Child process that reads/writes map. The child stats the file 517 * to determine the size, maps the size of the file, then reads/writes 518 * its own locations on random pages of the map (its locations being 519 * determined based on nprocs & procno). After a specific number of 520 * iterations, it exits. 521 */ 522 void child_mapper(char *file, unsigned procno, unsigned nprocs) 523 { 524 #ifdef LARGE_FILE 525 struct stat64 statbuf; 526 off64_t filesize; 527 off64_t offset; 528 #else /* LARGE_FILE */ 529 struct stat statbuf; 530 off_t filesize; 531 off_t offset; 532 #endif /* LARGE_FILE */ 533 size_t validsize; 534 caddr_t paddr; 535 int pagesize = sysconf(_SC_PAGE_SIZE); 536 unsigned randpage; 537 unsigned int seed; 538 unsigned loopcnt; 539 unsigned nloops; 540 unsigned mappages; 541 unsigned mapflags; 542 unsigned i; 543 struct sigaction sa_mapper; 544 545 mapflags = MAP_SHARED; 546 547 seed = initrand(); /* initialize random seed */ 548 549 sa_mapper.sa_handler = clean_mapper; 550 sa_mapper.sa_flags = 0; 551 if (sigemptyset(&sa_mapper.sa_mask)) { 552 perror("sigempty error"); 553 anyfail(); 554 } 555 556 if (sigaction(SIGUSR1, &sa_mapper, 0) == -1) { 557 perror("sigaction error SIGUSR1"); 558 anyfail(); 559 } 560 #ifdef LARGE_FILE 561 if ((fd_mapper = open64(file, O_RDWR)) == -1) { 562 #else /* LARGE_FILE */ 563 if ((fd_mapper = open(file, O_RDWR)) == -1) { 564 #endif /* LARGE_FILE */ 565 perror("open error"); 566 anyfail(); 567 } 568 #ifdef LARGE_FILE 569 if (fstat64(fd_mapper, &statbuf) == -1) { 570 #else /* LARGE_FILE */ 571 if (fstat(fd_mapper, &statbuf) == -1) { 572 #endif /* LARGE_FILE */ 573 perror("stat error"); 574 anyfail(); 575 } 576 filesize = statbuf.st_size; 577 578 if (statbuf.st_size - sparseoffset > SIZE_MAX) { 579 fprintf(stderr, "size_t overflow when setting up map\n"); 580 anyfail(); 581 } 582 mapsize_mapper = (size_t) (statbuf.st_size - sparseoffset); 583 mappages = roundup(mapsize_mapper, pagesize) / pagesize; 584 offset = sparseoffset; 585 if (do_offset) { 586 int pageoffset = lrand48() % mappages; 587 int byteoffset = pageoffset * pagesize; 588 offset += byteoffset; 589 mapsize_mapper -= byteoffset; 590 mappages -= pageoffset; 591 } 592 #ifdef LARGE_FILE 593 if ((maddr_mapper = mmap64(0, mapsize_mapper, PROT_READ | PROT_WRITE, 594 mapflags, fd_mapper, 595 offset)) == (caddr_t) - 1) { 596 #else /* LARGE_FILE */ 597 if ((maddr_mapper = mmap(0, mapsize_mapper, PROT_READ | PROT_WRITE, 598 mapflags, fd_mapper, 599 offset)) == (caddr_t) - 1) { 600 #endif /* LARGE_FILE */ 601 perror("mmap error"); 602 anyfail(); 603 } 604 605 (void)close(fd_mapper); 606 607 nloops = (randloops) ? (lrand48() % MAXLOOPS) : MAXLOOPS; 608 609 if (debug) { 610 #ifdef LARGE_FILE 611 (void)printf("child %d (pid %ld): seed %d, fsize %Ld, " 612 "mapsize %d, off %Ld, loop %d\n", 613 procno, getpid(), seed, filesize, mapsize_mapper, 614 offset / pagesize, nloops); 615 #else /* LARGE_FILE */ 616 (void)printf("child %d (pid %d): seed %d, fsize %ld, " 617 "mapsize %ld, off %ld, loop %d\n", 618 procno, getpid(), seed, filesize, 619 (long)mapsize_mapper, offset / pagesize, nloops); 620 #endif /* LARGE_FILE */ 621 } 622 623 /* 624 * Now loop read/writing random pages. 625 */ 626 for (loopcnt = 0; loopcnt < nloops; loopcnt++) { 627 randpage = lrand48() % mappages; 628 paddr = maddr_mapper + (randpage * pagesize); /* page address */ 629 630 if (randpage < mappages - 1 || !(mapsize_mapper % pagesize)) 631 validsize = pagesize; 632 else 633 validsize = mapsize_mapper % pagesize; 634 635 /* 636 * Because one child is mapping file in extend mode, 637 * it may be padded with zeros at end. So we can't 638 * do an exact check -- accept known pattern OR zeros. 639 */ 640 for (i = procno; i < validsize; i += nprocs) { 641 if (*((unsigned char *)(paddr + i)) 642 != ((procno + pattern) & 0xff) 643 && *((unsigned char *)(paddr + i)) != 0) { 644 (void)fprintf(stderr, "child %d: invalid data " 645 "<x%x>", procno, 646 *((unsigned char *)(paddr + i))); 647 (void)fprintf(stderr, 648 " at pg %d off %d, exp " 649 "<x%x>\n", randpage, i, 650 (procno + pattern) & 0xff); 651 anyfail(); 652 } 653 /* 654 * Now write it. 655 */ 656 657 *(paddr + i) = (procno + pattern) & 0xff; 658 } 659 } 660 if (dosync) { 661 /* 662 * Exercise msync() as well! 663 */ 664 randpage = lrand48() % mappages; 665 paddr = maddr_mapper + (randpage * pagesize); /* page address */ 666 if (msync(paddr, (mappages - randpage) * pagesize, 667 MS_SYNC) == -1) { 668 perror("msync error"); 669 anyfail(); 670 } 671 } 672 if (munmap(maddr_mapper, mapsize_mapper) == -1) { 673 perror("munmap failed"); 674 anyfail(); 675 } 676 exit(0); 677 } 678 679 /* 680 * child_writer 681 * The child process that continually (and slowly!!) grows 682 * the file. The purpose of this is to exercise the code 683 * supporting mapping of fragments. The map children are 684 * constantly reforking and will pick up the map changes, etc. 685 * This process executes until signalled (i.e. has no exit!) 686 * unless error. 687 */ 688 void child_writer(char *file, uchar_t * buf) 689 { /* buf already set up in main */ 690 struct sigaction sa_writer; 691 692 sa_writer.sa_handler = clean_writer; 693 sa_writer.sa_flags = 0; 694 if (sigemptyset(&sa_writer.sa_mask)) { 695 perror("sigempty error"); 696 anyfail(); 697 } 698 699 if (sigaction(SIGUSR1, &sa_writer, 0) == -1) { 700 perror("sigaction error SIGUSR1"); 701 anyfail(); 702 } 703 #ifdef LARGE_FILE 704 struct stat64 statbuf; 705 off64_t off; 706 #else /* LARGE_FILE */ 707 struct stat statbuf; 708 off_t off; 709 #endif /* LARGE_FILE */ 710 int pagesize = sysconf(_SC_PAGE_SIZE); 711 uchar_t *p; 712 int cnt; 713 714 #ifdef LARGE_FILE 715 if ((fd_writer = open64(file, O_RDWR)) == -1) { 716 #else /* LARGE_FILE */ 717 if ((fd_writer = open(file, O_RDWR)) == -1) { 718 #endif /* LARGE_FILE */ 719 perror("open error"); 720 anyfail(); 721 } 722 #ifdef LARGE_FILE 723 if ((off = lseek64(fd_writer, 0, SEEK_END)) == -1) { 724 #else /* LARGE_FILE */ 725 if ((off = lseek(fd_writer, 0, SEEK_END)) == -1) { 726 #endif /* LARGE_FILE */ 727 perror("lseek error"); 728 anyfail(); 729 } 730 731 for (;;) { 732 #ifdef LARGE_FILE 733 if (fstat64(fd_writer, &statbuf) == -1) { 734 #else /* LARGE_FILE */ 735 if (fstat(fd_writer, &statbuf) == -1) { 736 #endif /* LARGE_FILE */ 737 perror("fstat error"); 738 anyfail(); 739 } 740 #ifdef LARGE_FILE 741 if (debug) 742 (void)printf("writer %d bytes at off %Ld, size %Ld\n", 743 growsize, off, statbuf.st_size); 744 #else /* LARGE_FILE */ 745 if (debug) 746 (void)printf("writer %d bytes at off %ld, size %ld\n", 747 growsize, off, statbuf.st_size); 748 #endif /* LARGE_FILE */ 749 750 /* 751 * Write some number of bytes, then sleep some 752 * number of seconds... 753 * Need to keep track of our offset so write the 754 * right bytes. 755 */ 756 757 p = buf + (off % pagesize); 758 759 if ((cnt = write(fd_writer, p, growsize)) != growsize) { 760 if (cnt == -1) 761 perror("write error"); 762 else 763 (void)fprintf(stderr, "wrote %d of %d bytes\n", 764 cnt, growsize); 765 anyfail(); 766 } 767 768 off += growsize; 769 770 (void)sleep(sleeptime); 771 if (dosync) { 772 if (fsync(fd_writer) == -1) { 773 perror("fsync error"); 774 anyfail(); 775 } 776 } 777 } 778 close(fd_writer); 779 } 780 781 /* 782 * Make sure file has all the correct data. 783 784 */ 785 int fileokay(char *file, uchar_t * expbuf) 786 { 787 #ifdef LARGE_FILE 788 struct stat64 statbuf; 789 #else /* LARGE_FILE */ 790 struct stat statbuf; 791 #endif /* LARGE_FILE */ 792 size_t mapsize; 793 uchar_t *readbuf; 794 unsigned mappages; 795 unsigned pagesize = sysconf(_SC_PAGE_SIZE); 796 int fd; 797 int cnt; 798 unsigned i, j; 799 800 #ifdef LARGE_FILE 801 if ((fd = open64(file, O_RDONLY)) == -1) { 802 #else /* LARGE_FILE */ 803 if ((fd = open(file, O_RDONLY)) == -1) { 804 #endif /* LARGE_FILE */ 805 perror("open error"); 806 anyfail(); 807 } 808 #ifdef LARGE_FILE 809 if (fstat64(fd, &statbuf) == -1) { 810 #else /* LARGE_FILE */ 811 if (fstat(fd, &statbuf) == -1) { 812 #endif /* LARGE_FILE */ 813 perror("stat error"); 814 anyfail(); 815 } 816 #ifdef LARGE_FILE 817 if (lseek64(fd, sparseoffset, SEEK_SET) < 0) { 818 #else /* LARGE_FILE */ 819 if (lseek(fd, sparseoffset, SEEK_SET) < 0) { 820 #endif /* LARGE_FILE */ 821 perror("lseek"); 822 exit(1); 823 } 824 825 readbuf = malloc(pagesize); 826 827 if (statbuf.st_size - sparseoffset > SIZE_MAX) { 828 fprintf(stderr, "size_t overflow when setting up map\n"); 829 exit(1); 830 } 831 mapsize = (size_t) (statbuf.st_size - sparseoffset); 832 mappages = roundup(mapsize, pagesize) / pagesize; 833 834 for (i = 0; i < mappages; i++) { 835 cnt = read(fd, (char *)readbuf, pagesize); 836 if (cnt == -1) { 837 perror("read error"); 838 close(fd); 839 return 0; 840 } else if (cnt != pagesize) { 841 /* 842 * Okay if at last page in file... 843 */ 844 if ((i * pagesize) + cnt != mapsize) { 845 (void)fprintf(stderr, "read %d of %ld bytes\n", 846 (i * pagesize) + cnt, 847 (long)mapsize); 848 close(fd); 849 return 0; 850 } 851 } 852 /* 853 * Compare read bytes of data. 854 * May have zeros from map extend... 855 */ 856 for (j = 0; j < cnt; j++) { 857 if (expbuf[j] != readbuf[j] && readbuf[j] != 0) { 858 (void)fprintf(stderr, 859 "read bad data: exp %c got %c", 860 expbuf[j], readbuf[j]); 861 #ifdef LARGE_FILE 862 (void)fprintf(stderr, ", pg %d off %d, " 863 "(fsize %Ld)\n", i, j, 864 statbuf.st_size); 865 #else /* LARGE_FILE */ 866 (void)fprintf(stderr, ", pg %d off %d, " 867 "(fsize %ld)\n", i, j, 868 statbuf.st_size); 869 #endif /* LARGE_FILE */ 870 close(fd); 871 return 0; 872 } 873 } 874 } 875 876 close(fd); 877 return 1; 878 } 879 880 /*ARGSUSED*/ void finish(int sig) 881 { 882 finished++; 883 /* finish nicely and check the file contents */ 884 } 885 886 /*ARGSUSED*/ void clean_up_file(int sig) 887 { 888 if (!leavefile) 889 (void)unlink(filename); 890 exit(1); 891 } 892 893 void clean_mapper(int sig) 894 { 895 if (fd_mapper) 896 close(fd_mapper); 897 munmap(maddr_mapper, mapsize_mapper); 898 exit(0); 899 } 900 901 void clean_writer(int sig) 902 { 903 if (fd_writer) 904 close(fd_writer); 905 exit(0); 906 } 907 908 unsigned int initrand(void) 909 { 910 unsigned int seed; 911 912 /* 913 * Initialize random seed... Got this from a test written 914 * by scooter: 915 * Use srand/rand to diffuse the information from the 916 * time and pid. If you start several processes, then 917 * the time and pid information don't provide much 918 * variation. 919 */ 920 srand((unsigned int)getpid()); 921 seed = rand(); 922 srand((unsigned int)time(NULL)); 923 seed = (seed ^ rand()) % 100000; 924 srand48((long int)seed); 925 return (seed); 926 } 927 928 /***** LTP Port *****/ 929 void ok_exit(void) 930 { 931 tst_resm(TPASS, "Test passed\n"); 932 tst_rmdir(); 933 tst_exit(); 934 } 935 936 int anyfail(void) 937 { 938 tst_brkm(TFAIL, tst_rmdir, "Test failed\n"); 939 } 940 941 /***** ** ** *****/ 942