• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
43 static 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 
59 extern time_t time(time_t *);
60 extern char *ctime(const time_t *);
61 extern void exit(int);
62 static int checkchars(int fd, char val, int n);
63 
64 char *TCID = "mmapstress07";
65 
66 int local_flag = PASSED;
67 int block_number;
68 FILE *temp;
69 int TST_TOTAL = 1;
70 
71 int anyfail();
72 void ok_exit();
73 
74  /*ARGSUSED*/ static
cleanup(int sig)75 void 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 
main(int argc,char ** argv)85 int 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  */
302 static 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	**	*****/
314 int anyfail(void)
315 {
316 	tst_brkm(TFAIL, tst_rmdir, "Test failed");
317 }
318 
319 void ok_exit(void)
320 {
321 	tst_resm(TPASS, "Test passed");
322 	tst_rmdir();
323 	tst_exit();
324 }
325 
326 /*****	**	******		**	*****/
327