xref: /aosp_15_r20/external/ltp/testcases/kernel/mem/mmapstress/mmapstress10.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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