blob: 24b94ef839de68b39b96a1319f9ffabbb6dc0229 [file] [log] [blame]
robbiew24e30ab2003-01-07 20:53:21 +00001/*
2 *
3 * Copyright (c) International Business Machines Corp., 2002
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * NAME
22 * ftest08.c -- test single file io (tsfio.c by rbk) (ported from SPIE,
23 * section2/filesuite/ftest10.c, by Airong Zhang)
24 *
25 * this is the same as ftest5, except that it uses lseek64
26 *
27 * CALLS
28 * fsync, sync, lseek64, read, write
29 *
30 *
31 * ALGORITHM
32 * Several child processes doing random seeks, read/write
33 * operations on the same file.
34 *
35 *
36 * RESTRICTIONS
37 * Runs a long time with default args - can take others on input
38 * line. Use with "term mode".
39 *
40 */
41
42#define _XOPEN_SOURCE 500
43#define _LARGEFILE64_SOURCE 1
44#include <stdio.h> /* needed by testhead.h */
45#include <sys/types.h>
46#include <sys/param.h>
47#include <sys/wait.h>
48#include <sys/file.h>
49#include <sys/fcntl.h>
50#include <sys/stat.h>
51#include <sys/uio.h>
vapierf81795e2006-02-15 06:28:58 +000052#include <errno.h>
robbiew24e30ab2003-01-07 20:53:21 +000053#include <signal.h> /* DEM - added SIGTERM support */
54#include <unistd.h>
55#include "test.h"
56#include "usctest.h"
57
58char *TCID = "ftest08";
59int TST_TOTAL = 1;
60extern int Tst_count;
61
62#define PASSED 1
63#define FAILED 0
64
65#define MAXCHILD 25 /* max number of children to allow */
66#define K_1 1024
67#define K_2 2048
68#define K_4 4096
69#define MAXIOVCNT 16
70
71void init();
72int runtest();
73int dotest(int, int, int);
74int domisc(int, int, char*);
75int bfill(char*, char, int);
76int dumpiov(struct iovec*);
77int dumpbits(char*, int);
78int term();
79void cleanup(void);
80
81extern int errno;
82
83int csize; /* chunk size */
84int iterations; /* # total iterations */
85off64_t max_size; /* max file size */
86int misc_intvl; /* for doing misc things; 0 ==> no */
87int nchild; /* number of child processes */
88int nwait;
89int parent_pid;
90int pidlist[MAXCHILD];
91
92char filename[128];
93char *prog;
94
95char msg1[] = "Error on openning console.\n";
96char msg2[] = "1st open not fd 0!\n";
97int local_flag;
98
99/*--------------------------------------------------------------*/
100int main (ac, av)
101 int ac;
102 char *av[];
103{
104 int lc; /* loop counter */
105 char *msg; /* message returned from parse_opts */
106
107 /*
108 * parse standard options
109 */
110 if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
111 tst_resm(TBROK, "OPTION PARSING ERROR - %s", msg);
112 tst_exit();
113 /*NOTREACHED*/
114 }
115
116 for (lc = 0; TEST_LOOPING(lc); lc++) {
117
118
119 local_flag = PASSED;
120
121 init();
122
123 runtest();
124
125 if (local_flag == PASSED) {
126 tst_resm(TPASS, "Test passed.\n");
127 } else {
128 tst_resm(TFAIL, "Test failed.\n");
129 }
130
131 } /* end for */
132 cleanup();
133 return(0);
134}
135
136void init()
137{
138 int fd;
139 char wdbuf[MAXPATHLEN];
140
141 parent_pid = getpid();
142 tst_tmpdir();
143 /*
144 * Make a filename for the test.
145 */
146
147 if (!filename[0])
148 sprintf(filename, "%s/ftest08.%d", getcwd(wdbuf, MAXPATHLEN), getpid());
149
150 fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
151 if (fd < 0) {
152 tst_resm(TBROK, "Error %d creating file %s\n", errno, filename);
153 tst_exit();
154 }
155 close(fd);
156
157 /*
158 * Default values for run conditions.
159 */
160
161 iterations = 10;
162 nchild = 5;
163 csize = K_2; /* should run with 1, 2, and 4 K sizes */
164 max_size = K_1 * K_1;
165 misc_intvl = 10;
166
167 if (sigset(SIGTERM, (void (*)())term) == SIG_ERR) {
168 tst_resm(TBROK,"first sigset failed");
169 tst_exit();
170 }
171
172}
173
174/*--------------------------------------------------------------*/
175
176
177int runtest()
178{
179 register int i;
180 int child;
181 int status;
182 int count;
183 int fd;
184
185
186 for(i = 0; i < nchild; i++) {
187 if ((child = fork()) == 0) { /* child */
188 fd = open(filename, O_RDWR);
189 if (fd < 0) {
190 tst_resm(TFAIL, "\tTest[%d]: error %d openning %s.\n", errno, filename);
191 tst_exit();
192 }
193 dotest(nchild, i, fd); /* do it! */
194 tst_exit(); /* when done, exit */
195 }
196 close(fd);
197 if (child < 0) {
198 tst_resm(TINFO, "System resource may be too low, fork() malloc()"
199 " etc are likely to fail.\n");
200 tst_resm(TBROK, "Test broken due to inability of fork.\n");
201 tst_exit();
202
203 } else {
204 pidlist[i] = child;
205 nwait++;
206 }
207 }
208
209 /*
210 * Wait for children to finish.
211 */
212
213 count = 0;
214 while((child = wait(&status)) != -1 || errno == EINTR) {
215 if (child > 0)
216 {
217 //tst_resm(TINFO, "\tTest{%d} exited status = 0x%x\n", child, status);
218 if (status) {
219 tst_resm(TFAIL, "\tExpected 0 exit status - failed.\n");
220 local_flag = FAILED;
221 }
222 ++count;
223 }
224 }
225
226 /*
227 * Should have collected all children.
228 */
229
230 if (count != nwait) {
231 tst_resm(TFAIL, "\tWrong # children waited on, count = %d\n", count);
232 local_flag = FAILED;
233 }
234
235 unlink(filename);
236
237 sync(); /* safeness */
238 return(0);
239}
240
241/*
242 * dotest()
243 * Children execute this.
244 *
245 * Randomly read/mod/write chunks with known pattern and check.
246 * When fill sectors, iterate.
247 */
248
249#define NMISC 2
250enum m_type { m_fsync, m_sync };
251char *m_str[] = {
252 "fsync", "sync"
253};
254
255int misc_cnt[NMISC]; /* counts # of each kind of misc */
256int misc_flag;
257int nchunks;
258
259#define CHUNK(i) ((((off64_t)i) * testers + me) * csize)
260#define NEXTMISC ((rand() % misc_intvl) + 5)
261
262int dotest(testers, me, fd)
263 int testers;
264 int me;
265 int fd;
266{
267 register int i;
268 char *bits;
269 char *buf;
270 int count;
271 int collide;
272 char val;
273 char val0;
274 int chunk;
275 int whenmisc;
276 int xfr;
277
278 /* Stuff for the readv call */
279 struct iovec r_iovec[MAXIOVCNT];
280 int r_ioveclen;
281
282 /* Stuff for the writev call */
283
284 struct iovec val0_iovec[MAXIOVCNT];
285 struct iovec val_iovec[MAXIOVCNT];
286 int w_ioveclen;
287
288 nchunks = max_size / (testers * csize);
289 if( (bits = (char*)malloc((nchunks+7)/8)) == 0) {
290 tst_resm(TBROK, "\tmalloc failed(bits)\n");
291 tst_exit();
292 }
293 if( (buf = (char*)(malloc(csize))) == 0) {
294 tst_resm(TBROK, "\tmalloc failed(buf)\n");
295 tst_exit();
296 }
297
298 /*Allocate memory for the iovec buffers and init the iovec arrays
299 */
300 r_ioveclen = w_ioveclen = csize / MAXIOVCNT;
301
302 /* Please note that the above statement implies that csize
303 * be evenly divisible by MAXIOVCNT.
304 */
305
306 for (i = 0; i < MAXIOVCNT; i++) {
307 if( (r_iovec[i].iov_base = (char*)malloc(r_ioveclen)) == 0) {
308 tst_resm(TBROK, "\tmalloc failed(iov_base)\n");
309 tst_exit();
310 }
311 r_iovec[i].iov_len = r_ioveclen;
312
313 /* Allocate unused memory areas between all the buffers to
314 * make things more diffult for the OS.
315 */
316
317 if(malloc((i+1)*8) == 0) {
318 tst_resm(TBROK, "\tmalloc failed((i+1)*8)\n");
319 tst_exit();
320 }
321 if( (val0_iovec[i].iov_base = (char*)malloc(w_ioveclen)) == 0){
322 tst_resm(TBROK, "\tmalloc failed(val0_iovec)\n");
323 tst_exit();
324 }
325 val0_iovec[i].iov_len = w_ioveclen;
326
327 if(malloc((i+1)*8) == 0) {
328 tst_resm(TBROK, "\tmalloc failed((i+1)*8)\n");
329 tst_exit();
330 }
331 if( (val_iovec[i].iov_base = (char*)malloc(w_ioveclen)) == 0){
332 tst_resm(TBROK, "\tmalloc failed(iov_base)\n");
333 tst_exit();
334 }
335 val_iovec[i].iov_len = w_ioveclen;
336
337 if(malloc((i+1)*8) == 0) {
338 tst_resm(TBROK, "\tmalloc failed(((i+1)*8)\n");
339 tst_exit();
340 }
341 }
342
343 /*
344 * No init sectors; file-sys makes 0 to start.
345 */
346
347 val = (64/testers) * me + 1;
348 val0 = 0;
349
350 /*
351 * For each iteration:
352 * zap bits array
353 * loop:
354 * pick random chunk, read it.
355 * if corresponding bit off {
356 * verify == 0. (sparse file)
357 * ++count;
358 * } else
359 * verify == val.
360 * write "val" on it.
361 * repeat until count = nchunks.
362 * ++val.
363 */
364
365 srand(getpid());
366 if (misc_intvl) whenmisc = NEXTMISC;
367 while(iterations-- > 0) {
368 for(i = 0; i < NMISC; i++)
369 misc_cnt[i] = 0;
370 bfill(bits, 0, (nchunks+7)/8);
371 /* Have to fill the val0 and val iov buffers in a different manner
372 */
373 for(i = 0; i < MAXIOVCNT; i++) {
374 bfill(val0_iovec[i].iov_base,val0,val0_iovec[i].iov_len);
375 bfill(val_iovec[i].iov_base,val,val_iovec[i].iov_len);
376
377 }
378 count = 0;
379 collide = 0;
380 while(count < nchunks) {
381 chunk = rand() % nchunks;
382 /*
383 * Read it.
384 */
385 if (lseek64(fd, CHUNK(chunk), 0) < (off64_t)0) {
386 tst_resm(TFAIL, "\tTest[%d]: lseek64(0) fail at %Lx, errno = %d.\n",
387 me, CHUNK(chunk), errno);
388 tst_exit();
389 }
390 if ((xfr = readv(fd, &r_iovec[0], MAXIOVCNT)) < 0) {
391 tst_resm(TFAIL, "\tTest[%d]: readv fail at %Lx, errno = %d.\n",
392 me, CHUNK(chunk), errno);
393 tst_exit();
394 }
395 /*
396 * If chunk beyond EOF just write on it.
397 * Else if bit off, haven't seen it yet.
398 * Else, have. Verify values.
399 */
400 if (xfr == 0) {
401 bits[chunk/8] |= (1<<(chunk%8));
402 } else if ((bits[chunk/8] & (1<<(chunk%8))) == 0) {
403 if (xfr != csize) {
404 tst_resm(TFAIL, "\tTest[%d]: xfr=%d != %d, zero read.\n",
405 me, xfr, csize);
406 tst_exit();
407 }
408 for(i = 0; i < MAXIOVCNT; i++) {
409 if (memcmp(r_iovec[i].iov_base, val0_iovec[i].iov_base, r_iovec[i].iov_len)) {
410 tst_resm(TFAIL, "\tTest[%d] bad verify @ 0x%Lx for val %d count %d xfr %d.\n",
411 me, CHUNK(chunk), val0, count, xfr);
412 dumpiov(&r_iovec[i]);
413 dumpbits(bits, (nchunks+7)/8);
414 tst_exit();
415 }
416 }
417 bits[chunk/8] |= (1<<(chunk%8));
418 ++count;
419 } else {
420 if (xfr != csize) {
421 tst_resm(TFAIL, "\tTest[%d]: xfr=%d != %d, val read.\n",
422 me, xfr, csize);
423 tst_exit();
424 }
425 ++collide;
426 for(i = 0; i < MAXIOVCNT; i++) {
427 if (memcmp(r_iovec[i].iov_base, val_iovec[i].iov_base, r_iovec[i].iov_len)) {
428 tst_resm(TFAIL, "\tTest[%d] bad verify @ 0x%Lx for val %d count %d xfr %d.\n",
429 me, CHUNK(chunk), val, count, xfr);
430 dumpiov(&r_iovec[i]);
431 dumpbits(bits, (nchunks+7)/8);
432 tst_exit();
433 }
434 }
435 }
436 /*
437 * Write it.
438 */
439 if (lseek64(fd, -((off64_t)xfr), 1) < (off64_t)0) {
440 tst_resm(TFAIL, "\tTest[%d]: lseek64(1) fail at %Lx, errno = %d.\n",
441 me, CHUNK(chunk), errno);
442 tst_exit();
443 }
444 if ((xfr = writev(fd, &val_iovec[0], MAXIOVCNT)) < csize) {
445 if (errno == ENOSPC) {
446 tst_resm(TFAIL, "\tTest[%d]: no space, exiting.\n", me);
447 fsync(fd);
448 tst_exit();
449 }
450 tst_resm(TFAIL, "\tTest[%d]: writev fail at %Lx xfr %d, errno = %d.\n",
451 me, CHUNK(chunk), xfr, errno);
452 tst_exit();
453 }
454 /*
455 * If hit "misc" interval, do it.
456 */
457 if (misc_intvl && --whenmisc <= 0) {
458 domisc(me, fd, bits);
459 whenmisc = NEXTMISC;
460 }
461 if (count + collide > 2 * nchunks)
462 break;
463 }
464
465 /*
466 * End of iteration, maybe before doing all chunks.
467 */
468
469 if (count < nchunks) {
470 //tst_resm(TINFO, "\tTest{%d} val %d stopping @ %d, collide = {%d}.\n",
471 // me, val, count, collide);
472 for(i = 0; i < nchunks; i++) {
473 if ((bits[i/8] & (1<<(i%8))) == 0) {
474 if (lseek64(fd, CHUNK(i), 0) < (off64_t)0) {
475 tst_resm(TFAIL, "\tTest[%d]: lseek64 fail at %Lx, errno = %d.\n",
476 me, CHUNK(i), errno);
477 tst_exit();
478 }
479 if (writev(fd, &val_iovec[0], MAXIOVCNT) != csize) {
480 tst_resm(TFAIL, "\tTest[%d]: writev fail at %Lx, errno = %d.\n",
481 me, CHUNK(i), errno);
482 tst_exit();
483 }
484 }
485 }
486 }
487
488 fsync(fd);
489 ++misc_cnt[(int)m_fsync];
490 //tst_resm(TINFO, "\tTest[%d] val %d done, count = %d, collide = %d.\n",
491 // me, val, count, collide);
492 //for(i = 0; i < NMISC; i++)
493 // tst_resm(TINFO, "\t\tTest[%d]: %d %s's.\n", me, misc_cnt[i], m_str[i]);
494 val0 = val++;
495 }
496 return(0);
497}
498
499/*
500 * domisc()
501 * Inject misc syscalls into the thing.
502 */
503
504int domisc(me, fd, bits)
505 int me;
506 int fd;
507 char *bits;
508{
509 enum m_type type;
510
511 if (misc_flag) {
512 type = m_fsync;
513 misc_flag = 0;
514 } else {
515 type = m_sync;;
516 misc_flag = 1;
517 }
518 switch(type) {
519 case m_fsync:
520 if (fsync(fd) < 0) {
521 tst_resm(TFAIL, "\tTest[%d]: fsync error %d.\n", me, errno);
522 tst_exit();
523 }
524 break;
525 case m_sync:
526 sync();
527 break;
528 }
529 ++misc_cnt[(int)type];
530 return(0);
531}
532
533int bfill(buf, val, size)
534 register char *buf;
535 char val;
536 register int size;
537{
538 register int i;
539
540 for(i = 0; i < size; i++)
541 buf[i] = val;
542 return(0);
543}
544
545/*
546 * dumpiov
547 * Dump the contents of the r_iovec buffer.
548 */
549
550int dumpiov(iovptr)
551 register struct iovec *iovptr;
552{
553 register int i;
554 char val;
555 int idx;
556 int nout;
557
558 tst_resm(TINFO, "\tBuf:");
559 nout = 0;
560 idx = 0;
561 val = ((char *)iovptr->iov_base)[0];
562 for(i = 0; i < iovptr->iov_len; i++) {
563 if (((char *)iovptr->iov_base)[i] != val) {
564 if (i == idx+1)
565 tst_resm(TINFO, "\t%x, ", ((char *)iovptr->iov_base)[idx] & 0xff);
566 else
567 tst_resm(TINFO, "\t%d*%x, ", i-idx, ((char *)iovptr->iov_base)[idx] & 0xff);
568 idx = i;
569 ++nout;
570 }
571 if (nout > 10) {
572 tst_resm(TINFO, "\t ... more\n");
573 return(0);
574 }
575 }
576 if (i == idx+1)
577 tst_resm(TINFO, "\t%x\n", ((char *)iovptr->iov_base)[idx] & 0xff);
578 else
579 tst_resm(TINFO, "\t%d*%x\n", i-idx, ((char *)iovptr->iov_base)[idx]);
580 return(0);
581}
582
583
584/*
585 * dumpbits
586 * Dump the bit-map.
587 */
588
589int dumpbits(bits, size)
590 char *bits;
591 register int size;
592{
593 register char *buf;
594
595 tst_resm(TINFO, "\tBits array:");
596 for(buf = bits; size > 0; --size, ++buf) {
597 if ((buf-bits) % 16 == 0)
598 tst_resm(TINFO, "\n\t%04x:\t", 8*(buf-bits));
599 tst_resm(TINFO, "%02x ", (int)*buf & 0xff);
600 }
601 printf("\n");
602 return(0);
603}
604
605/*--------------------------------------------------------------*/
606
607
608int term()
609{
610 register int i;
611
612 tst_resm(TINFO, "\tterm -[%d]- got sig term.\n", getpid());
613
614 if (parent_pid == getpid()) {
615 for (i=0; i < nchild; i++)
616 if (pidlist[i]) /* avoid embarassment */
617 kill(pidlist[i], SIGTERM);
618 return(0);
619 }
620
621 tst_exit();
622 return(0);
623}
624
625void
626cleanup()
627{
628 /*
629 * print timing stats if that option was specified.
630 * print errno log if that option was specified.
631 */
632 TEST_CLEANUP;
633
634 tst_rmdir();
635 tst_exit();
636}
637