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