1/* IBM Corporation */
2/* 01/02/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 * weave:
25 *	Mmap parts of a file, and then write to the file causing single
26 *	write requests to jump back and forth between mmaped io and regular io.
27 *
28 *	Usage: weave filename startoffset. pageoffset = 4096.
29 *
30 *	startoffset specifies a byte count in the file at which to begin
31 *	the test.  When this value is non-zero, a sparse file is created.
32 *	This is useful for testing with large files.
33 *
34 *  Compile with -DLARGE_FILE to enable file sizes > 2 GB.
35 */
36
37#include <sys/types.h>
38#include <sys/mman.h>
39#include <unistd.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <signal.h>
43#include <stdio.h>
44#include <stdlib.h>
45/*****	LTP Port	*****/
46#include "test.h"
47#define FAILED 0
48#define PASSED 1
49/*****	**	**	*****/
50
51#define CLEAN	(void)close(rofd); \
52		(void)close(rwfd); \
53		(void)unlink(filename);
54#define ERROR(M)	(void)fprintf(stderr, "%s:  errno = %d; " M "\n", \
55				argv[0], errno)
56#define CLEANERROR(M)	CLEAN; ERROR(M)
57#define CATCH_SIG(SIG) \
58        if (sigaction(SIG, &sa, 0) == -1) { \
59                ERROR("couldn't catch signal " #SIG); \
60                exit(1); \
61        }
62
63static char *filename;
64
65/*****	LTP Port	*****/
66char *TCID = "mmapstress04";	//weave
67int local_flag = PASSED;
68int block_number;
69FILE *temp;
70int TST_TOTAL = 1;
71
72int anyfail();
73int blenter();
74int blexit();
75int instress();
76void setup();
77void terror();
78void fail_exit();
79void ok_exit();
80/*****	**	**	*****/
81
82extern time_t time(time_t *);
83extern char *ctime(const time_t *);
84extern void exit(int);
85static int rofd, rwfd;
86
87 /*ARGSUSED*/ static
88void cleanup(int sig)
89{
90	/*
91	 * Don't check error codes - we could be signaled before the file is
92	 * created.
93	 */
94	(void)close(rofd);
95	(void)close(rwfd);
96	(void)unlink(filename);
97	exit(1);
98}
99
100int main(int argc, char *argv[])
101{
102	char *buf;
103	size_t pagesize = (size_t) sysconf(_SC_PAGE_SIZE);
104	caddr_t mmapaddr;
105	time_t t;
106	int i, j;
107	struct sigaction sa;
108#ifdef LARGE_FILE
109	off64_t startoffset;
110	off64_t seekoff;
111	off64_t mapoff;
112#else /* LARGE_FILE */
113	off_t startoffset;
114	off_t seekoff;
115	off_t mapoff;
116#endif /* LARGE_FILE */
117
118	if (argc < 2 || argc > 3) {
119		(void)fprintf(stderr, "Usage: %s filename startoffset\n",
120			      argv[0]);
121		return 1;
122	}
123	filename = argv[1];
124
125	if (argc >= 3) {
126#ifdef LARGE_FILE
127		startoffset = atoll(argv[2]);
128#else /* LARGE_FILE */
129		startoffset = atoi(argv[2]);
130#endif /* LARGE_FILE */
131	} else
132		startoffset = pagesize;
133
134	if (startoffset % pagesize != 0) {
135		fprintf(stderr, "pagesize=%ld\n", (long)pagesize);
136		fprintf(stderr, "startoffset must be a pagesize multiple\n");
137		anyfail();	//LTP Port
138	}
139	(void)time(&t);
140//      (void)printf("%s: Started %s", argv[0], ctime(&t));
141	if ((buf = sbrk(6 * pagesize)) == (char *)-1) {
142		ERROR("couldn't allocate buf");
143		anyfail();	//LTP Port
144	}
145	if (sbrk(pagesize - ((ulong) sbrk(0) & (pagesize - 1))) == (char *)-1) {
146		ERROR("couldn't round up brk");
147		anyfail();	//LTP Port
148	}
149	if ((mmapaddr = (caddr_t) sbrk(0)) == (caddr_t) - 1) {
150		ERROR("couldn't find top of brk");
151		anyfail();	//LTP Port
152	}
153	sa.sa_handler = cleanup;
154	sa.sa_flags = 0;
155	if (sigemptyset(&sa.sa_mask)) {
156		ERROR("sigemptyset failed");
157		anyfail();	//LTP Port
158	}
159	CATCH_SIG(SIGINT);
160	CATCH_SIG(SIGQUIT);
161	CATCH_SIG(SIGTERM);
162	tst_tmpdir();
163#ifdef LARGE_FILE
164	if ((rofd = open64(filename, O_RDONLY | O_CREAT, 0777)) == -1) {
165#else /* LARGE_FILE */
166	if ((rofd = open(filename, O_RDONLY | O_CREAT, 0777)) == -1) {
167#endif /* LARGE_FILE */
168		ERROR("read only open failed");
169		anyfail();	//LTP Port
170	}
171#ifdef LARGE_FILE
172	if ((rwfd = open64(filename, O_RDWR)) == -1) {
173#else /* LARGE_FILE */
174	if ((rwfd = open(filename, O_RDWR)) == -1) {
175#endif /* LARGE_FILE */
176		(void)close(rofd);
177		(void)unlink(filename);
178		ERROR("read/write open failed");
179		anyfail();	//LTP Port
180	}
181#ifdef LARGE_FILE
182	seekoff = startoffset + (off64_t) 64 *(off64_t) 6 *(off64_t) pagesize;
183	if (lseek64(rwfd, seekoff, SEEK_SET) != seekoff) {
184#else /* LARGE_FILE */
185	seekoff = startoffset + (off_t) 64 *(off_t) 6 *(off_t) pagesize;
186	if (lseek(rwfd, seekoff, SEEK_SET) != seekoff) {
187#endif /* LARGE_FILE */
188		CLEANERROR("first lseek failed");
189		anyfail();	//LTP Port
190	}
191	i = 0;
192	while (i < pagesize && write(rwfd, "b", 1) == 1)
193		i++;
194	if (i != pagesize) {
195		CLEANERROR("write to extend file failed");
196		anyfail();	//LTP Port
197	}
198	/* The file is now really big, and empty.
199	 * Assuming disk blocks are 8k, and logical pages are 4k, there are
200	 * two maps per page.  In order to test mapping at the beginning and
201	 * ends of the block, mapping the whole block, or none of the block
202	 * with different mappings on preceding and following blocks, each
203	 * 3 blocks with 6 pages can be thought of as a binary number from 0 to
204	 * 64 with a bit set for mapped or cleared for unmapped.  This number
205	 * is represented by i.  The value j is used to look at the bits of i
206	 * and decided to map the page or not.
207	 * NOTE: None of the above assumptions are critical.
208	 */
209	for (i = 0; i < 64; i++) {
210		for (j = 0; j < 6; j++) {
211			if (i & (1 << j)) {
212#ifdef LARGE_FILE
213				mapoff = startoffset +
214				    (off64_t) pagesize *(off64_t) (6 + i + j);
215				if (mmap64(mmapaddr + pagesize * (6 * i + j),
216					   pagesize, PROT_READ,
217					   MAP_FILE | MAP_PRIVATE | MAP_FIXED,
218					   rofd, mapoff)
219				    == (caddr_t) - 1) {
220#else /* LARGE_FILE */
221				mapoff = startoffset +
222				    (off_t) pagesize *(off_t) (6 + i + j);
223				if (mmap(mmapaddr + pagesize * (6 * i + j),
224					 pagesize, PROT_READ,
225					 MAP_FILE | MAP_PRIVATE | MAP_FIXED,
226					 rofd, mapoff)
227				    == (caddr_t) - 1) {
228#endif /* LARGE_FILE */
229					CLEANERROR("mmap failed");
230					anyfail();	//LTP Port
231				}
232			}
233		}
234	}
235	/* done mapping */
236	for (i = 0; i < 6 * pagesize; i++)
237		buf[i] = 'a';
238	/* write out 6 pages of stuff into each of the 64 six page sections */
239#ifdef LARGE_FILE
240	if (lseek64(rwfd, startoffset, SEEK_SET) != startoffset) {
241#else /* LARGE_FILE */
242	if (lseek(rwfd, startoffset, SEEK_SET) != startoffset) {
243#endif /* LARGE_FILE */
244		CLEANERROR("second lseek failed");
245		anyfail();	//LTP Port
246	}
247	for (i = 0; i < 64; i++) {
248		if (write(rwfd, buf, 6 * pagesize) != 6 * pagesize) {
249			CLEANERROR("write failed");
250			anyfail();	//LTP Port
251		}
252	}
253	/* Just finished scribbling all over interwoven mmapped and unmapped
254	 * regions.
255	 */
256	for (i = 0; i < 64; i++) {
257		for (j = 0; j < 6; j++) {
258			/* if mmaped && not updated */
259			if ((i & (1 << j))
260			    && *(mmapaddr + pagesize * (6 * i + j)) != 'a') {
261				CLEANERROR("'a' missing from mmap");
262				(void)fprintf(stderr, "i=%d\nj=%d\n"
263					      "val=0x%x\n", i, j,
264					      (int)(*
265						    (mmapaddr +
266						     pagesize * (6 * i + j))));
267				anyfail();	//LTP Port
268			}
269		}
270	}
271	/* Just checked to see that each mmapped page at least had an 'a' at
272	 * the beginning.
273	 */
274	CLEAN;
275	(void)time(&t);
276//      (void)printf("%s: Finished %s", argv[0], ctime(&t)); LTP Port
277	(local_flag == FAILED) ? tst_resm(TFAIL, "Test failed\n") : tst_resm(TPASS, "Test passed\n");	//LTP Port
278	tst_rmdir();
279	tst_exit();		//LTP Port
280
281	tst_exit();
282}
283
284/*****	LTP Port	*****/
285int anyfail(void)
286{
287	tst_brkm(TFAIL, tst_rmdir, "Test failed\n");
288}
289
290/*****	**	**	*****/
291