1 /*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /* 11/18/2002 Port to LTP robbiew@us.ibm.com */
21 /* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
22
23 /*
24 * NAME
25 * data_space.c -- test data space
26 *
27 * CALLS
28 * malloc (3)
29 *
30 * ALGORITHM
31 * Test VM for set of data-space intensive programs
32 *
33 */
34
35 #define _XOPEN_SOURCE 500
36 #include <stdio.h>
37 #include <signal.h>
38 #include <sys/types.h>
39 #include <errno.h>
40 #include <sys/wait.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <string.h>
44 //void (*sigset(int, void(*)(int)))(int);
45
46 /** LTP Port **/
47 #include "test.h"
48
49 #define FAILED 0
50 #define PASSED 1
51
52 int local_flag = PASSED;
53 int block_number;
54
55 char *TCID = "data_space"; /* Test program identifier. */
56 int TST_TOTAL = 1; /* Total number of test cases. */
57 /**************/
58
59 #define MAXCHILD 100 /* max number of children to allow */
60 int allchild[MAXCHILD + 1];
61 #define K_1 1024
62 #define K_2 2048
63 #define K_4 4096
64
65 #define bd_arg(str) \
66 tst_brkm(TCONF, NULL, \
67 "bad argument - %s - could not parse as number.", str)
68
69 int nchild; /* # kids */
70 int csize; /* chunk size */
71 int iterations; /* # total iterations */
72 int rep_freq; /* report frequency */
73 int max_size; /* max file size */
74 int parent_pid;
75
76 int usage(char *);
77 int runtest();
78 int dotest(int, int);
79 void bfill(char *, char, int);
80 int dumpbuf(char *);
81 void dumpbits(char *, int);
82 int massmurder();
83 int okexit(int);
84
85 char *prog; /* invoked name */
86 int chld_flag = 0;
87
cleanup(void)88 void cleanup(void)
89 {
90 tst_rmdir();
91 }
92
usage(prog)93 int usage(prog)
94 char *prog;
95 {
96 tst_resm(TCONF, "Usage: %s <nchild> <size> <chunk_size> <iterations>",
97 prog);
98 tst_brkm(TCONF, NULL, "DEFAULTS: 10 1024*1024 4096 25");
99 }
100
main(argc,argv)101 int main(argc, argv)
102 int argc;
103 char *argv[];
104 {
105 int i = 1;
106 int term();
107 int chld();
108
109 prog = argv[0];
110
111 if (argc == 1) {
112 nchild = 10;
113 max_size = K_1 * K_1;
114 csize = K_4;
115 iterations = 25;
116 } else if (argc == 5) {
117 if (sscanf(argv[i++], "%d", &nchild) != 1)
118 bd_arg(argv[i - 1]);
119 if (sscanf(argv[i++], "%d", &max_size) != 1)
120 bd_arg(argv[i - 1]);
121 if (sscanf(argv[i++], "%d", &csize) != 1)
122 bd_arg(argv[i - 1]);
123 if (sscanf(argv[i++], "%d", &iterations) != 1)
124 bd_arg(argv[i - 1]);
125 if (nchild > MAXCHILD) {
126 tst_brkm(TBROK, NULL,
127 "FAILURE, %d children exceeded maximum allowed",
128 nchild);
129 }
130 } else
131 usage(prog);
132
133 tst_tmpdir();
134
135 parent_pid = getpid();
136
137 if (sigset(SIGTERM, (void (*)())term) == SIG_ERR) {
138 tst_brkm(TBROK, NULL, "first sigset failed");
139 }
140 if (sigset(SIGUSR1, (void (*)())chld) == SIG_ERR) {
141 tst_brkm(TBROK, NULL, "sigset shichld");
142 }
143
144 runtest();
145 tst_exit();
146 }
147
runtest()148 int runtest()
149 {
150 register int i;
151 int child;
152 int status;
153 int count;
154
155 for (i = 0; i < nchild; i++) {
156 chld_flag = 0;
157 switch (child = fork()) {
158 case -1:
159 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
160 case 0:
161 dotest(nchild, i);
162 exit(0);
163 }
164 allchild[i] = child;
165 while (!chld_flag)
166 sleep(1);
167 }
168
169 /*
170 * Wait for children to finish.
171 */
172
173 count = 0;
174 while ((child = wait(&status)) > 0) {
175 #ifdef DEBUG
176 tst_resm(TINFO, "\t%s[%d] exited status = 0x%x\n", prog, child,
177 status);
178 #endif
179 if (status) {
180 tst_resm(TFAIL, "\tTest failed, expected 0 exit.\n");
181 local_flag = FAILED;
182 }
183 ++count;
184 }
185
186 /*
187 * Should have collected all children.
188 */
189
190 if (count != nchild) {
191 tst_resm(TFAIL, "\tWrong # children waited on, count = %d\n",
192 count);
193 local_flag = FAILED;
194 }
195
196 if (local_flag == FAILED)
197 tst_resm(TFAIL, "Test failed");
198 else
199 tst_resm(TPASS, "Test passed");
200 sync(); /* safeness */
201
202 return 0;
203 }
204
205 /*
206 * dotest()
207 * Children execute this.
208 *
209 * Randomly read/mod/write chunks with known pattern and check.
210 * When fill sectors, iterate.
211 *
212 */
213
214 int nchunks;
215
216 #define CHUNK(i) ((i) * csize)
217
dotest(testers,me)218 int dotest(testers, me)
219 int testers;
220 int me;
221 {
222 char *bits;
223 char *mondobuf;
224 char *val_buf;
225 char *zero_buf;
226 char *buf;
227 int count;
228 int collide;
229 char val;
230 int chunk;
231
232 /*
233 * Do the mondo-test.
234 *
235 * NOTE: If we run this with a lot of children, the last child
236 * processes may not have enough swap space to do these
237 * malloc's (mainly mondobuf). So if the malloc's don't
238 * work we just exit with zero status as long as we are
239 * not the first child.
240 */
241
242 nchunks = max_size / csize;
243 bits = malloc((nchunks + 7) / 8);
244 if (bits == 0)
245 okexit(me);
246 val_buf = (char *)(malloc(csize));
247 if (val_buf == 0)
248 okexit(me);
249 zero_buf = (char *)(malloc(csize));
250 if (zero_buf == 0)
251 okexit(me);
252 mondobuf = malloc(max_size);
253 if (mondobuf == 0)
254 okexit(me);
255
256 kill(parent_pid, SIGUSR1);
257
258 /*
259 * No init sectors; allow file to be sparse.
260 */
261
262 val = (64 / testers) * me + 1;
263
264 /*
265 * For each iteration:
266 * zap bits array
267 * loop:
268 * pick random chunk.
269 * if corresponding bit off {
270 * verify == 0. (sparse file)
271 * ++count;
272 * } else
273 * verify == val.
274 * write "val" on it.
275 * repeat until count = nchunks.
276 * ++val.
277 * Fill-in those chunks not yet seen.
278 */
279
280 bfill(zero_buf, 0, csize);
281 bfill(mondobuf, 0, max_size);
282
283 srand(getpid());
284 while (iterations-- > 0) {
285 bfill(bits, 0, (nchunks + 7) / 8);
286 bfill(val_buf, val, csize);
287 count = 0;
288 collide = 0;
289 while (count < nchunks) {
290 chunk = rand() % nchunks;
291 buf = mondobuf + CHUNK(chunk);
292
293 /*
294 * If bit off, haven't seen it yet.
295 * Else, have. Verify values.
296 */
297
298 if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0) {
299 if (memcmp(buf, zero_buf, csize)) {
300 tst_resm(TFAIL,
301 "\t%s[%d] bad verify @ %d (%p) for val %d count %d, should be 0x%x.\n",
302 prog, me, chunk, buf, val,
303 count, val - 1);
304 tst_resm(TINFO, "\tPrev ");
305 dumpbuf(buf - csize);
306 dumpbuf(buf);
307 tst_resm(TINFO, "\tNext ");
308 dumpbuf(buf + csize);
309 dumpbits(bits, (nchunks + 7) / 8);
310 tst_exit();
311 }
312 bits[chunk / 8] |= (1 << (chunk % 8));
313 ++count;
314 } else {
315 ++collide;
316 if (memcmp(buf, val_buf, csize)) {
317 tst_resm(TFAIL,
318 "\t%s[%d] bad verify @ %d (%p) for val %d count %d.\n",
319 prog, me, chunk, buf, val,
320 count);
321 tst_resm(TINFO, "\tPrev ");
322 dumpbuf(buf - csize);
323 dumpbuf(buf);
324 tst_resm(TINFO, "\tNext ");
325 dumpbuf(buf + csize);
326 dumpbits(bits, (nchunks + 7) / 8);
327 tst_exit();
328 }
329 }
330
331 /*
332 * Write it.
333 */
334
335 bfill(buf, val, csize);
336
337 if (count + collide > 2 * nchunks)
338 break;
339 }
340
341 /*
342 * End of iteration, maybe before doing all chunks.
343 */
344 #ifdef DEBUG
345 tst_resm(TINFO,
346 "\t%s[%d] val %d done, count = %d, collide = %d.\n",
347 prog, me, val, count, collide);
348 #endif
349 for (chunk = 0; chunk < nchunks; chunk++) {
350 if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0)
351 bfill(mondobuf + CHUNK(chunk), val, csize);
352 }
353 bfill(zero_buf, val, csize);
354 ++val;
355 }
356
357 return 0;
358 }
359
bfill(buf,val,size)360 void bfill(buf, val, size)
361 register char *buf;
362 char val;
363 register int size;
364 {
365 register int i;
366
367 for (i = 0; i < size; i++)
368 buf[i] = val;
369 }
370
371 /*
372 * dumpbuf
373 * Dump the buffer.
374 */
375
dumpbuf(buf)376 int dumpbuf(buf)
377 register char *buf;
378 {
379 register int i;
380 char val;
381 int idx;
382 int nout;
383
384 #ifdef DEBUG
385 tst_resm(TINFO, "Buf: ... ");
386 for (i = -10; i < 0; i++)
387 tst_resm(TINFO, "%x, ", buf[i]);
388 tst_resm(TINFO, "\n");
389 #endif
390
391 nout = 0;
392 idx = 0;
393 val = buf[0];
394 for (i = 0; i < csize; i++) {
395 if (buf[i] != val) {
396 #ifdef DEBUG
397 if (i == idx + 1)
398 tst_resm(TINFO, "%x, ", buf[idx] & 0xff);
399 else
400 tst_resm(TINFO, "%d*%x, ", i - idx,
401 buf[idx] & 0xff);
402 #endif
403 idx = i;
404 val = buf[i];
405 ++nout;
406 }
407 if (nout > 10) {
408 #ifdef DEBUG
409 tst_resm(TINFO, " ... more\n");
410 #endif
411 return 0;
412 }
413 }
414 #ifdef DEBUG
415 if (i == idx + 1)
416 tst_resm(TINFO, "%x\n", buf[idx] & 0xff);
417 else
418 tst_resm(TINFO, "%d*%x\n", i - idx, buf[idx]);
419 #endif
420 return 0;
421 }
422
423 /*
424 * dumpbits
425 * Dump the bit-map.
426 */
427
dumpbits(bits,size)428 void dumpbits(bits, size)
429 char *bits;
430 register int size;
431 {
432 #ifdef DEBUG
433 register char *buf;
434
435 tst_resm(TINFO, "Bits array:");
436 for (buf = bits; size > 0; --size, ++buf) {
437 if ((buf - bits) % 16 == 0)
438 tst_resm(TINFO, "\n%04x:\t", 8 * (buf - bits));
439 tst_resm(TINFO, "%02x ", (int)*buf & 0xff);
440 }
441 tst_resm(TINFO, "\n");
442 #endif
443 }
444
445 /* term()
446 *
447 * Parent - kill kids and return when signal arrives.
448 * Child - exit.
449 */
term()450 int term()
451 {
452 #ifdef DEBUG
453 tst_resm(TINFO, "\tterm -[%d]- got sig term.\n", getpid());
454 #endif
455
456 if (parent_pid == getpid()) {
457 massmurder();
458 return 0;
459 }
460
461 exit(0);
462 }
463
chld()464 int chld()
465 {
466 if (sigset(SIGUSR1, (void (*)())chld) == SIG_ERR) {
467 tst_resm(TBROK, "sigset shichld");
468 exit(1);
469 }
470 chld_flag++;
471 return 0;
472 }
473
massmurder()474 int massmurder()
475 {
476 int i;
477 for (i = 0; i < MAXCHILD; i++) {
478 if (allchild[i]) {
479 kill(allchild[i], SIGTERM);
480 }
481 }
482 return 0;
483 }
484
okexit(me)485 int okexit(me)
486 int me;
487 {
488 kill(parent_pid, SIGUSR1);
489 tst_resm(TINFO, "\tChild [%d] - cannot malloc buffer - exiting.\n", me);
490 if (me) {
491 tst_resm(TINFO, "\tThis is ok - probably swap space limit.\n");
492 tst_exit();
493 } else {
494 tst_brkm(TBROK,
495 NULL,
496 "\tThis is not ok for first child - check parameters.\n");
497 }
498
499 return 0;
500 }
501