1 /* 2 * Disktest 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 * 20 * Please send e-mail to yardleyb (at) us.ibm.com if you have 21 * questions or comments. 22 * 23 * Project Website: TBD 24 * 25 * $Id: childmain.c,v 1.11 2009/02/26 12:14:53 subrata_modak Exp $ 26 * 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <stdarg.h> 32 #include <stdint.h> 33 #ifdef WINDOWS 34 #include <windows.h> 35 #include <winioctl.h> 36 #include <io.h> 37 #include <process.h> 38 #include <sys/stat.h> 39 #include "getopt.h" 40 #else 41 #include <pthread.h> 42 #include <sys/types.h> 43 #include <unistd.h> 44 #endif 45 #include <signal.h> 46 #include <time.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <string.h> 50 #include <ctype.h> 51 52 #include "defs.h" 53 #include "globals.h" 54 #include "main.h" 55 #include "sfunc.h" 56 #include "threading.h" 57 #include "io.h" 58 #include "dump.h" 59 #include "timer.h" 60 #include "signals.h" 61 #include "childmain.h" 62 63 /* 64 * The following three functions are used to mutex LBAs that are in use by another 65 * thread from any other thread performing an action on that lba. 66 */ 67 unsigned short action_in_use(const test_env_t * env, const action_t target) 68 { 69 int i = 0; 70 71 for (i = 0; i < env->action_list_entry; i++) { 72 if ((target.lba == env->action_list[i].lba) /* attempting same transfer start lba */ 73 ||((target.lba < env->action_list[i].lba) && (target.lba + target.trsiz - 1) >= env->action_list[i].lba) /* attempting transfer over an lba in use */ 74 ) { 75 /* 76 * The lba(s) we want to do IO to are in use by another thread, 77 * but since POSIX allows for multiple readers, we need to compare 78 * our action with the action being executed by the other thread 79 */ 80 switch (target.oper) { 81 case WRITER: /* if we want to write, we can't */ 82 return TRUE; 83 case READER: /* if we want to read, and a write is in progress, we can't */ 84 if (env->action_list[i].oper == WRITER) { 85 return TRUE; 86 } 87 /* otherwise allow multiple readers */ 88 return FALSE; 89 default: 90 /* for all other operations, always assume inuse */ 91 return TRUE; 92 } 93 } 94 } 95 96 return FALSE; 97 } 98 99 void add_action(test_env_t * env, const child_args_t * args, 100 const action_t target) 101 { 102 103 if (env->action_list_entry == args->t_kids) { /* we should never get here */ 104 printf 105 ("ATTEMPT TO ADD MORE ENTRIES TO LBA WRITE LIST THEN ALLOWED, CODE BUG!!!\n"); 106 abort(); 107 } 108 109 env->action_list[env->action_list_entry++] = target; 110 } 111 112 void remove_action(test_env_t * env, const action_t target) 113 { 114 int i = 0; 115 116 if (env->action_list_entry == 0) { 117 /* we should never get here */ 118 printf 119 ("ATTEMPT TO REMOVE ENTRIES FROM LBA WRITE LIST WHERE NONE EXIST, CODE BUG!!!\n"); 120 abort(); 121 } 122 123 /* look for the removing target */ 124 while (target.lba != env->action_list[i].lba) { 125 if (env->action_list_entry == i++) { 126 printf 127 ("INDEX AND CURRENT LIST ENTRY, CODE BUG!!!!!!\n"); 128 abort(); 129 } 130 } 131 132 /* move eny other entries down */ 133 for (; i < env->action_list_entry - 1; i++) { 134 env->action_list[i] = env->action_list[i + 1]; 135 } 136 137 /* reduce the slot */ 138 env->action_list_entry--; 139 } 140 141 void decrement_io_count(const child_args_t * args, test_env_t * env, 142 const action_t target) 143 { 144 if (args->flags & CLD_FLG_LBA_SYNC) { 145 remove_action(env, target); 146 } 147 if (target.oper == WRITER) { 148 (env->wcount)--; 149 } else { 150 (env->rcount)--; 151 } 152 } 153 154 /* 155 * This function will write a special mark to LBA 0 of 156 * a target, if an error occured on the target. This 157 * is so a trigger can be set, i.e. on an analyser. 158 */ 159 void write_error_mark(fd_t fd, char *data) 160 { 161 OFF_T ActualBytePos = 0; 162 long tcnt = 0; 163 164 ActualBytePos = Seek(fd, 0); 165 if (ActualBytePos != 0) { 166 /* could not seek to LBA 0 */ 167 return; 168 } 169 170 memcpy(data, "DISKTEST ERROR OCCURRED", 171 strlen("DISKTEST ERROR OCCURRED")); 172 tcnt = Write(fd, data, BLK_SIZE); 173 } 174 175 /* 176 * Sets the test state correctly, and updates test flags 177 * based on user parsed options 178 */ 179 void update_test_state(child_args_t * args, test_env_t * env, 180 const int this_thread_id, fd_t fd, char *data) 181 { 182 extern unsigned short glb_run; 183 extern unsigned long glb_flags; 184 185 if (args->flags & CLD_FLG_ALLDIE) { 186 #ifdef _DEBUG 187 PDBG4(DBUG, args, 188 "Thread %d: Setting bContinue to FALSE, io error, all die\n", 189 this_thread_id); 190 #endif 191 args->test_state = SET_STS_FAIL(args->test_state); 192 env->bContinue = FALSE; 193 } 194 if (glb_flags & GLB_FLG_KILL) { 195 #ifdef _DEBUG 196 PDBG4(DBUG, args, 197 "Thread %d: Setting bContinue to FALSE, io error, global die\n", 198 this_thread_id); 199 #endif 200 args->test_state = SET_STS_FAIL(args->test_state); 201 env->bContinue = FALSE; 202 glb_run = 0; 203 } 204 if ((args->flags & CLD_FLG_W) && (args->flags & CLD_FLG_ERR_MARK)) { 205 write_error_mark(fd, data); 206 } 207 } 208 209 #ifdef _DEBUG 210 #ifdef _DEBUG_PRINTMAP 211 void print_lba_bitmap(const test_env_t * env) 212 { 213 unsigned char *wbitmap = (unsigned char *)env->shared_mem + BMP_OFFSET; 214 int i; 215 216 for (i = 0; i < (env->bmp_siz - 1); i++) { 217 printf("%02x", *(wbitmap + i)); 218 } 219 printf("\n"); 220 } 221 #endif 222 #endif 223 224 action_t get_next_action(child_args_t * args, test_env_t * env, 225 const OFF_T mask) 226 { 227 228 OFF_T *pVal1 = (OFF_T *) env->shared_mem; 229 OFF_T *tmpLBA; 230 OFF_T guessLBA; 231 unsigned char *wbitmap = (unsigned char *)env->shared_mem + BMP_OFFSET; 232 233 short blk_written = 0; 234 unsigned long i; 235 action_t target = { NONE, 0, 0 }; 236 short direct = 0; 237 238 /* pick an operation */ 239 target.oper = env->lastAction.oper; 240 if ((args->flags & CLD_FLG_LINEAR) && !(args->flags & CLD_FLG_NTRLVD)) { 241 target.oper = TST_OPER(args->test_state); 242 } else if ((args->flags & CLD_FLG_RANDOM) 243 && !(args->flags & CLD_FLG_NTRLVD)) { 244 if ((((env->wcount) * 100) / 245 (((env->rcount) + 1) + (env->wcount))) >= (args->wperc)) { 246 target.oper = READER; 247 } else { 248 target.oper = WRITER; 249 } 250 #ifdef _DEBUG 251 PDBG4(DBUG, args, "W:%.2f%% R:%.2f%%\n", 252 100 * ((double)(env->wcount) / 253 ((double)env->rcount + (double)env->wcount)), 254 100 * ((double)(env->rcount) / 255 ((double)env->wcount + (double)env->rcount))); 256 #endif 257 } else if ((args->flags & CLD_FLG_NTRLVD) 258 && !TST_wFST_TIME(args->test_state)) { 259 if ((args->flags & CLD_FLG_R) && (args->flags & CLD_FLG_W)) { 260 target.oper = 261 (env->lastAction.oper == WRITER) ? READER : WRITER; 262 } 263 } else if (target.oper == NONE) { 264 /* if still no decision for an operation, do the basics */ 265 target.oper = (args->flags & CLD_FLG_W) ? WRITER : READER; 266 } 267 268 /* pick a transfer length */ 269 if (!(args->flags & CLD_FLG_RTRSIZ)) { 270 target.trsiz = args->ltrsiz; 271 } else { 272 if ((args->flags & CLD_FLG_NTRLVD) && 273 (args->flags & CLD_FLG_W) && 274 (args->flags & CLD_FLG_R) && 275 (env->lastAction.trsiz != 0) && (target.oper == READER)) { 276 target.trsiz = env->lastAction.trsiz; 277 } else { 278 do { 279 target.trsiz = (rand() & 0xFFF) + args->ltrsiz; 280 if ((args->flags & CLD_FLG_SKS) 281 && (((env->wcount) + (env->rcount)) >= 282 args->seeks)) 283 break; 284 } while (target.trsiz > args->htrsiz); 285 } 286 } 287 288 /* pick an lba */ 289 if (args->start_blk == args->stop_blk) { /* diskcache test */ 290 target.lba = args->start_lba + args->offset; 291 } else if (args->flags & CLD_FLG_LINEAR) { 292 tmpLBA = 293 (target.oper == 294 WRITER) ? pVal1 + OFF_WLBA : pVal1 + OFF_RLBA; 295 direct = (TST_DIRCTN(args->test_state)) ? 1 : -1; 296 if ((target.oper == WRITER) && TST_wFST_TIME(args->test_state)) { 297 *(tmpLBA) = args->start_lba + args->offset; 298 } else if ((target.oper == READER) 299 && TST_rFST_TIME(args->test_state)) { 300 *(tmpLBA) = args->start_lba + args->offset; 301 } else if ((TST_DIRCTN(args->test_state)) 302 && ((*(tmpLBA) + (target.trsiz - 1)) <= 303 args->stop_lba)) { 304 } else if (!(TST_DIRCTN(args->test_state)) 305 && (*(tmpLBA) >= (args->start_lba + args->offset))) { 306 } else { 307 if (args->flags & CLD_FLG_LUNU) { 308 *(tmpLBA) = args->start_lba + args->offset; 309 if ((args->flags & CLD_FLG_CYC) 310 && (target.oper == WRITER)) { 311 target.oper = NONE; 312 } 313 } else if (args->flags & CLD_FLG_LUND) { 314 args->test_state = DIRCT_CNG(args->test_state); 315 direct = 316 (TST_DIRCTN(args->test_state)) ? 1 : -1; 317 *(tmpLBA) += 318 (OFF_T) direct *(OFF_T) target.trsiz; 319 if ((args->flags & CLD_FLG_CYC) && (direct > 0)) { 320 target.oper = NONE; 321 } 322 } 323 } 324 target.lba = *(tmpLBA); 325 } else if (args->flags & CLD_FLG_RANDOM) { 326 if ((args->flags & CLD_FLG_NTRLVD) 327 && (args->flags & CLD_FLG_W) 328 && (args->flags & CLD_FLG_R) 329 && (target.oper == READER)) { 330 target.lba = env->lastAction.lba; 331 } else { 332 do { 333 target.lba = 334 (Rand64() & mask) + args->start_lba; 335 } while (target.lba > args->stop_lba); 336 337 guessLBA = 338 ALIGN(target.lba, target.trsiz) + args->offset; 339 if (guessLBA > args->stop_lba) { 340 target.lba = guessLBA = args->stop_lba; 341 } 342 if (target.lba != guessLBA) { 343 if ((target.lba - guessLBA) <= 344 ((guessLBA + target.trsiz) - target.lba)) { 345 target.lba = guessLBA; 346 } else if ((guessLBA + target.trsiz) > 347 args->stop_lba) { 348 target.lba = guessLBA; 349 } else { 350 target.lba = guessLBA + target.trsiz; 351 } 352 } 353 if ((target.lba + (target.trsiz - 1)) > args->stop_lba) { 354 target.lba -= target.trsiz; 355 } 356 } 357 } 358 if ((args->flags & CLD_FLG_LBA_SYNC) && (action_in_use(env, target))) { 359 target.oper = RETRY; 360 } 361 362 if (!(args->flags & CLD_FLG_NTRLVD) 363 && !(args->flags & CLD_FLG_RANDOM) 364 && (args->flags & CLD_FLG_W) 365 && (args->flags & CLD_FLG_R)) { 366 if (((target.oper == WRITER) ? env->wcount : env->rcount) >= 367 (args->seeks / 2)) { 368 target.oper = NONE; 369 } 370 } 371 372 /* get out if exceeded one of the following */ 373 if ((args->flags & CLD_FLG_SKS) 374 && (((env->wcount) + (env->rcount)) >= args->seeks)) { 375 target.oper = NONE; 376 } 377 378 /* 379 * check the bitmask to see if we can read, 380 * if the bitmask is set for the block of LBAs, 381 * then we are OK to read 382 * 383 * only matters of error checking or write once 384 */ 385 blk_written = 1; 386 if (args->flags & (CLD_FLG_CMPR | CLD_FLG_WRITE_ONCE)) { 387 for (i = 0; i < target.trsiz; i++) { 388 if ((* 389 (wbitmap + 390 (((target.lba - args->offset - args->start_lba) + 391 i) / 8)) & (0x80 >> (((target.lba - 392 args->offset - 393 args->start_lba) + 394 i) % 8))) == 0) { 395 blk_written = 0; 396 break; 397 } 398 } 399 } 400 401 /* get out, nothing to do */ 402 if ((target.oper == NONE) || (target.oper == RETRY)) ; 403 /* get out, read only, or not comparing */ 404 else if (!(args->flags & CLD_FLG_W)) ; 405 /* get out, we are a writer, write once enabled, and block not written */ 406 else if ((target.oper == WRITER) && (args->flags & CLD_FLG_WRITE_ONCE) 407 && !blk_written) ; 408 /* get out, we are a writer and not write once */ 409 else if ((target.oper == WRITER) 410 && !(args->flags & CLD_FLG_WRITE_ONCE)) ; 411 /* get out, we are a reader, and blocks written */ 412 else if ((target.oper == READER) && blk_written) ; 413 else if ((args->flags & CLD_FLG_LINEAR) 414 || ((args->flags & CLD_FLG_NTRLVD) 415 && (args->flags & CLD_FLG_RANDOM))) { 416 if (!blk_written) { 417 /* 418 * if we are linear and not interleaved and on the read pass 419 * with random transfer sizes, and we hit the limit of the 420 * random write transfer lengths, because blk_written was 421 * false, then we cannot do any more reads unless we start 422 * over at start_lba+offset. 423 */ 424 if ((args->flags & CLD_FLG_LINEAR) && 425 !(args->flags & CLD_FLG_NTRLVD) && 426 (args->flags & CLD_FLG_RTRSIZ) && 427 (target.oper == READER)) { 428 tmpLBA = pVal1 + OFF_RLBA; 429 *(tmpLBA) = args->start_lba + args->offset; 430 target.lba = *(tmpLBA); 431 } else { 432 /* 433 * we must retry, as we can't start the read, since the write 434 * has not happened yet. 435 */ 436 target.oper = RETRY; 437 } 438 } 439 } else if ((target.oper == READER) && (args->flags & CLD_FLG_CMPR) 440 && !blk_written) { 441 /* should have been a random reader, but blk not written, and running with compare, so make me a writer */ 442 target.oper = WRITER; 443 args->test_state = SET_OPER_W(args->test_state); 444 /* if we switched to a writer, then we have to check action_in_use again */ 445 if ((args->flags & CLD_FLG_LBA_SYNC) 446 && (action_in_use(env, target))) { 447 target.oper = RETRY; 448 } 449 } else { 450 /* should have been a random writer, but blk already written, so make me a reader */ 451 target.oper = READER; 452 args->test_state = SET_OPER_R(args->test_state); 453 /* if we switched to a reader, then no need to check action_in_use again */ 454 } 455 456 #ifdef _DEBUG 457 #ifdef WINDOWS 458 PDBG5(DBUG, args, "%I64d, %I64d, %I64d, %I64d\n", env->wcount, 459 env->rcount, args->seeks, args->stop_lba); 460 #else 461 PDBG5(DBUG, args, "%lld, %lld, %lld, %lld\n", env->wcount, env->rcount, 462 args->seeks, args->stop_lba); 463 #endif 464 #endif 465 466 if (target.oper == WRITER) { 467 (env->wcount)++; 468 if ((args->flags & CLD_FLG_LUND)) 469 *(pVal1 + OFF_RLBA) = *(pVal1 + OFF_WLBA); 470 *(pVal1 + OFF_WLBA) += (OFF_T) direct *(OFF_T) target.trsiz; 471 if (TST_wFST_TIME(args->test_state)) 472 args->test_state = CLR_wFST_TIME(args->test_state); 473 env->lastAction = target; 474 if (args->flags & CLD_FLG_LBA_SYNC) { 475 add_action(env, args, target); 476 } 477 } 478 if (target.oper == READER) { 479 (env->rcount)++; 480 *(pVal1 + OFF_RLBA) += (OFF_T) direct *(OFF_T) target.trsiz; 481 if (TST_rFST_TIME(args->test_state)) 482 args->test_state = CLR_rFST_TIME(args->test_state); 483 env->lastAction = target; 484 if (args->flags & CLD_FLG_LBA_SYNC) { 485 add_action(env, args, target); 486 } 487 } 488 489 return target; 490 } 491 492 void miscompare_dump(const child_args_t * args, const char *data, 493 const size_t buf_len, OFF_T tPosition, const size_t offset, 494 mc_func_t oper, const int this_thread_id) 495 { 496 FILE *fpDumpFile; 497 char obuff[80]; 498 499 obuff[0] = 0; 500 sprintf(obuff, "dump_%d.dat", args->pid); 501 fpDumpFile = fopen(obuff, "a"); 502 503 if (oper == EXP) { 504 if (fpDumpFile) 505 fprintf(fpDumpFile, "\n\n\n"); 506 if (fpDumpFile) 507 fprintf(fpDumpFile, "Execution string: %s\n", 508 args->argstr); 509 if (fpDumpFile) 510 fprintf(fpDumpFile, "Target: %s\n", args->device); 511 if (fpDumpFile) 512 fprintf(fpDumpFile, DMSTR, this_thread_id, tPosition, 513 tPosition); 514 if (fpDumpFile) 515 fprintf(fpDumpFile, DMOFFSTR, this_thread_id, offset, 516 offset); 517 pMsg(ERR, args, "EXPECTED:\n"); 518 if (fpDumpFile) 519 fprintf(fpDumpFile, DMFILESTR, "EXPECTED", args->device, 520 tPosition, offset); 521 } else if (oper == ACT) { 522 pMsg(ERR, args, "ACTUAL:\n"); 523 if (fpDumpFile) 524 fprintf(fpDumpFile, DMFILESTR, "ACTUAL", args->device, 525 tPosition, offset); 526 } else if (oper == REREAD) { 527 pMsg(ERR, args, "REREAD ACTUAL:\n"); 528 if (fpDumpFile) 529 fprintf(fpDumpFile, DMFILESTR, "REREAD ACTUAL", 530 args->device, tPosition, offset); 531 } 532 533 dump_data(stdout, data, 16, 16, offset, FMT_STR); 534 if (fpDumpFile) 535 dump_data(fpDumpFile, data, buf_len, 16, 0, FMT_STR); 536 if (fpDumpFile) 537 fclose(fpDumpFile); 538 } 539 540 /* 541 * called after all the checks have been made to verify 542 * that the io completed successfully. 543 */ 544 void complete_io(test_env_t * env, const child_args_t * args, 545 const action_t target) 546 { 547 unsigned char *wbitmap = (unsigned char *)env->shared_mem + BMP_OFFSET; 548 int i = 0; 549 550 if (target.oper == WRITER) { 551 (env->hbeat_stats.wbytes) += target.trsiz * BLK_SIZE; 552 env->hbeat_stats.wcount++; 553 for (i = 0; i < target.trsiz; i++) { 554 *(wbitmap + 555 (((target.lba - args->offset - args->start_lba) + 556 i) / 8)) |= 557 0x80 >> (((target.lba - args->offset - args->start_lba) + i) % 558 8); 559 } 560 } else { 561 (env->hbeat_stats.rbytes) += target.trsiz * BLK_SIZE; 562 env->hbeat_stats.rcount++; 563 } 564 if (args->flags & CLD_FLG_LBA_SYNC) { 565 remove_action(env, target); 566 } 567 } 568 569 /* 570 * This function is really the main function for a thread 571 * Once here, this function will act as if it 572 * were 'main' for that thread. 573 */ 574 #ifdef WINDOWS 575 DWORD WINAPI ChildMain(test_ll_t * test) 576 #else 577 void *ChildMain(void *vtest) 578 #endif 579 { 580 #ifndef WINDOWS 581 test_ll_t *test = (test_ll_t *) vtest; 582 #endif 583 584 child_args_t *args = test->args; 585 test_env_t *env = test->env; 586 587 static int thread_id = 0; 588 int this_thread_id = thread_id++; 589 char *buf1 = NULL, *buffer1 = NULL; /* 'buf' is the aligned 'buffer' */ 590 char *buf2 = NULL, *buffer2 = NULL; /* 'buf' is the aligned 'buffer' */ 591 unsigned long ulLastError; 592 unsigned long delayTime; 593 594 action_t target = { NONE, 0, 0 }; 595 unsigned int i; 596 OFF_T ActualBytePos = 0, TargetBytePos = 0, mask = 1, delayMask = 1; 597 long tcnt = 0; 598 int exit_code = 0, rv = 0; 599 char filespec[DEV_NAME_LEN]; 600 fd_t fd; 601 602 unsigned int retries = 0; 603 BOOL is_retry = FALSE; 604 lvl_t msg_level = WARN; 605 int SET_CHAR = 0; /* when data buffers are cleared, using memset, use this */ 606 607 extern unsigned long glb_flags; 608 extern unsigned short glb_run; 609 extern int signal_action; 610 611 #ifdef WINDOWS 612 HANDLE MutexMISCOMP; 613 614 if ((MutexMISCOMP = OpenMutex(SYNCHRONIZE, TRUE, "gbl")) == NULL) { 615 pMsg(ERR, args, 616 "Thread %d: Failed to open semaphore, error = %u\n", 617 this_thread_id, GetLastError()); 618 args->test_state = SET_STS_FAIL(args->test_state); 619 TEXIT(GETLASTERROR()); 620 } 621 #else 622 static pthread_mutex_t MutexMISCOMP = PTHREAD_MUTEX_INITIALIZER; 623 #endif 624 625 /* 626 * For some messages, the error level will change, based on if 627 * the test should continue on error, or stop on error. 628 */ 629 if ((args->flags & CLD_FLG_ALLDIE) || (glb_flags & GLB_FLG_KILL)) { 630 msg_level = ERR; 631 } 632 633 target.oper = TST_OPER(args->test_state); 634 635 strncpy(filespec, args->device, DEV_NAME_LEN); 636 637 fd = Open(filespec, args->flags); 638 if (INVALID_FD(fd)) { 639 pMsg(ERR, args, "Thread %d: could not open %s, errno = %u.\n", 640 this_thread_id, args->device, GETLASTERROR()); 641 args->test_state = SET_STS_FAIL(args->test_state); 642 TEXIT((uintptr_t) GETLASTERROR()); 643 } 644 645 /* Create aligned memory buffers for sending IO. */ 646 if ((buffer1 = 647 (char *)ALLOC(((args->htrsiz * BLK_SIZE) + ALIGNSIZE))) == NULL) { 648 pMsg(ERR, args, 649 "Thread %d: Memory allocation failure for IO buffer, errno = %u\n", 650 this_thread_id, GETLASTERROR()); 651 args->test_state = SET_STS_FAIL(args->test_state); 652 CLOSE(fd); 653 TEXIT((uintptr_t) GETLASTERROR()); 654 } 655 memset(buffer1, SET_CHAR, ((args->htrsiz * BLK_SIZE) + ALIGNSIZE)); 656 buf1 = (char *)BUFALIGN(buffer1); 657 658 if ((buffer2 = 659 (char *)ALLOC(((args->htrsiz * BLK_SIZE) + ALIGNSIZE))) == NULL) { 660 pMsg(ERR, args, 661 "Thread %d: Memory allocation failure for IO buffer, errno = %u\n", 662 this_thread_id, GETLASTERROR()); 663 FREE(buffer1); 664 args->test_state = SET_STS_FAIL(args->test_state); 665 CLOSE(fd); 666 TEXIT((uintptr_t) GETLASTERROR()); 667 } 668 memset(buffer2, SET_CHAR, ((args->htrsiz * BLK_SIZE) + ALIGNSIZE)); 669 buf2 = (char *)BUFALIGN(buffer2); 670 671 /* set up lba mask of all 1's with value between vsiz and 2*vsiz */ 672 while (mask <= (args->stop_lba - args->start_lba)) { 673 mask = mask << 1; 674 } 675 mask -= 1; 676 677 /* set up delay mask of all 1's with value between delayTimeMin and 2*delayTimeMax */ 678 while (delayMask <= (args->delayTimeMax - args->delayTimeMin)) { 679 delayMask = delayMask << 1; 680 } 681 delayMask -= 1; 682 683 while (env->bContinue) { 684 if (!is_retry) { 685 retries = args->retries; 686 #ifdef _DEBUG 687 PDBG5(DBUG, args, 688 "Thread %d: lastAction: oper: %d, lba: %lld, trsiz: %ld\n", 689 this_thread_id, target.oper, target.lba, 690 target.trsiz); 691 #endif 692 do { 693 if (signal_action & SIGNAL_STOP) { 694 break; 695 } /* user request to stop */ 696 if (glb_run == 0) { 697 break; 698 } /* global request to stop */ 699 LOCK(env->mutexs.MutexACTION); 700 target = get_next_action(args, env, mask); 701 UNLOCK(env->mutexs.MutexACTION); 702 /* this thread has to retry, so give up the reset of my time slice */ 703 if (target.oper == RETRY) { 704 Sleep(0); 705 } 706 } while ((env->bContinue) && (target.oper == RETRY)); /* we failed to get an action, and were asked to retry */ 707 708 #ifdef _DEBUG 709 PDBG5(DBUG, args, 710 "Thread %d: nextAction: oper: %d, lba: %lld, trsiz: %ld\n", 711 this_thread_id, target.oper, target.lba, 712 target.trsiz); 713 #endif 714 715 /* 716 * Delay delayTime msecs before continuing, for simulated 717 * processing time, requested by user 718 */ 719 720 if (args->delayTimeMin == args->delayTimeMax) { /* static delay time */ 721 /* only sleep if delay is greater then zero */ 722 if (args->delayTimeMin > 0) { 723 Sleep(args->delayTimeMin); 724 } 725 } else { /* random delay time between min & max */ 726 do { 727 delayTime = 728 (unsigned long)(rand() & delayMask) 729 + args->delayTimeMin; 730 } while (delayTime > args->delayTimeMax); 731 #ifdef _DEBUG 732 PDBG3(DBUG, args, 733 "Thread %d: Delay time = %lu\n", 734 this_thread_id, delayTime); 735 #endif 736 Sleep(delayTime); 737 } 738 } 739 #ifdef _DEBUG 740 if (target.oper == NONE) { /* nothing left to do */ 741 PDBG3(DBUG, args, 742 "Thread %d: Setting break, oper is NONE\n", 743 this_thread_id); 744 } 745 #endif 746 747 if (target.oper == NONE) { 748 break; 749 } /* nothing left so stop */ 750 if (signal_action & SIGNAL_STOP) { 751 break; 752 } /* user request to stop */ 753 if (env->bContinue == FALSE) { 754 break; 755 } /* internal request to stop */ 756 if (glb_run == 0) { 757 break; 758 } 759 /* global request to stop */ 760 TargetBytePos = (OFF_T) (target.lba * BLK_SIZE); 761 ActualBytePos = Seek(fd, TargetBytePos); 762 if (ActualBytePos != TargetBytePos) { 763 ulLastError = GETLASTERROR(); 764 pMsg(msg_level, args, SFSTR, this_thread_id, 765 (target.oper == 766 WRITER) ? (env->wcount) : (env->rcount), 767 target.lba, TargetBytePos, ActualBytePos, 768 ulLastError); 769 if (retries-- > 1) { /* request to retry on error, decrement retry */ 770 pMsg(INFO, args, 771 "Thread %d: Retry after seek failure, retry count: %u\n", 772 this_thread_id, retries); 773 is_retry = TRUE; 774 Sleep(args->retry_delay); 775 } else { 776 exit_code = SEEK_FAILURE; 777 is_retry = FALSE; 778 LOCK(env->mutexs.MutexACTION); 779 update_test_state(args, env, this_thread_id, fd, 780 buf2); 781 decrement_io_count(args, env, target); 782 UNLOCK(env->mutexs.MutexACTION); 783 } 784 continue; 785 } 786 787 if (target.oper == WRITER) { 788 if (args->flags & CLD_FLG_LPTYPE) { 789 fill_buffer(buf2, target.trsiz, &(target.lba), 790 sizeof(OFF_T), CLD_FLG_LPTYPE); 791 } else { 792 memcpy(buf2, env->data_buffer, 793 target.trsiz * BLK_SIZE); 794 } 795 if (args->flags & CLD_FLG_MBLK) { 796 mark_buffer(buf2, target.trsiz * BLK_SIZE, 797 &(target.lba), args, env); 798 } 799 #ifdef _DEBUG 800 setStartTime(); 801 #endif 802 if (args->flags & CLD_FLG_IO_SERIAL) { 803 LOCK(env->mutexs.MutexIO); 804 tcnt = Write(fd, buf2, target.trsiz * BLK_SIZE); 805 UNLOCK(env->mutexs.MutexIO); 806 } else { 807 tcnt = Write(fd, buf2, target.trsiz * BLK_SIZE); 808 } 809 810 #ifdef _DEBUG 811 setEndTime(); 812 PDBG5(DBUG, args, "Thread %d: I/O Time: %ld usecs\n", 813 this_thread_id, getTimeDiff()); 814 #endif 815 if (args->flags & CLD_FLG_WFSYNC) { 816 rv = 0; 817 /* if need to sync, then only have one thread do it */ 818 LOCK(env->mutexs.MutexACTION); 819 if (0 == 820 (env->hbeat_stats.wcount % 821 args->sync_interval)) { 822 #ifdef _DEBUG 823 PDBG3(DBUG, args, 824 "Thread %d: Performing sync, write IO count %llu\n", 825 this_thread_id, 826 env->hbeat_stats.wcount); 827 #endif 828 rv = Sync(fd); 829 if (0 != rv) { 830 exit_code = GETLASTERROR(); 831 pMsg(msg_level, args, 832 "Thread %d: fsync error = %d\n", 833 this_thread_id, exit_code); 834 is_retry = FALSE; 835 update_test_state(args, env, 836 this_thread_id, 837 fd, buf2); 838 decrement_io_count(args, env, 839 target); 840 } 841 } 842 UNLOCK(env->mutexs.MutexACTION); 843 844 if (0 != rv) { /* sync error, so don't count the write */ 845 continue; 846 } 847 } 848 } 849 850 if (target.oper == READER) { 851 memset(buf1, SET_CHAR, target.trsiz * BLK_SIZE); 852 #ifdef _DEBUG 853 setStartTime(); 854 #endif 855 if (args->flags & CLD_FLG_IO_SERIAL) { 856 LOCK(env->mutexs.MutexIO); 857 tcnt = Read(fd, buf1, target.trsiz * BLK_SIZE); 858 UNLOCK(env->mutexs.MutexIO); 859 } else { 860 tcnt = Read(fd, buf1, target.trsiz * BLK_SIZE); 861 } 862 #ifdef _DEBUG 863 setEndTime(); 864 PDBG5(DBUG, args, "Thread %d: I/O Time: %ld usecs\n", 865 this_thread_id, getTimeDiff()); 866 #endif 867 } 868 869 if (tcnt != (long)target.trsiz * BLK_SIZE) { 870 ulLastError = GETLASTERROR(); 871 pMsg(msg_level, args, AFSTR, this_thread_id, 872 (target.oper) ? "Read" : "Write", 873 (target.oper) ? (env->rcount) : (env->wcount), 874 target.lba, target.lba, tcnt, 875 target.trsiz * BLK_SIZE, ulLastError); 876 if (retries-- > 1) { /* request to retry on error, decrement retry */ 877 pMsg(INFO, args, 878 "Thread %d: Retry after transfer failure, retry count: %u\n", 879 this_thread_id, retries); 880 is_retry = TRUE; 881 Sleep(args->retry_delay); 882 } else { 883 exit_code = ACCESS_FAILURE; 884 is_retry = FALSE; 885 LOCK(env->mutexs.MutexACTION); 886 update_test_state(args, env, this_thread_id, fd, 887 buf2); 888 decrement_io_count(args, env, target); 889 UNLOCK(env->mutexs.MutexACTION); 890 } 891 continue; 892 } 893 894 /* data compare routine. Act as if we were to write, but just compare */ 895 if ((target.oper == READER) && (args->flags & CLD_FLG_CMPR)) { 896 /* This is very SLOW!!! */ 897 if ((args->cmp_lng == 0) 898 || (args->cmp_lng > target.trsiz * BLK_SIZE)) { 899 args->cmp_lng = target.trsiz * BLK_SIZE; 900 } 901 if (args->flags & CLD_FLG_LPTYPE) { 902 fill_buffer(buf2, target.trsiz, &(target.lba), 903 sizeof(OFF_T), CLD_FLG_LPTYPE); 904 } else { 905 memcpy(buf2, env->data_buffer, 906 target.trsiz * BLK_SIZE); 907 } 908 if (args->flags & CLD_FLG_MBLK) { 909 mark_buffer(buf2, target.trsiz * BLK_SIZE, 910 &(target.lba), args, env); 911 } 912 if (memcmp(buf2, buf1, args->cmp_lng) != 0) { 913 /* data miscompare, this takes lots of time, but its OK... !!! */ 914 LOCK(MutexMISCOMP); 915 pMsg(ERR, args, DMSTR, this_thread_id, 916 target.lba, target.lba); 917 /* find the actual byte that started the miscompare */ 918 for (i = 0; i < args->htrsiz * BLK_SIZE; i++) { 919 if (*(buf2 + i) != *(buf1 + i)) { 920 pMsg(ERR, args, DMOFFSTR, 921 this_thread_id, i, i); 922 break; 923 } 924 } 925 miscompare_dump(args, buf2, 926 args->htrsiz * BLK_SIZE, 927 target.lba, i, EXP, 928 this_thread_id); 929 miscompare_dump(args, buf1, 930 args->htrsiz * BLK_SIZE, 931 target.lba, i, ACT, 932 this_thread_id); 933 /* perform a reread of the target, if requested */ 934 if (args->flags & CLD_FLG_ERR_REREAD) { 935 ActualBytePos = Seek(fd, TargetBytePos); 936 if (ActualBytePos == TargetBytePos) { 937 memset(buf1, SET_CHAR, 938 target.trsiz * BLK_SIZE); 939 #ifdef _DEBUG 940 setStartTime(); 941 #endif 942 tcnt = 943 Read(fd, buf1, 944 target.trsiz * 945 BLK_SIZE); 946 #ifdef _DEBUG 947 setEndTime(); 948 PDBG5(DBUG, args, 949 "Thread %d: ReRead I/O Time: %ld usecs\n", 950 this_thread_id, 951 getTimeDiff()); 952 #endif 953 if (tcnt != 954 (long)target.trsiz * 955 BLK_SIZE) { 956 pMsg(ERR, args, 957 "Thread %d: ReRead after data miscompare failed on transfer.\n", 958 this_thread_id); 959 pMsg(ERR, args, AFSTR, 960 this_thread_id, 961 "ReRead", 962 (target. 963 oper) ? (env-> 964 rcount) 965 : (env->wcount), 966 target.lba, 967 target.lba, tcnt, 968 target.trsiz * 969 BLK_SIZE); 970 } 971 miscompare_dump(args, buf1, 972 args->htrsiz * 973 BLK_SIZE, 974 target.lba, i, 975 REREAD, 976 this_thread_id); 977 } else { 978 pMsg(ERR, args, 979 "Thread %d: ReRead after data miscompare failed on seek.\n", 980 this_thread_id); 981 pMsg(ERR, args, SFSTR, 982 this_thread_id, 983 (target.oper == 984 WRITER) ? (env-> 985 wcount) 986 : (env->rcount), 987 target.lba, TargetBytePos, 988 ActualBytePos); 989 } 990 } 991 UNLOCK(MutexMISCOMP); 992 993 exit_code = DATA_MISCOMPARE; 994 is_retry = FALSE; 995 LOCK(env->mutexs.MutexACTION); 996 update_test_state(args, env, this_thread_id, fd, 997 buf2); 998 decrement_io_count(args, env, target); 999 UNLOCK(env->mutexs.MutexACTION); 1000 continue; 1001 } 1002 } 1003 1004 /* update stats, bitmap, and release LBA */ 1005 LOCK(env->mutexs.MutexACTION); 1006 complete_io(env, args, target); 1007 UNLOCK(env->mutexs.MutexACTION); 1008 1009 is_retry = FALSE; 1010 } 1011 1012 #ifdef _DEBUG 1013 #ifdef _DEBUG_PRINTMAP 1014 LOCK(env->mutexs.MutexACTION); 1015 print_lba_bitmap(env); 1016 UNLOCK(env->mutexs.MutexACTION); 1017 #endif 1018 #endif 1019 1020 FREE(buffer1); 1021 FREE(buffer2); 1022 1023 if ((args->flags & CLD_FLG_W) && !(args->flags & CLD_FLG_RAW)) { 1024 #ifdef _DEBUG 1025 PDBG5(DBUG, args, "Thread %d: starting sync\n", this_thread_id); 1026 #endif 1027 if (Sync(fd) < 0) { /* just sync, should not matter the device type */ 1028 exit_code = GETLASTERROR(); 1029 pMsg(ERR, args, "Thread %d: fsync error = %d\n", 1030 this_thread_id, exit_code); 1031 args->test_state = SET_STS_FAIL(args->test_state); 1032 } 1033 #ifdef _DEBUG 1034 PDBG5(DBUG, args, "Thread %d: finished sync\n", this_thread_id); 1035 #endif 1036 } 1037 1038 if (CLOSE(fd) < 0) { /* check return status on close */ 1039 exit_code = GETLASTERROR(); 1040 pMsg(ERR, args, "Thread %d: close error = %d\n", this_thread_id, 1041 exit_code); 1042 args->test_state = SET_STS_FAIL(args->test_state); 1043 } 1044 1045 TEXIT((uintptr_t) exit_code); 1046 } 1047