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 (at) us.ibm.com */ 21 /* 06/30/2001 Port to Linux nsharoff (at) 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 88 void cleanup(void) 89 { 90 tst_rmdir(); 91 } 92 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 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 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 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 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 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 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 */ 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 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 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 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