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 */
67unsigned 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
99void 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
112void 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
141void 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 */
159void 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 */
179void 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
211void 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
224action_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
492void 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 */
544void 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
575DWORD WINAPI ChildMain(test_ll_t * test)
576#else
577void *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