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 52int local_flag = PASSED; 53int block_number; 54 55char *TCID = "data_space"; /* Test program identifier. */ 56int TST_TOTAL = 1; /* Total number of test cases. */ 57/**************/ 58 59#define MAXCHILD 100 /* max number of children to allow */ 60int 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 69int nchild; /* # kids */ 70int csize; /* chunk size */ 71int iterations; /* # total iterations */ 72int rep_freq; /* report frequency */ 73int max_size; /* max file size */ 74int parent_pid; 75 76int usage(char *); 77int runtest(); 78int dotest(int, int); 79void bfill(char *, char, int); 80int dumpbuf(char *); 81void dumpbits(char *, int); 82int massmurder(); 83int okexit(int); 84 85char *prog; /* invoked name */ 86int chld_flag = 0; 87 88void cleanup(void) 89{ 90 tst_rmdir(); 91} 92 93int usage(prog) 94char *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 101int main(argc, argv) 102int argc; 103char *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 148int 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 214int nchunks; 215 216#define CHUNK(i) ((i) * csize) 217 218int dotest(testers, me) 219int testers; 220int 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 360void bfill(buf, val, size) 361register char *buf; 362char val; 363register 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 376int dumpbuf(buf) 377register 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 428void dumpbits(bits, size) 429char *bits; 430register 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 */ 450int 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 464int 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 474int 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 485int okexit(me) 486int 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