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