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@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 */
action_in_use(const test_env_t * env,const action_t target)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
add_action(test_env_t * env,const child_args_t * args,const action_t target)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
remove_action(test_env_t * env,const action_t target)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
decrement_io_count(const child_args_t * args,test_env_t * env,const action_t target)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 */
write_error_mark(fd_t fd,char * data)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 */
update_test_state(child_args_t * args,test_env_t * env,const int this_thread_id,fd_t fd,char * data)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
print_lba_bitmap(const test_env_t * env)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
get_next_action(child_args_t * args,test_env_t * env,const OFF_T mask)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
miscompare_dump(const child_args_t * args,const char * data,const size_t buf_len,OFF_T tPosition,const size_t offset,mc_func_t oper,const int this_thread_id)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 */
complete_io(test_env_t * env,const child_args_t * args,const action_t target)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
ChildMain(test_ll_t * test)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