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\n");
317 }
318
319 void ok_exit(void)
320 {
321 tst_resm(TPASS, "Test passed\n");
322 tst_rmdir();
323 tst_exit();
324 }
325
326 /***** ** ****** ** *****/
327