Beispiel #1
0
Datei: main.c Projekt: 1587/ltp
void *threadedMain(void *vtest)
#endif
{
#ifndef WINDOWS
	test_ll_t *test = (test_ll_t *) vtest;
#endif

	OFF_T *pVal1;
	unsigned char *data_buffer_unaligned = NULL;
	unsigned long ulRV;
	int i;
	unsigned char *sharedMem;

	extern unsigned short glb_run;
	extern int signal_action;

	test->args->pid = GETPID();

	init_gbl_data(test->env);

	if (make_assumptions(test->args) < 0) {
		TEXIT((uintptr_t) GETLASTERROR());
	}
	if (check_conclusions(test->args) < 0) {
		TEXIT((uintptr_t) GETLASTERROR());
	}
	if (test->args->flags & CLD_FLG_DUMP) {
		/*
		 * All we are doing is dumping filespec data to STDOUT, so
		 * we will do this here and be done.
		 */
		do_dump(test->args);
		TEXIT((uintptr_t) GETLASTERROR());
	} else {
		ulRV = init_data(test, &data_buffer_unaligned);
		if (ulRV != 0) {
			TEXIT(ulRV);
		}
		pVal1 = (OFF_T *) test->env->shared_mem;
	}

	pMsg(START, test->args, "Start args: %s\n", test->args->argstr);

	/*
	 * This loop takes care of passes
	 */
	do {
		test->env->pass_count++;
		test->env->start_time = time(NULL);
		if (test->args->flags & CLD_FLG_RPTYPE) {	/* force random data to be different each cycle */
			fill_buffer(test->env->data_buffer,
				    ((test->args->htrsiz * BLK_SIZE) * 2), NULL,
				    0, CLD_FLG_RPTYPE);
		}
		sharedMem = test->env->shared_mem;
		memset(sharedMem + BMP_OFFSET, 0, test->env->bmp_siz);
		if ((test->args->flags & CLD_FLG_LINEAR)
		    && !(test->args->flags & CLD_FLG_NTRLVD)) {
			linear_read_write_test(test);
		} else {
			/* we only reset the end time if not running a linear read / write test */
			test->env->end_time =
			    test->env->start_time + test->args->run_time;
			test->env->bContinue = TRUE;
			*(pVal1 + OFF_WLBA) = test->args->start_lba;
			test->args->test_state =
			    DIRCT_INC(test->args->test_state);
			test->args->test_state =
			    SET_wFST_TIME(test->args->test_state);
			test->args->test_state =
			    SET_rFST_TIME(test->args->test_state);
			if (test->args->flags & CLD_FLG_W) {
				test->env->lastAction.oper = WRITER;
				test->args->test_state =
				    SET_OPER_W(test->args->test_state);
			} else {
				test->env->lastAction.oper = READER;
				test->args->test_state =
				    SET_OPER_R(test->args->test_state);
			}
			memset(test->env->action_list, 0,
			       sizeof(action_t) * test->args->t_kids);
			test->env->action_list_entry = 0;
			test->env->wcount = 0;
			test->env->rcount = 0;

			if (test->args->flags & CLD_FLG_CYC)
				if (test->args->cycles == 0) {
					pMsg(INFO, test->args,
					     "Starting pass %lu\n",
					     (unsigned long)test->env->
					     pass_count);
				} else {
					pMsg(INFO, test->args,
					     "Starting pass %lu of %lu\n",
					     (unsigned long)test->env->
					     pass_count, test->args->cycles);
			} else {
				pMsg(INFO, test->args, "Starting pass\n");
			}

			CreateTestChild(ChildTimer, test);
			for (i = 0; i < test->args->t_kids; i++) {
				CreateTestChild(ChildMain, test);
			}
			/* Wait for the children to finish */
			cleanUpTestChildren(test);
		}

		update_cyc_stats(test->env);
		if ((test->args->flags & CLD_FLG_CYC)
		    && (test->args->flags & CLD_FLG_PCYC)) {
			print_stats(test->args, test->env, CYCLE);
		}
		update_gbl_stats(test->env);

		if (signal_action & SIGNAL_STOP) {
			break;
		}		/* user request to stop */
		if ((glb_run == 0)) {
			break;
		}
		/* global request to stop */
		if (!(test->args->flags & CLD_FLG_CYC)) {
			break;	/* leave, unless cycle testing */
		} else {
			if ((test->args->cycles > 0)
			    && (test->env->pass_count >= test->args->cycles)) {
				break;	/* leave, cycle testing complete */
			}
		}
	} while (TST_STS(test->args->test_state));
	print_stats(test->args, test->env, TOTAL);

	FREE(data_buffer_unaligned);
	FREE(test->env->shared_mem);
#ifdef WINDOWS
	CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "gbl"));
	CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "data"));
#endif

	if (TST_STS(test->args->test_state)) {
		if (signal_action & SIGNAL_STOP) {
			pMsg(END, test->args,
			     "User Interrupt: Test Done (Passed)\n");
		} else {
			pMsg(END, test->args, "Test Done (Passed)\n");
		}
	} else {
		if (signal_action & SIGNAL_STOP) {
			pMsg(END, test->args,
			     "User Interrupt: Test Done (Failed)\n");
		} else {
			pMsg(END, test->args, "Test Done (Failed)\n");
		}
	}
	TEXIT((uintptr_t) GETLASTERROR());
}
Beispiel #2
0
/*
 * checks validity of data after parsing
 * args and make assumtions. returns 0 on
 * success and -1 on failure.
 */
int check_conclusions(child_args_t * args)
{
	extern unsigned long glb_flags;
	struct stat stat_buf;
	int rv;

	if ((args->flags & CLD_FLG_DUTY)
	    && ((args->flags & CLD_FLG_LINEAR)
		|| (args->flags & CLD_FLG_NTRLVD))) {
		pMsg(WARN, args,
		     "Duty cycle testing is supported for random (-pR) tests only.\n");
		return (-1);
	}
	if ((args->flags & CLD_FLG_BLK_RNG) && (args->flags & CLD_FLG_RTRSIZ)) {
		pMsg(WARN, args,
		     "Can't have unfixed block sizes and specify seek range in terms of blocks.\n");
		return (-1);
	}
	if ((args->vsiz < 0) || (args->ltrsiz < 1) || (args->htrsiz < 1)) {
		pMsg(WARN, args,
		     "Bounds exceeded for transfer size and/or volume size.\n");
		pMsg(WARN, args, MAXTRSIZ, (args->htrsiz * BLK_SIZE),
		     args->vsiz);
		return (-1);
	}
	if (args->htrsiz < args->ltrsiz) {
		pMsg(ERR, args,
		     "Min transfer size, %lu, greater then Max transfer size, %lu.\n",
		     args->ltrsiz, args->htrsiz);
		return (-1);
	}
	if (args->vsiz < (args->stop_lba - args->start_lba + 1)) {
		pMsg(ERR, args, "Volume stop block/lba exceeds volume size.\n");
		return (-1);
	}
	if (args->vsiz < args->htrsiz) {
		pMsg(WARN, args, VSIZETS, args->vsiz, args->htrsiz);
		return (-1);
	}
	if ((args->flags & CLD_FLG_TMD) == 0 && (args->seeks <= 0)) {
		pMsg(WARN, args, TSEEK, args->seeks);
		return (-1);
	}
	if ((args->flags & CLD_FLG_SKS) && (args->t_kids > args->seeks)) {
		pMsg(WARN, args,
		     "Can't have more children then max number of seeks, use -K/-L to adjust.\n");
		return (-1);
	}
	if ((args->start_blk > args->vsiz)
	    && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
		pMsg(WARN, args, STBGTTLBA, args->start_blk,
		     (args->vsiz / args->htrsiz));
		return (-1);
	}
	if ((args->stop_blk > args->vsiz)
	    && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
		pMsg(WARN, args, SBGTTLBA, args->stop_blk,
		     (args->vsiz / args->htrsiz));
		return (-1);
	}
	if ((args->start_lba > args->vsiz)
	    && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
		pMsg(WARN, args, STLBAGTLBA, args->start_lba, args->vsiz);
		return (-1);
	}
	if ((args->stop_lba > args->vsiz)
	    && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
		pMsg(WARN, args, SLBAGTLBA, args->stop_lba, args->vsiz);
		return (-1);
	}
	if (args->start_blk > args->stop_blk) {
		pMsg(WARN, args, SBRSB, args->stop_blk, args->start_blk);
		return (-1);
	}
	if (args->start_lba > args->stop_lba) {
		pMsg(ERR, args, SLBARSLBA, args->stop_lba, args->start_lba);
		return (-1);
	}
	if ((args->flags & CLD_FLG_LBA_RNG) && (args->flags & CLD_FLG_BLK_RNG)) {
		pMsg(ERR, args,
		     "Can't specify range in both block and LBA, use -s or -S.\n");
		return (-1);
	}

	/* use stat to get file properties, and test then agains specified -I */
	rv = stat(args->device, &stat_buf);
	if (0 == rv) {		/* no error on call to stat, compare against -I option */
		/* files are usually file type */
		if ((args->flags & CLD_FLG_FILE) && !IS_FILE(stat_buf.st_mode)) {
			pMsg(ERR, args,
			     "Can't open non-file filespec with file device type, -If.\n");
			return (-1);
		}
		/* block devices, are usually block type */
		if ((args->flags & CLD_FLG_BLK) && !IS_BLK(stat_buf.st_mode)) {
			pMsg(ERR, args,
			     "Can't open non-block filespec with block device type, -Ib.\n");
			return (-1);
		}
#ifndef WINDOWS
		/* raw devices, are usually character type */
		if ((args->flags & CLD_FLG_RAW) && !S_ISCHR(stat_buf.st_mode)) {
			pMsg(ERR, args,
			     "Can't open non-raw filespec with raw device type, -Ir.\n");
			return (-1);
		}
#else
		if (args->flags & CLD_FLG_RAW) {
			pMsg(ERR, args,
			     "RAW IO type not supported in Windows, use direct IO instead.\n");
			return (-1);
		}
#endif
#ifdef _DEBUG
	} else {
		PDBG1(DBUG, args,
		      "Can't get status on %s, assuming a new file, errno = %d\n",
		      args->device, GETLASTERROR());
#endif
	}

	if ((args->hbeat > 0) && (args->flags & CLD_FLG_TMD)
	    && (args->hbeat > args->run_time)) {
		pMsg(ERR, args,
		     "Heartbeat should be at least equal to runtime, use -h/-T to adjust.\n");
		return (-1);
	}
	if ((args->hbeat > 0) && !(args->flags & CLD_FLG_PRFTYPS)) {
		pMsg(ERR, args,
		     "At least one performance option, -P, must be specified when using -h.\n");
		return (-1);
	}
	if ((args->flags & CLD_FLG_W) && !(args->flags & CLD_FLG_R)
	    && (args->flags & CLD_FLG_CMPR)) {
		pMsg(ERR, args, "Write only, ignoring option -E.\n");
	}
	if ((args->flags & CLD_FLG_TMD) && (args->flags & CLD_FLG_SKS)) {
		pMsg(ERR, args,
		     "Can't specify both -L and -T they are mutually exclusive.\n");
		return (-1);
	}
	if (((args->flags & CLD_FLG_R) && !(args->flags & CLD_FLG_W))
	    && (args->flags & CLD_FLG_ERR_MARK)) {
		pMsg(ERR, args,
		     "Can't specify mark on error, -Am, in read only mode.\n");
		return (-1);
	}
	if (!(args->flags & CLD_FLG_ALLDIE) && (args->flags & CLD_FLG_ERR_MARK)) {
		pMsg(ERR, args,
		     "Can't specify mark on error, -Am, when continue on error is set.\n");
		return (-1);
	}
	if ((glb_flags & GLB_FLG_KILL) && !(args->flags & CLD_FLG_ALLDIE)) {
		pMsg(ERR, args,
		     "Can't specify global kill, -Ag, when continue on error is set, -Ac.\n");
		return (-1);
	}
	if ((args->flags & CLD_FLG_LINEAR) && !(args->flags & CLD_FLG_NTRLVD)
	    && (args->flags & CLD_FLG_TMD)) {
		pMsg(ERR, args, "Linear read / write test can not be timed.\n");
		return (-1);
	}
	if ((args->flags & CLD_FLG_CMPR)
	    && (args->cmp_lng > (args->ltrsiz * BLK_SIZE))) {
		pMsg(ERR, args,
		     "Compare length, %lu, is greater then transfer size, %lu\n",
		     args->cmp_lng, args->ltrsiz * BLK_SIZE);
		return (-1);
	}
	if ((args->flags & CLD_FLG_OFFSET) && (args->offset > args->stop_lba)) {
		pMsg(ERR, args, LBAOFFGSLBA, args->offset, args->stop_lba);
		return (-1);
	}
	if ((args->flags & CLD_FLG_OFFSET)
	    && ((args->offset + args->ltrsiz - 1) > args->stop_lba)) {
		pMsg(ERR, args, LBAOTSGSLBA, args->offset, args->ltrsiz,
		     args->stop_lba);
		return (-1);
	}
	return 0;
}
Beispiel #3
0
void *ChildTimer(void *vtest)
#endif
{
#ifndef WINDOWS
	test_ll_t *test = (test_ll_t *) vtest;
#endif
	time_t ioTimeoutCount = 0;
	time_t total_time = 0;
	OFF_T cur_total_io_count = 0;
	OFF_T last_total_io_count = 0;

	OFF_T tmp_io_count = 0;
	time_t run_time = 0;

	lvl_t msg_level = WARN;

	child_args_t *args = test->args;
	test_env_t *env = test->env;

	extern int signal_action;
	extern unsigned short glb_run;

#ifdef _DEBUG
	PDBG3(DBUG, args, "In timer %lu, %d\n", time(NULL), env->bContinue);
#endif
	do {
		Sleep(1000);
		run_time++;
#ifdef _DEBUG
		PDBG3(DBUG, args, "Continue timing %lu, %lu, %d\n", time(NULL),
		      run_time, env->bContinue);
#endif
		if (args->flags & CLD_FLG_W) {
			if ((args->flags & CLD_FLG_LINEAR)
			    && !(args->flags & CLD_FLG_NTRLVD)) {
				if (TST_OPER(args->test_state) == WRITER) {
					env->hbeat_stats.wtime++;
				}
			} else {
				env->hbeat_stats.wtime++;
			}
		}
		if (args->flags & CLD_FLG_R) {
			if ((args->flags & CLD_FLG_LINEAR)
			    && !(args->flags & CLD_FLG_NTRLVD)) {
				if (TST_OPER(args->test_state) == READER) {
					env->hbeat_stats.rtime++;
				}
			} else {
				env->hbeat_stats.rtime++;
			}
		}

		/*
		 * Check to see if we have made any IO progress in the last interval,
		 * if not incremment the ioTimeout timer, otherwise, clear it
		 */
		cur_total_io_count = env->global_stats.wcount
		    + env->cycle_stats.wcount
		    + env->hbeat_stats.wcount
		    + env->global_stats.rcount
		    + env->cycle_stats.rcount + env->hbeat_stats.rcount;

		if (cur_total_io_count == 0) {
			tmp_io_count = 1;
		} else {
			tmp_io_count = cur_total_io_count;
		}

		total_time = env->global_stats.rtime
		    + env->cycle_stats.rtime
		    + env->hbeat_stats.rtime
		    + env->global_stats.wtime
		    + env->cycle_stats.wtime + env->hbeat_stats.wtime;

#ifdef _DEBUG
		PDBG3(DBUG, args, "average number of seconds per IO: %0.8lf\n",
		      ((double)(total_time) / (double)(tmp_io_count)));
#endif

		if (cur_total_io_count == last_total_io_count) {	/* no IOs completed in interval */
			if (0 == (++ioTimeoutCount % args->ioTimeout)) {	/* no progress after modulo ioTimeout interval */
				if (args->flags & CLD_FLG_TMO_ERROR) {
					args->test_state =
					    SET_STS_FAIL(args->test_state);
					env->bContinue = FALSE;
					msg_level = ERR;
				}
				pMsg(msg_level, args,
				     "Possible IO hang condition, IO timeout reached, %lu seconds\n",
				     args->ioTimeout);
			}
#ifdef _DEBUG
			PDBG3(DBUG, args, "io timeout count: %lu\n",
			      ioTimeoutCount);
#endif
		} else {
			ioTimeoutCount = 0;
			last_total_io_count = cur_total_io_count;
#ifdef _DEBUG
			PDBG3(DBUG, args, "io timeout reset\n");
#endif
		}

		if (((args->hbeat > 0) && ((run_time % args->hbeat) == 0))
		    || (signal_action & SIGNAL_STAT)) {
			print_stats(args, env, HBEAT);
			update_cyc_stats(env);
			clear_stat_signal();
		}

		if (glb_run == 0) {
			break;
		}		/* global run flag cleared */
		if (signal_action & SIGNAL_STOP) {
			break;
		}
		/* 超过设定的时间 */
		/* user request to stop */
		if (args->flags & CLD_FLG_TMD) {	/* if timing */
			if (run_time >= args->run_time) {	/* and run time exceeded */
				break;
			}
		} else {	/* if not timing */
			if (env->kids <= 1) {	/* and the timer is the only child */
				break;
			}
		}
	} while (TRUE);
#ifdef _DEBUG
	PDBG3(DBUG, args, "Out of timer %lu, %lu, %d, %d\n", time(NULL),
	      run_time, env->bContinue, env->kids);
#endif

	if (args->flags & CLD_FLG_TMD) {	/* timed test, timer exit needs to stop io threads */
#ifdef _DEBUG
		PDBG3(DBUG, args,
		      "Setting bContinue to FALSE, timed test & timer exit\n");
#endif
		/* 设置此值,使工作线程不工作 */
		env->bContinue = FALSE;
	}

	TEXIT((uintptr_t) GETLASTERROR());
}
Beispiel #4
0
int make_assumptions(child_args_t * args)
{
	char TmpStr[80];
	struct stat stat_buf;
	int rv;

	if (!(args->flags & CLD_FLG_IOTYPS)) {
		/* use stat to get file properties, and use to set -I */
		rv = stat(args->device, &stat_buf);
		if (0 == rv) {
			if (IS_FILE(stat_buf.st_mode)) {
				strncat(args->argstr, "(-I f) ",
					(MAX_ARG_LEN - 1) -
					strlen(args->argstr));
				args->flags |= CLD_FLG_FILE;
			} else if (IS_BLK(stat_buf.st_mode)) {
				strncat(args->argstr, "(-I b) ",
					(MAX_ARG_LEN - 1) -
					strlen(args->argstr));
				args->flags |= CLD_FLG_BLK;
#ifndef WINDOWS
			} else if (S_ISCHR(stat_buf.st_mode)) {
				strncat(args->argstr, "(-I r) ",
					(MAX_ARG_LEN - 1) -
					strlen(args->argstr));
				args->flags |= CLD_FLG_RAW;
#endif
			}
		} else {
			pMsg(WARN, args,
			     "Can't get status on %s, defaulting to file, errno = %d\n",
			     args->device, GETLASTERROR());
			strncat(args->argstr, "(-I f) ",
				(MAX_ARG_LEN - 1) - strlen(args->argstr));
			args->flags |= CLD_FLG_FILE;
		}
	}
	if ((args->flags & CLD_FLG_WFSYNC) && (0 == args->sync_interval)) {
		pMsg(INFO, args,
		     "Sync interval set to zero, assuming interval of 1.\n");
		args->sync_interval = 1;
	}

	if (args->ltrsiz <= 0) {
		sprintf(TmpStr, "(-B %d) ", TRSIZ * BLK_SIZE);
		strncat(args->argstr, TmpStr,
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
		args->ltrsiz = TRSIZ;
		args->htrsiz = TRSIZ;
	}
	if (args->flags & CLD_FLG_LBA_RNG) {
		args->start_blk = args->start_lba / args->htrsiz;
		if (!(args->stop_lba < 0))
			args->stop_blk = args->stop_lba / args->htrsiz;
	}
	if (args->flags & CLD_FLG_BLK_RNG) {
		args->start_lba = args->start_blk * args->htrsiz;
		if (!(args->stop_blk < 0))
			args->stop_lba =
			    (args->stop_blk * args->htrsiz) + (args->htrsiz -
							       1);
	}
	/* if vsiz is still not set, try and get it from the file */
	if ((args->vsiz <= 0) && (args->flags & CLD_FLG_FILE)) {
		if (0 != get_file_size(args->device)) {	/* file size retrieved */
			args->vsiz = get_file_size(args->device);
		}
	}
	/* if vsiz is still not set, try and get it from the device */
	if ((args->vsiz <= 0) && !(args->flags & CLD_FLG_FILE)) {
		args->vsiz = get_vsiz(args->device);
	}
	/* if vsiz is still not set, set based on given range */
	if ((args->vsiz <= 0)
	    && (args->flags & (CLD_FLG_LBA_RNG | CLD_FLG_BLK_RNG))) {
		if (!(args->stop_lba < 0))
			args->vsiz = args->stop_lba + 1;
		else
			args->vsiz = args->start_lba + 1;
	}
	/* if vsiz is still not set, then set it to the default size */
	if (args->vsiz <= 0) {
		args->vsiz = VSIZ;
	}
	if (!(args->flags & CLD_FLG_VSIZ)) {
		sprintf(TmpStr, N_ASSUME, args->vsiz);
		strncat(args->argstr, TmpStr,
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
	}

	if (args->stop_lba == -1) {
		args->stop_lba = args->vsiz - 1;
	}
	if (args->stop_blk == -1) {
		args->stop_blk = (args->stop_lba / (OFF_T) args->htrsiz);
	}
	if (args->t_kids == 0) {
		sprintf(TmpStr, "(-K %d) ", KIDS);
		strncat(args->argstr, TmpStr,
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
		args->t_kids = KIDS;
	}
	if ((args->flags & (CLD_FLG_W | CLD_FLG_R)) == 0) {
		if (args->flags & CLD_FLG_DUTY) {	/* no read/write but duty cycle specified */
			if (args->rperc > 0) {
				args->flags |= CLD_FLG_R;
				strncat(args->argstr, "(-r) ",
					(MAX_ARG_LEN - 1) -
					strlen(args->argstr));
			}
			if (args->wperc > 0) {
				args->flags |= CLD_FLG_W;
				strncat(args->argstr, "(-w) ",
					(MAX_ARG_LEN - 1) -
					strlen(args->argstr));
			}
		} else {
			strncat(args->argstr, "(-r) ",
				(MAX_ARG_LEN - 1) - strlen(args->argstr));
			args->flags |= CLD_FLG_R;
		}
	}
	if (!(args->flags & CLD_FLG_PTYPS)) {
		strncat(args->argstr, "(-c) ",
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
		args->flags |= CLD_FLG_CPTYPE;
	}
	if (!(args->flags & CLD_FLG_SKTYPS)) {
		strncat(args->argstr, "(-p R) ",
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
		args->flags |= CLD_FLG_RANDOM;
	}
	if (!(args->flags & CLD_FLG_SKS)) {
		if (args->start_blk == args->stop_blk) {	/* diskcache test, w/ no seek count set */
			args->seeks = SEEKS;
		} else if (args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG)) {	/* range set, w/ no seek count */
			args->seeks = args->stop_blk - args->start_blk + 1;
		} else {
			/* if vsiz is available, calculated seeks are in terms of the largest transfer size */
			args->seeks =
			    (args->vsiz >
			     0) ? (args->vsiz / args->htrsiz) : SEEKS;
		}
		if ((args->flags & CLD_FLG_LINEAR) && (args->flags & CLD_FLG_R)
		    && (args->flags & CLD_FLG_W)) {
			args->seeks *= 2;
		}

		if (!(args->flags & CLD_FLG_TMD)) {
			sprintf(TmpStr, L_ASSUME, args->seeks);
			strncat(args->argstr, TmpStr,
				(MAX_ARG_LEN - 1) - strlen(args->argstr));
		}
	}
	if (!(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD))
	    || ((args->flags & CLD_FLG_CYC)
		&& !(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD)))) {
		args->flags |= CLD_FLG_SKS;
	}
	if (args->flags & (CLD_FLG_LINEAR)) {
		if (!(args->flags & (CLD_FLG_LUNU | CLD_FLG_LUND))) {
			strncat(args->argstr, "(-p u) ",
				(MAX_ARG_LEN - 1) - strlen(args->argstr));
			args->flags |= CLD_FLG_LUNU;
		}
	}
	normalize_percs(args);
	if (!(args->flags & CLD_FLG_DUTY) && (args->flags & CLD_FLG_RANDOM)
	    && !(args->flags & CLD_FLG_NTRLVD)) {
		sprintf(TmpStr, "(-D %d:%d) ", args->rperc, args->wperc);
		strncat(args->argstr, TmpStr,
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
		args->flags |= CLD_FLG_DUTY;
	}
	if ((args->delayTimeMin == 0) && (args->delayTimeMax == 0)
	    && (args->ioTimeout == DEFAULT_IO_TIMEOUT)) {
		strncat(args->argstr, "(-t 0:2m) ",
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
	}
	if (!(args->flags & CLD_FLG_OFFSET)) {
		strncat(args->argstr, "(-o 0) ",
			(MAX_ARG_LEN - 1) - strlen(args->argstr));
	}

	return 0;
}