Home | History | Annotate | Download | only in doio
      1 /*
      2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of version 2 of the GNU General Public License as
      6  * published by the Free Software Foundation.
      7  *
      8  * This program is distributed in the hope that it would be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * Further, this software is distributed without any warranty that it is
     13  * free of the rightful claim of any third person regarding infringement
     14  * or the like.  Any license provided herein, whether implied or
     15  * otherwise, applies only to this software file.  Patent licenses, if
     16  * any, provided herein do not apply to combinations of this program with
     17  * other software, or any other product whatsoever.
     18  *
     19  * You should have received a copy of the GNU General Public License along
     20  * with this program; if not, write the Free Software Foundation, Inc.,
     21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     22  *
     23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
     24  * Mountain View, CA  94043, or:
     25  *
     26  * http://www.sgi.com
     27  *
     28  * For further information regarding this notice, see:
     29  *
     30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
     31  */
     32 /*
     33  * iogen - a tool for generating file/sds io for a doio process
     34  */
     35 
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <unistd.h>
     39 #include <signal.h>
     40 #include <fcntl.h>
     41 #include <errno.h>
     42 #include <string.h>
     43 #include <signal.h>
     44 #include <time.h>
     45 #include <sys/param.h>
     46 #include <sys/types.h>
     47 #include <sys/time.h>
     48 #include <sys/stat.h>
     49 #include <sys/sysmacros.h>
     50 #ifdef CRAY
     51 #include <sys/file.h>
     52 #include <sys/iosw.h>
     53 #include <sys/listio.h>
     54 #endif
     55 #ifdef sgi
     56 #include <sys/statvfs.h>
     57 #include <sys/fs/xfs_itable.h>
     58 #endif
     59 
     60 #ifdef CRAY
     61 #include "libkern.h"
     62 #endif
     63 #include "doio.h"
     64 #include "bytes_by_prefix.h"
     65 #include "string_to_tokens.h"
     66 #include "open_flags.h"
     67 #include "random_range.h"
     68 
     69 #ifndef PATH_MAX
     70 #define	PATH_MAX 512		/* ??? */
     71 #endif
     72 
     73 #ifndef BSIZE
     74 #ifdef linux
     75 #define BSIZE DEV_BSIZE
     76 #else
     77 #define BSIZE 512
     78 #endif
     79 #endif
     80 
     81 #define RAW_IO(_flags_)	((_flags_) & (O_RAW | O_SSD))
     82 
     83 #ifndef __linux__
     84 extern char *sys_errlist[];
     85 #endif
     86 #define SYSERR	strerror(errno)
     87 
     88 /*
     89  * Structure for retaining test file information
     90  */
     91 
     92 struct file_info {
     93 	char f_path[MAX_FNAME_LENGTH + 1];	/* file name (full path)    */
     94 	int f_length;		/* length in bytes                      */
     95 	int f_iou;		/* file iounit                          */
     96 	int f_riou;		/* file raw iounit (for O_RAW/O_SSD)    */
     97 	int f_dalign;		/* direct I/O alignment                 */
     98 	int f_nextoff;		/* offset of end of last io operation   */
     99 	int f_type;		/* file type S_IFREG, etc...            */
    100 	int f_lastoffset;	/* offset of last io operation          */
    101 	int f_lastlength;	/* length of last io operation          */
    102 };
    103 
    104 /*
    105  * Simple structure for associating strings with values - useful for converting
    106  * cmdline args to internal values, as well as printing internal values in
    107  * a human readable form.
    108  */
    109 
    110 struct strmap {
    111 	char *m_string;
    112 	int m_value;
    113 	int m_flags;
    114 };
    115 
    116 void startup_info(FILE * stream, int seed);
    117 int init_output(void);
    118 int form_iorequest(struct io_req *req);
    119 int get_file_info(struct file_info *rec);
    120 int create_file(char *path, int nbytes);
    121 int str_to_value(struct strmap *map, char *str);
    122 struct strmap *str_lookup(struct strmap *map, char *str);
    123 char *value_to_string(struct strmap *map, int val);
    124 int parse_cmdline(int argc, char **argv, char *opts);
    125 int help(FILE * stream);
    126 int usage(FILE * stream);
    127 
    128 /*
    129  * Declare cmdline option flags/variables initialized in parse_cmdline()
    130  */
    131 
    132 #define OPTS	"a:dhf:i:L:m:op:qr:s:t:T:O:N:"
    133 
    134 int a_opt = 0;			/* async io comp. types supplied            */
    135 int o_opt = 0;			/* form overlapping requests                */
    136 int f_opt = 0;			/* test flags                               */
    137 int i_opt = 0;			/* iterations - 0 implies infinite          */
    138 int L_opt = 0;			/* listio min-max nstrides & nents          */
    139 int m_opt = 0;			/* offset mode                              */
    140 int O_opt = 0;			/* file creation Open flags                 */
    141 int p_opt = 0;			/* output pipe - default is stdout          */
    142 int r_opt = 0;			/* specify raw io multiple instead of       */
    143 				/* getting it from the mounted on device.   */
    144 				/* Only applies to regular files.           */
    145 int s_opt = 0;			/* syscalls                                 */
    146 int t_opt = 0;			/* min transfer size (bytes)                */
    147 int T_opt = 0;			/* max transfer size (bytes)                */
    148 int q_opt = 0;			/* quiet operation on startup               */
    149 char TagName[40];		/* name of this iogen (see Monster)         */
    150 struct strmap *Offset_Mode;	/* M_SEQUENTIAL, M_RANDOM, etc.             */
    151 int Iterations;			/* # requests to generate (0 --> infinite)  */
    152 int Time_Mode = 0;		/* non-zero if Iterations is in seconds     */
    153 				/* (ie. -i arg was suffixed with 's')       */
    154 char *Outpipe;			/* Pipe to write output to if p_opt         */
    155 int Mintrans;			/* min io transfer size                     */
    156 int Maxtrans;			/* max io transfer size                     */
    157 int Rawmult;			/* raw/ssd io multiple (from -r)            */
    158 int Minstrides;			/* min # of listio strides per request      */
    159 int Maxstrides;			/* max # of listio strides per request      */
    160 int Oflags;			/* open(2) flags for creating files         */
    161 int Ocbits;			/* open(2) cbits for creating files         */
    162 int Ocblks;			/* open(2) cblks for creating files         */
    163 int Orealtime = 0;		/* flag set for -O REALTIME                 */
    164 int Oextsize = 0;		/* real-time extent size                    */
    165 int Oreserve = 1;		/* flag for -O [no]reserve                  */
    166 int Oallocate = 0;		/* flag for -O allocate                     */
    167 int Owrite = 1;			/* flag for -O nowrite                      */
    168 
    169 int Nfiles = 0;			/* # files on cmdline                       */
    170 struct file_info *File_List;	/* info about each file                     */
    171 int Nflags = 0;			/* # flags on cmdline                       */
    172 struct strmap *Flag_List[128];	/* flags selected from cmdline              */
    173 int Nsyscalls = 0;		/* # syscalls on cmdline                    */
    174 struct strmap *Syscall_List[128];	/* syscalls selected on cmdline          */
    175 int Fileio = 0;			/* flag indicating that a file              */
    176 				/* io syscall has been chosen.              */
    177 int Naio_Strat_Types = 0;	/* # async io completion types              */
    178 struct strmap *Aio_Strat_List[128];	/* Async io completion types           */
    179 
    180 /*
    181  * Map async io completion modes (-a args) names to values.  Macros are
    182  * defined in doio.h.
    183  */
    184 
    185 struct strmap Aio_Strat_Map[] = {
    186 #ifndef linux
    187 	{"poll", A_POLL},
    188 	{"signal", A_SIGNAL},
    189 #else
    190 	{"none", 0},
    191 #endif /* !linux */
    192 #ifdef CRAY
    193 #if _UMK || RELEASE_LEVEL >= 8000
    194 	{"recall", A_RECALL},
    195 #endif
    196 
    197 #ifdef RECALL_SIZEOF
    198 	{"recalla", A_RECALLA},
    199 #endif
    200 	{"recalls", A_RECALLS},
    201 #endif /* CRAY */
    202 
    203 #ifdef sgi
    204 	{"suspend", A_SUSPEND},
    205 	{"callback", A_CALLBACK},
    206 #endif
    207 	{NULL, -1}
    208 };
    209 
    210 /*
    211  * Offset_Mode #defines
    212  */
    213 
    214 #define M_RANDOM    	1
    215 #define M_SEQUENTIAL	2
    216 #define M_REVERSE   	3
    217 
    218 /*
    219  * Map offset mode (-m args) names to values
    220  */
    221 
    222 struct strmap Omode_Map[] = {
    223 	{"random", M_RANDOM},
    224 	{"sequential", M_SEQUENTIAL},
    225 	{"reverse", M_REVERSE},
    226 	{NULL, -1}
    227 };
    228 
    229 /*
    230  * Map syscall names (-s args) to values - macros are defined in doio.h.
    231  */
    232 #define	SY_ASYNC	00001
    233 #define	SY_WRITE	00002
    234 #define	SY_SDS		00010
    235 #define	SY_LISTIO	00020
    236 #define	SY_NENT		00100	/* multi entry vs multi stride >>> */
    237 
    238 struct strmap Syscall_Map[] = {
    239 	{"read", READ, 0},
    240 	{"write", WRITE, SY_WRITE},
    241 #ifdef CRAY
    242 	{"reada", READA, SY_ASYNC},
    243 	{"writea", WRITEA, SY_WRITE | SY_ASYNC},
    244 #ifndef _CRAYMPP
    245 	{"ssread", SSREAD, SY_SDS},
    246 	{"sswrite", SSWRITE, SY_WRITE | SY_SDS},
    247 #endif
    248 	{"listio", LISTIO, SY_ASYNC},
    249 
    250 	/* listio as 4 system calls */
    251 	{"lread", LREAD, 0},
    252 	{"lreada", LREADA, SY_ASYNC},
    253 	{"lwrite", LWRITE, SY_WRITE},
    254 	{"lwritea", LWRITEA, SY_WRITE | SY_ASYNC},
    255 
    256 	/* listio with nstrides > 1 */
    257 	{"lsread", LSREAD, 0},
    258 	{"lsreada", LSREADA, SY_ASYNC},
    259 	{"lswrite", LSWRITE, SY_WRITE},
    260 	{"lswritea", LSWRITEA, SY_WRITE | SY_ASYNC},
    261 
    262 	/* listio with nents > 1 */
    263 	{"leread", LEREAD, 0 | SY_NENT},
    264 	{"lereada", LEREADA, SY_ASYNC | SY_NENT},
    265 	{"lewrite", LEWRITE, SY_WRITE | SY_NENT},
    266 	{"lewritea", LEWRITEA, SY_WRITE | SY_ASYNC | SY_NENT},
    267 
    268 	/* listio with nents > 1 & nstrides > 1 */
    269 
    270 	/* all listio system calls under one name */
    271 	{"listio+", LREAD, 0},
    272 	{"listio+", LREADA, SY_ASYNC},
    273 	{"listio+", LWRITE, SY_WRITE},
    274 	{"listio+", LWRITEA, SY_WRITE | SY_ASYNC},
    275 	{"listio+", LSREAD, 0},
    276 	{"listio+", LSREADA, SY_ASYNC},
    277 	{"listio+", LSWRITE, SY_WRITE},
    278 	{"listio+", LSWRITEA, SY_WRITE | SY_ASYNC},
    279 	{"listio+", LEREAD, 0 | SY_NENT},
    280 	{"listio+", LEREADA, SY_ASYNC | SY_NENT},
    281 	{"listio+", LEWRITE, SY_WRITE | SY_NENT},
    282 	{"listio+", LEWRITEA, SY_WRITE | SY_ASYNC | SY_NENT},
    283 #endif
    284 
    285 #ifdef sgi
    286 	{"pread", PREAD},
    287 	{"pwrite", PWRITE, SY_WRITE},
    288 	{"aread", AREAD, SY_ASYNC},
    289 	{"awrite", AWRITE, SY_WRITE | SY_ASYNC},
    290 #if 0
    291 	/* not written yet */
    292 	{"llread", LLREAD, 0},
    293 	{"llaread", LLAREAD, SY_ASYNC},
    294 	{"llwrite", LLWRITE, 0},
    295 	{"llawrite", LLAWRITE, SY_ASYNC},
    296 #endif
    297 	{"resvsp", RESVSP, SY_WRITE},
    298 	{"unresvsp", UNRESVSP, SY_WRITE},
    299 	{"reserve", RESVSP, SY_WRITE},
    300 	{"unreserve", UNRESVSP, SY_WRITE},
    301 	{"ffsync", DFFSYNC, SY_WRITE},
    302 #endif /* SGI */
    303 
    304 #ifndef CRAY
    305 	{"readv", READV},
    306 	{"writev", WRITEV, SY_WRITE},
    307 	{"mmread", MMAPR},
    308 	{"mmwrite", MMAPW, SY_WRITE},
    309 	{"fsync2", FSYNC2, SY_WRITE},
    310 	{"fdatasync", FDATASYNC, SY_WRITE},
    311 #endif
    312 
    313 	{NULL, -1}
    314 };
    315 
    316 /*
    317  * Map open flags (-f args) to values
    318  */
    319 #define	FLG_RAW		00001
    320 
    321 struct strmap Flag_Map[] = {
    322 	{"buffered", 0, 0},
    323 	{"sync", O_SYNC, 0},
    324 #ifdef CRAY
    325 	{"raw", O_RAW, FLG_RAW},
    326 	{"raw+wf", O_RAW | O_WELLFORMED, FLG_RAW},
    327 	{"raw+wf+ldraw", O_RAW | O_WELLFORMED | O_LDRAW, FLG_RAW},
    328 	{"raw+wf+ldraw+sync", O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC, FLG_RAW},
    329 #ifdef O_SSD
    330 	{"ssd", O_SSD, FLG_RAW},
    331 #endif
    332 #ifdef O_LDRAW
    333 	{"ldraw", O_LDRAW, 0},
    334 #endif
    335 #ifdef O_PARALLEL
    336 	{"parallel", O_PARALLEL | O_RAW | O_WELLFORMED,
    337 	 FLG_RAW},
    338 	{"parallel+sync", O_PARALLEL | O_RAW | O_WELLFORMED | O_SYNC,
    339 	 FLG_RAW},
    340 	{"parallel+ldraw", O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW,
    341 	 FLG_RAW},
    342 	{"parallel+ldraw+sync",
    343 	 O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC,
    344 	 FLG_RAW},
    345 #endif
    346 #endif /* CRAY */
    347 
    348 #ifdef sgi
    349 	{"direct", O_DIRECT, FLG_RAW},
    350 	{"dsync", O_DSYNC},	/* affects writes */
    351 	{"rsync", O_RSYNC},	/* affects reads */
    352 	{"rsync+dsync", O_RSYNC | O_DSYNC},
    353 #endif
    354 	{NULL, -1}
    355 };
    356 
    357 /*
    358  * Map file types to strings
    359  */
    360 
    361 struct strmap Ftype_Map[] = {
    362 	{"regular", S_IFREG},
    363 	{"blk-spec", S_IFBLK},
    364 	{"chr-spec", S_IFCHR},
    365 	{NULL, 0}
    366 };
    367 
    368 /*
    369  * Misc declarations
    370  */
    371 
    372 int Sds_Avail;
    373 
    374 char Byte_Patterns[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    375 	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    376 	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
    377 	'Y', 'Z'
    378 };
    379 
    380 int main(int argc, char **argv)
    381 {
    382 	int rseed, outfd, infinite;
    383 	time_t start_time;
    384 	struct io_req req;
    385 
    386 	umask(0);
    387 
    388 #ifdef CRAY
    389 	Sds_Avail = sysconf(_SC_CRAY_SDS);
    390 #else
    391 	Sds_Avail = 0;
    392 #endif
    393 
    394 	TagName[0] = '\0';
    395 	parse_cmdline(argc, argv, OPTS);
    396 
    397 	/*
    398 	 * Initialize output descriptor.
    399 	 */
    400 	if (!p_opt) {
    401 		outfd = 1;
    402 	} else {
    403 		outfd = init_output();
    404 	}
    405 
    406 	rseed = getpid();
    407 	random_range_seed(rseed);	/* initialize random number generator */
    408 
    409 	/*
    410 	 * Print out startup information, unless we're running in quiet mode
    411 	 */
    412 	if (!q_opt)
    413 		startup_info(stderr, rseed);
    414 	{
    415 		struct timeval ts;
    416 		gettimeofday(&ts, NULL);
    417 		start_time = ts.tv_sec;
    418 	}
    419 	/*
    420 	 * While iterations (or forever if Iterations == 0) - compute an
    421 	 * io request, and write the structure to the output descriptor
    422 	 */
    423 
    424 	infinite = !Iterations;
    425 	struct timeval ts;
    426 	gettimeofday(&ts, NULL);
    427 	while (infinite ||
    428 	       (!Time_Mode && Iterations--) ||
    429 	       (Time_Mode && (ts.tv_sec - start_time <= Iterations))) {
    430 		gettimeofday(&ts, NULL);
    431 		memset(&req, 0, sizeof(struct io_req));
    432 		if (form_iorequest(&req) == -1) {
    433 			fprintf(stderr, "iogen%s:  form_iorequest() failed\n",
    434 				TagName);
    435 			continue;
    436 		}
    437 
    438 		req.r_magic = DOIO_MAGIC;
    439 		if (write(outfd, (char *)&req, sizeof(req)) == -1)
    440 			perror("Warning: Could not write");
    441 	}
    442 
    443 	exit(0);
    444 
    445 }				/* main */
    446 
    447 void startup_info(FILE * stream, int seed)
    448 {
    449 	char *value_to_string(), *type;
    450 	int i;
    451 
    452 	fprintf(stream, "\n");
    453 	fprintf(stream, "iogen%s starting up with the following:\n", TagName);
    454 	fprintf(stream, "\n");
    455 
    456 	fprintf(stream, "Out-pipe:              %s\n",
    457 		p_opt ? Outpipe : "stdout");
    458 
    459 	if (Iterations) {
    460 		fprintf(stream, "Iterations:            %d", Iterations);
    461 		if (Time_Mode)
    462 			fprintf(stream, " seconds");
    463 
    464 		fprintf(stream, "\n");
    465 	} else {
    466 		fprintf(stream, "Iterations:            Infinite\n");
    467 	}
    468 
    469 	fprintf(stream, "Seed:                  %d\n", seed);
    470 
    471 	fprintf(stream, "Offset-Mode:           %s\n", Offset_Mode->m_string);
    472 
    473 	fprintf(stream, "Overlap Flag:          %s\n", o_opt ? "on" : "off");
    474 
    475 	fprintf(stream,
    476 		"Mintrans:              %-11d (%d blocks)\n",
    477 		Mintrans, (Mintrans + BSIZE - 1) / BSIZE);
    478 
    479 	fprintf(stream,
    480 		"Maxtrans:              %-11d (%d blocks)\n",
    481 		Maxtrans, (Maxtrans + BSIZE - 1) / BSIZE);
    482 
    483 	if (!r_opt)
    484 		fprintf(stream,
    485 			"O_RAW/O_SSD Multiple:  (Determined by device)\n");
    486 	else
    487 		fprintf(stream,
    488 			"O_RAW/O_SSD Multiple:  %-11d (%d blocks)\n",
    489 			Rawmult, (Rawmult + BSIZE - 1) / BSIZE);
    490 
    491 	fprintf(stream, "Syscalls:              ");
    492 	for (i = 0; i < Nsyscalls; i++)
    493 		fprintf(stream, "%s ", Syscall_List[i]->m_string);
    494 	fprintf(stream, "\n");
    495 
    496 	fprintf(stream, "Aio completion types:  ");
    497 	for (i = 0; i < Naio_Strat_Types; i++)
    498 		fprintf(stream, "%s ", Aio_Strat_List[i]->m_string);
    499 	fprintf(stream, "\n");
    500 
    501 	if (Fileio) {
    502 		fprintf(stream, "Flags:                 ");
    503 		for (i = 0; i < Nflags; i++)
    504 			fprintf(stream, "%s ", Flag_List[i]->m_string);
    505 
    506 		fprintf(stream, "\n");
    507 		fprintf(stream, "\n");
    508 		fprintf(stream, "Test Files:  \n");
    509 		fprintf(stream, "\n");
    510 		fprintf(stream,
    511 			"Path                                          Length    iou   raw iou file\n");
    512 		fprintf(stream,
    513 			"                                              (bytes) (bytes) (bytes) type\n");
    514 		fprintf(stream,
    515 			"-----------------------------------------------------------------------------\n");
    516 
    517 		for (i = 0; i < Nfiles; i++) {
    518 			type = value_to_string(Ftype_Map, File_List[i].f_type);
    519 			fprintf(stream, "%-40s %12d %7d %7d %s\n",
    520 				File_List[i].f_path, File_List[i].f_length,
    521 				File_List[i].f_iou, File_List[i].f_riou, type);
    522 		}
    523 	}
    524 }
    525 
    526 /*
    527  * Initialize output descriptor.  If going to stdout, its easy,
    528  * otherwise, attempt to create a FIFO on path Outpipe.  Exit with an
    529  * error code if this cannot be done.
    530  */
    531 int init_output(void)
    532 {
    533 	int outfd;
    534 	struct stat sbuf;
    535 
    536 	if (stat(Outpipe, &sbuf) == -1) {
    537 		if (errno == ENOENT) {
    538 			if (mkfifo(Outpipe, 0666) == -1) {
    539 				fprintf(stderr,
    540 					"iogen%s:  Could not mkfifo %s:  %s\n",
    541 					TagName, Outpipe, SYSERR);
    542 				exit(2);
    543 			}
    544 		} else {
    545 			fprintf(stderr,
    546 				"iogen%s:  Could not stat outpipe %s:  %s\n",
    547 				TagName, Outpipe, SYSERR);
    548 			exit(2);
    549 		}
    550 	} else {
    551 		if (!S_ISFIFO(sbuf.st_mode)) {
    552 			fprintf(stderr,
    553 				"iogen%s:  Output file %s exists, but is not a FIFO\n",
    554 				TagName, Outpipe);
    555 			exit(2);
    556 		}
    557 	}
    558 
    559 	if ((outfd = open(Outpipe, O_RDWR)) == -1) {
    560 		fprintf(stderr,
    561 			"iogen%s:  Couldn't open outpipe %s with flags O_RDWR: %s\n",
    562 			TagName, Outpipe, SYSERR);
    563 		exit(2);
    564 	}
    565 
    566 	return (outfd);
    567 }
    568 
    569 /*
    570  * Main io generation function.  form_iorequest() selects a system call to
    571  * do based on cmdline arguments, and proceeds to select parameters for that
    572  * system call.
    573  *
    574  * Returns 0 if req is filled in with a complete doio request, otherwise
    575  * returns -1.
    576  */
    577 
    578 int form_iorequest(struct io_req *req)
    579 {
    580 	int mult, offset = 0, length = 0, slength;
    581 	int minlength, maxlength, laststart, lastend;
    582 	int minoffset, maxoffset;
    583 	int maxstride, nstrides;
    584 	char pattern, *errp;
    585 	struct strmap *flags, *sc, *aio_strat;
    586 	struct file_info *fptr;
    587 #ifdef CRAY
    588 	int opcode, cmd;
    589 #endif
    590 
    591 	/*
    592 	 * Choose system call, flags, and file
    593 	 */
    594 
    595 	sc = Syscall_List[random_range(0, Nsyscalls - 1, 1, NULL)];
    596 	req->r_type = sc->m_value;
    597 
    598 #ifdef CRAY
    599 	if (sc->m_value == LISTIO) {
    600 		opcode = random_range(0, 1, 1, NULL) ? LO_READ : LO_WRITE;
    601 		cmd = random_range(0, 1, 1, NULL) ? LC_START : LC_WAIT;
    602 	}
    603 #endif
    604 
    605 	if (sc->m_flags & SY_WRITE)
    606 		pattern =
    607 		    Byte_Patterns[random_range
    608 				  (0, sizeof(Byte_Patterns) - 1, 1, NULL)];
    609 	else
    610 		pattern = 0;
    611 
    612 #if CRAY
    613 	/*
    614 	 * If sds io, simply choose a length (possibly pattern) and return
    615 	 */
    616 
    617 	if (sc->m_flags & SY_SDS) {
    618 		req->r_data.ssread.r_nbytes =
    619 		    random_range(Mintrans, Maxtrans, BSIZE, NULL);
    620 		if (sc->m_flags & SY_WRITE)
    621 			req->r_data.sswrite.r_pattern = pattern;
    622 
    623 		return 0;
    624 	}
    625 #endif
    626 
    627 	/*
    628 	 * otherwise, we're doing file io.  Choose starting offset, length,
    629 	 * open flags, and possibly a pattern (for write/writea).
    630 	 */
    631 
    632 	fptr = &File_List[random_range(0, Nfiles - 1, 1, NULL)];
    633 	flags = Flag_List[random_range(0, Nflags - 1, 1, NULL)];
    634 
    635 	/*
    636 	 * Choose offset/length multiple.  IO going to a device, or regular
    637 	 * IO that is O_RAW or O_SSD must be aligned on the file r_iou.  Otherwise
    638 	 * it must be aligned on the regular iou (normally 1).
    639 	 */
    640 
    641 	if (fptr->f_type == S_IFREG && (flags->m_flags & FLG_RAW))
    642 		mult = fptr->f_riou;
    643 	else
    644 		mult = fptr->f_iou;
    645 
    646 	/*
    647 	 * Choose offset and length.  Both must be a multiple of mult
    648 	 */
    649 
    650 	/*
    651 	 * Choose length first - it must be a multiple of mult
    652 	 */
    653 
    654 	laststart = fptr->f_lastoffset;
    655 	lastend = fptr->f_lastoffset + fptr->f_lastlength - 1;
    656 
    657 	minlength = (Mintrans > mult) ? Mintrans : mult;
    658 
    659 	switch (Offset_Mode->m_value) {
    660 	case M_SEQUENTIAL:
    661 		if (o_opt && lastend > laststart)
    662 			offset = random_range(laststart, lastend, 1, NULL);
    663 		else
    664 			offset = lastend + 1;
    665 		if (offset && (offset % mult))
    666 			offset += mult - (offset % mult);
    667 
    668 		if (minlength > fptr->f_length - offset)
    669 			offset = 0;
    670 
    671 		maxlength = fptr->f_length - offset;
    672 		if (maxlength > Maxtrans)
    673 			maxlength = Maxtrans;
    674 
    675 		length = random_range(minlength, maxlength, mult, &errp);
    676 		if (errp != NULL) {
    677 			fprintf(stderr,
    678 				"iogen%s:  random_range(%d, %d, %d) failed\n",
    679 				TagName, minlength, maxlength, mult);
    680 			return -1;
    681 		}
    682 
    683 		break;
    684 
    685 	case M_REVERSE:
    686 		maxlength = laststart;
    687 
    688 		if (maxlength > Maxtrans)
    689 			maxlength = Maxtrans;
    690 
    691 		if (minlength > maxlength) {
    692 			laststart = fptr->f_length;
    693 			lastend = fptr->f_length;
    694 			maxlength = Maxtrans;
    695 		}
    696 
    697 		length = random_range(minlength, maxlength, mult, &errp);
    698 		if (errp != NULL) {
    699 			fprintf(stderr,
    700 				"iogen%s:  random_range(%d, %d, %d) failed\n",
    701 				TagName, minlength, maxlength, mult);
    702 			return -1;
    703 		}
    704 
    705 		offset = laststart - length;
    706 
    707 		if (o_opt && lastend > laststart)
    708 			offset += random_range(1, lastend - laststart, 1, NULL);
    709 
    710 		if (offset && (offset % mult))
    711 			offset -= offset % mult;
    712 
    713 		break;
    714 
    715 	case M_RANDOM:
    716 		length = random_range(Mintrans, Maxtrans, mult, NULL);
    717 
    718 		if (o_opt && lastend > laststart) {
    719 			minoffset = laststart - length + 1;
    720 			if (minoffset < 0) {
    721 				minoffset = 0;
    722 			}
    723 
    724 			if (lastend + length > fptr->f_length) {
    725 				maxoffset = fptr->f_length - length;
    726 			} else {
    727 				maxoffset = lastend;
    728 			}
    729 		} else {
    730 			minoffset = 0;
    731 			maxoffset = fptr->f_length - length;
    732 		}
    733 
    734 		if (minoffset < 0)
    735 			minoffset = 0;
    736 
    737 		offset = random_range(minoffset, maxoffset, mult, &errp);
    738 		if (errp != NULL) {
    739 			fprintf(stderr,
    740 				"iogen%s:  random_range(%d, %d, %d) failed\n",
    741 				TagName, minoffset, maxoffset, mult);
    742 			return -1;
    743 		}
    744 	}
    745 
    746 	fptr->f_lastoffset = offset;
    747 	fptr->f_lastlength = length;
    748 
    749 	/*
    750 	 * Choose an async io completion strategy if necessary
    751 	 */
    752 	if (sc->m_flags & SY_ASYNC)
    753 		aio_strat = Aio_Strat_List[random_range(0, Naio_Strat_Types - 1,
    754 							1, NULL)];
    755 	else
    756 		aio_strat = NULL;
    757 
    758 	/*
    759 	 * fill in specific syscall record data
    760 	 */
    761 	switch (sc->m_value) {
    762 	case READ:
    763 	case READA:
    764 		strcpy(req->r_data.read.r_file, fptr->f_path);
    765 		req->r_data.read.r_oflags = O_RDONLY | flags->m_value;
    766 		req->r_data.read.r_offset = offset;
    767 		req->r_data.read.r_nbytes = length;
    768 		req->r_data.read.r_uflags =
    769 		    (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
    770 		req->r_data.read.r_aio_strat =
    771 		    (aio_strat == NULL) ? 0 : aio_strat->m_value;
    772 		req->r_data.read.r_nstrides = 1;
    773 		req->r_data.read.r_nent = 1;
    774 		break;
    775 
    776 	case WRITE:
    777 	case WRITEA:
    778 		strcpy(req->r_data.write.r_file, fptr->f_path);
    779 		req->r_data.write.r_oflags = O_WRONLY | flags->m_value;
    780 		req->r_data.write.r_offset = offset;
    781 		req->r_data.write.r_nbytes = length;
    782 		req->r_data.write.r_pattern = pattern;
    783 		req->r_data.write.r_uflags =
    784 		    (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
    785 		req->r_data.write.r_aio_strat =
    786 		    (aio_strat == NULL) ? 0 : aio_strat->m_value;
    787 		req->r_data.write.r_nstrides = 1;
    788 		req->r_data.write.r_nent = 1;
    789 		break;
    790 
    791 	case READV:
    792 	case AREAD:
    793 	case PREAD:
    794 	case WRITEV:
    795 	case AWRITE:
    796 	case PWRITE:
    797 
    798 	case LREAD:
    799 	case LREADA:
    800 	case LWRITE:
    801 	case LWRITEA:
    802 
    803 	case RESVSP:
    804 	case UNRESVSP:
    805 	case DFFSYNC:
    806 	case FSYNC2:
    807 	case FDATASYNC:
    808 
    809 		strcpy(req->r_data.io.r_file, fptr->f_path);
    810 		req->r_data.io.r_oflags =
    811 		    ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->
    812 		    m_value;
    813 		req->r_data.io.r_offset = offset;
    814 		req->r_data.io.r_nbytes = length;
    815 		req->r_data.io.r_pattern = pattern;
    816 		req->r_data.io.r_uflags =
    817 		    (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
    818 		req->r_data.io.r_aio_strat =
    819 		    (aio_strat == NULL) ? 0 : aio_strat->m_value;
    820 		req->r_data.io.r_nstrides = 1;
    821 		req->r_data.io.r_nent = 1;
    822 		break;
    823 
    824 	case MMAPR:
    825 	case MMAPW:
    826 		strcpy(req->r_data.io.r_file, fptr->f_path);
    827 		/* a subtle "feature" of mmap: a write-map requires
    828 		   the file open read/write */
    829 		req->r_data.io.r_oflags =
    830 		    ((sc->m_flags & SY_WRITE) ? O_RDWR : O_RDONLY) | flags->
    831 		    m_value;
    832 		req->r_data.io.r_offset = offset;
    833 		req->r_data.io.r_nbytes = length;
    834 		req->r_data.io.r_pattern = pattern;
    835 		req->r_data.io.r_uflags =
    836 		    (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
    837 		req->r_data.io.r_aio_strat =
    838 		    (aio_strat == NULL) ? 0 : aio_strat->m_value;
    839 		req->r_data.io.r_nstrides = 1;
    840 		req->r_data.io.r_nent = 1;
    841 		break;
    842 
    843 	case LSREAD:
    844 	case LSREADA:
    845 	case LEREAD:
    846 	case LEREADA:
    847 	case LSWRITE:
    848 	case LSWRITEA:
    849 	case LEWRITE:
    850 	case LEWRITEA:
    851 		/* multi-strided */
    852 		strcpy(req->r_data.io.r_file, fptr->f_path);
    853 		req->r_data.io.r_oflags =
    854 		    ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->
    855 		    m_value;
    856 		req->r_data.io.r_offset = offset;
    857 		req->r_data.io.r_uflags =
    858 		    (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
    859 		req->r_data.io.r_aio_strat =
    860 		    (aio_strat == NULL) ? 0 : aio_strat->m_value;
    861 		req->r_data.io.r_pattern = pattern;
    862 
    863 		/* multi-strided request...
    864 		 *  random number of strides (1...MaxStrides)
    865 		 *  length of stride must be > minlength
    866 		 *  length of stride must be % mult
    867 		 *
    868 		 * maxstrides = min(length / mult, overall.max#strides)
    869 		 * nstrides = random #
    870 		 * while (length / nstrides < minlength)
    871 		 *      nstrides = new random #
    872 		 */
    873 		maxstride = length / mult;
    874 		if (maxstride > Maxstrides)
    875 			maxstride = Maxstrides;
    876 
    877 		if (!Minstrides)
    878 			Minstrides = 1;
    879 		nstrides = random_range(Minstrides, maxstride, 1, &errp);
    880 		if (errp != NULL) {
    881 			fprintf(stderr,
    882 				"iogen%s:  random_range(%d, %d, %d) failed\n",
    883 				TagName, Minstrides, maxstride, 1);
    884 			return -1;
    885 		}
    886 
    887 		slength = length / nstrides;
    888 		if (slength % mult != 0) {
    889 			if (mult > slength) {
    890 				slength = mult;
    891 			} else {
    892 				slength -= slength % mult;
    893 			}
    894 			nstrides = length / slength;
    895 			if (nstrides > Maxstrides)
    896 				nstrides = Maxstrides;
    897 		}
    898 
    899 		req->r_data.io.r_nbytes = slength;
    900 		if (sc->m_flags & SY_NENT) {
    901 			req->r_data.io.r_nstrides = 1;
    902 			req->r_data.io.r_nent = nstrides;
    903 		} else {
    904 			req->r_data.io.r_nstrides = nstrides;
    905 			req->r_data.io.r_nent = 1;
    906 		}
    907 		break;
    908 
    909 	case LISTIO:
    910 #ifdef CRAY
    911 		strcpy(req->r_data.listio.r_file, fptr->f_path);
    912 		req->r_data.listio.r_offset = offset;
    913 		req->r_data.listio.r_cmd = cmd;
    914 		req->r_data.listio.r_aio_strat =
    915 		    (aio_strat == NULL) ? 0 : aio_strat->m_value;
    916 		req->r_data.listio.r_filestride = 0;
    917 		req->r_data.listio.r_memstride = 0;
    918 		req->r_data.listio.r_opcode = opcode;
    919 		req->r_data.listio.r_nstrides = 1;
    920 		req->r_data.listio.r_nbytes = length;
    921 		req->r_data.listio.r_uflags =
    922 		    (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
    923 
    924 		if (opcode == LO_WRITE) {
    925 			req->r_data.listio.r_pattern = pattern;
    926 			req->r_data.listio.r_oflags = O_WRONLY | flags->m_value;
    927 		} else {
    928 			req->r_data.listio.r_oflags = O_RDONLY | flags->m_value;
    929 		}
    930 #endif
    931 		break;
    932 	}
    933 
    934 	return 0;
    935 }
    936 
    937 /*
    938  * Get information about a file that iogen uses to choose io length and
    939  * offset.  Information gathered is file length, iounit, and raw iounit.
    940  * For regurlar files, iounit is 1, and raw iounit is the iounit of the
    941  * device on which the file resides.  For block/character special files
    942  * the iounit and raw iounit are both the iounit of the device.
    943  *
    944  * Note:	buffered and osync io must be iounit aligned
    945  *		raw and ossd io must be raw iounit aligned
    946  */
    947 
    948 int get_file_info(struct file_info *rec)
    949 {
    950 	struct stat sbuf;
    951 #ifdef CRAY
    952 	struct lk_device_info dinfo;
    953 #endif
    954 #ifdef sgi
    955 	int fd;
    956 	struct dioattr finfo;
    957 #endif
    958 
    959 	/*
    960 	 * Figure out if the files is regular, block or character special.  Any
    961 	 * other type is an error.
    962 	 */
    963 
    964 	if (stat(rec->f_path, &sbuf) == -1) {
    965 		fprintf(stderr,
    966 			"iogen%s: get_file_info():  Could not stat() %s:  %s\n",
    967 			TagName, rec->f_path, SYSERR);
    968 		return -1;
    969 	}
    970 #if _CRAY2
    971 	if ((!S_ISREG(sbuf.st_mode)) || strncmp(rec->f_path, "/dev/", 5) == 0) {
    972 		fprintf(stderr,
    973 			"iogen%s:  device level io not supported on cray2\n",
    974 			TagName);
    975 		return -1;
    976 	}
    977 #endif
    978 
    979 	rec->f_type = sbuf.st_mode & S_IFMT;
    980 
    981 	/*
    982 	 * If regular, iou is 1, and we must figure out the device on
    983 	 * which the file resides.  riou is the iou (logical sector size) of
    984 	 * this device.
    985 	 */
    986 
    987 	if (S_ISREG(sbuf.st_mode)) {
    988 		rec->f_iou = 1;
    989 		rec->f_length = sbuf.st_size;
    990 
    991 		/*
    992 		 * If -r used, take Rawmult as the raw/ssd io multiple.  Otherwise
    993 		 * attempt to determine it by looking at the device the file
    994 		 * resides on.
    995 		 */
    996 
    997 		if (r_opt) {
    998 			rec->f_riou = Rawmult;
    999 			return 0;
   1000 		}
   1001 #ifdef CRAY
   1002 		if (lk_rawdev(rec->f_path, dinfo.path, sizeof(dinfo.path), 0) ==
   1003 		    -1)
   1004 			return -1;
   1005 
   1006 		if (lk_devinfo(&dinfo, 0) == -1) {
   1007 			/* can't get raw I/O unit -- use stat to fudge it */
   1008 			rec->f_riou = sbuf.st_blksize;
   1009 		} else {
   1010 			rec->f_riou = ctob(dinfo.iou);
   1011 		}
   1012 #endif
   1013 #ifdef linux
   1014 		rec->f_riou = BSIZE;
   1015 #endif
   1016 #ifdef sgi
   1017 		if ((fd = open(rec->f_path, O_RDWR | O_DIRECT, 0)) != -1) {
   1018 			if (fcntl(fd, F_DIOINFO, &finfo) != -1) {
   1019 				rec->f_riou = finfo.d_miniosz;
   1020 			} else {
   1021 				fprintf(stderr,
   1022 					"iogen%s: Error %s (%d) getting direct I/O info of file %s\n",
   1023 					TagName, strerror(errno), errno,
   1024 					rec->f_path);
   1025 			}
   1026 			close(fd);
   1027 		} else {
   1028 			rec->f_riou = BBSIZE;
   1029 		}
   1030 #endif /* SGI */
   1031 
   1032 	} else {
   1033 
   1034 #ifdef CRAY
   1035 		/*
   1036 		 * Otherwise, file is a device.  Use lk_devinfo() to get its logical
   1037 		 * sector size.  This is the iou and riou
   1038 		 */
   1039 
   1040 		strcpy(dinfo.path, rec->f_path);
   1041 
   1042 		if (lk_devinfo(&dinfo, 0) == -1) {
   1043 			fprintf(stderr, "iogen%s: %s:  %s\n", TagName,
   1044 				Lk_err_func, Lk_err_mesg);
   1045 			return -1;
   1046 		}
   1047 
   1048 		rec->f_iou = ctob(dinfo.iou);
   1049 		rec->f_riou = ctob(dinfo.iou);
   1050 		rec->f_length = ctob(dinfo.length);
   1051 #else
   1052 #ifdef sgi
   1053 		rec->f_riou = BBSIZE;
   1054 		rec->f_length = BBSIZE;
   1055 #else
   1056 		rec->f_riou = BSIZE;
   1057 		rec->f_length = BSIZE;
   1058 #endif /* sgi */
   1059 #endif /* CRAY */
   1060 	}
   1061 
   1062 	return 0;
   1063 }
   1064 
   1065 /*
   1066  * Create file path as nbytes long.  If path exists, the file will either be
   1067  * extended or truncated to be nbytes long.  Returns final size of file,
   1068  * or -1 if there was a failure.
   1069  */
   1070 
   1071 int create_file(char *path, int nbytes)
   1072 {
   1073 	int fd, rval;
   1074 	char c;
   1075 	struct stat sbuf;
   1076 #ifdef sgi
   1077 	int nb;
   1078 	struct flock f;
   1079 	struct fsxattr xattr;
   1080 	struct dioattr finfo;
   1081 	char *b, *buf;
   1082 #endif
   1083 
   1084 	errno = 0;
   1085 	rval = stat(path, &sbuf);
   1086 
   1087 	if (rval == -1) {
   1088 		if (errno == ENOENT) {
   1089 			sbuf.st_size = 0;
   1090 		} else {
   1091 			fprintf(stderr,
   1092 				"iogen%s:  Could not stat file %s:  %s (%d)\n",
   1093 				TagName, path, SYSERR, errno);
   1094 			return -1;
   1095 		}
   1096 	} else {
   1097 		if (!S_ISREG(sbuf.st_mode)) {
   1098 			fprintf(stderr,
   1099 				"iogen%s:  file %s exists, but is not a regular file - cannot modify length\n",
   1100 				TagName, path);
   1101 			return -1;
   1102 		}
   1103 	}
   1104 
   1105 	if (sbuf.st_size == nbytes)
   1106 		return nbytes;
   1107 
   1108 	Oflags |= O_CREAT | O_WRONLY;
   1109 
   1110 	if ((fd = open(path, Oflags, 0666)) == -1) {
   1111 		fprintf(stderr,
   1112 			"iogen%s:  Could not create/open file %s: %s (%d)\n",
   1113 			TagName, path, SYSERR, errno);
   1114 		return -1;
   1115 	}
   1116 
   1117 	/*
   1118 	 * Truncate file if it is longer than nbytes, otherwise attempt to
   1119 	 * pre-allocate file blocks.
   1120 	 */
   1121 
   1122 	if (sbuf.st_size > nbytes) {
   1123 		if (ftruncate(fd, nbytes) == -1) {
   1124 			fprintf(stderr,
   1125 				"iogen%s:  Could not ftruncate() %s to %d bytes:  %s (%d)\n",
   1126 				TagName, path, nbytes, SYSERR, errno);
   1127 			close(fd);
   1128 			return -1;
   1129 		}
   1130 	} else {
   1131 
   1132 #ifdef sgi
   1133 		/*
   1134 		 *  The file must be designated as Real-Time before any data
   1135 		 *  is allocated to it.
   1136 		 *
   1137 		 */
   1138 		if (Orealtime != 0) {
   1139 			memset(&xattr, 0x00, sizeof(xattr));
   1140 			xattr.fsx_xflags = XFS_XFLAG_REALTIME;
   1141 			/*fprintf(stderr, "set: fsx_xflags = 0x%x\n", xattr.fsx_xflags); */
   1142 			if (fcntl(fd, F_FSSETXATTR, &xattr) == -1) {
   1143 				fprintf(stderr,
   1144 					"iogen%s: Error %s (%d) setting XFS XATTR->Realtime on file %s\n",
   1145 					TagName, SYSERR, errno, path);
   1146 				close(fd);
   1147 				return -1;
   1148 			}
   1149 #ifdef DEBUG
   1150 			if (fcntl(fd, F_FSGETXATTR, &xattr) == -1) {
   1151 				fprintf(stderr,
   1152 					"iogen%s: Error getting realtime flag %s (%d)\n",
   1153 					TagName, SYSERR, errno);
   1154 				close(fd);
   1155 				return -1;
   1156 			} else {
   1157 				fprintf(stderr, "get: fsx_xflags = 0x%x\n",
   1158 					xattr.fsx_xflags);
   1159 			}
   1160 #endif
   1161 		}
   1162 
   1163 		/*
   1164 		 * Reserve space with F_RESVSP
   1165 		 *
   1166 		 * Failure is ignored since F_RESVSP only works on XFS and the
   1167 		 * filesystem could be on EFS or NFS
   1168 		 */
   1169 		if (Oreserve) {
   1170 			f.l_whence = SEEK_SET;
   1171 			f.l_start = 0;
   1172 			f.l_len = nbytes;
   1173 
   1174 			/*fprintf(stderr,
   1175 			   "create_file: fcntl(%d, F_RESVSP, { %d, %lld, %lld })\n",
   1176 			   fd, f.l_whence, (long long)f.l_start, (long long)f.l_len); */
   1177 
   1178 			/* non-zeroing reservation */
   1179 			if (fcntl(fd, F_RESVSP, &f) == -1) {
   1180 				fprintf(stderr,
   1181 					"iogen%s:  Could not fcntl(F_RESVSP) %d bytes in file %s: %s (%d)\n",
   1182 					TagName, nbytes, path, SYSERR, errno);
   1183 				close(fd);
   1184 				return -1;
   1185 			}
   1186 		}
   1187 
   1188 		if (Oallocate) {
   1189 			/* F_ALLOCSP allocates from the start of the file to l_start */
   1190 			f.l_whence = SEEK_SET;
   1191 			f.l_start = nbytes;
   1192 			f.l_len = 0;
   1193 			/*fprintf(stderr,
   1194 			   "create_file: fcntl(%d, F_ALLOCSP, { %d, %lld, %lld })\n",
   1195 			   fd, f.l_whence, (long long)f.l_start,
   1196 			   (long long)f.l_len); */
   1197 
   1198 			/* zeroing reservation */
   1199 			if (fcntl(fd, F_ALLOCSP, &f) == -1) {
   1200 				fprintf(stderr,
   1201 					"iogen%s:  Could not fcntl(F_ALLOCSP) %d bytes in file %s: %s (%d)\n",
   1202 					TagName, nbytes, path, SYSERR, errno);
   1203 				close(fd);
   1204 				return -1;
   1205 			}
   1206 		}
   1207 #endif /* sgi */
   1208 
   1209 		/*
   1210 		 * Write a byte at the end of file so that stat() sets the right
   1211 		 * file size.
   1212 		 */
   1213 
   1214 #ifdef sgi
   1215 		if (Owrite == 2) {
   1216 			close(fd);
   1217 			if ((fd =
   1218 			     open(path, O_CREAT | O_RDWR | O_DIRECT,
   1219 				  0)) != -1) {
   1220 				if (fcntl(fd, F_DIOINFO, &finfo) == -1) {
   1221 					fprintf(stderr,
   1222 						"iogen%s: Error %s (%d) getting direct I/O info for file %s\n",
   1223 						TagName, SYSERR, errno, path);
   1224 					return -1;
   1225 				} else {
   1226 					/*fprintf(stderr, "%s: miniosz=%d\n",
   1227 					   path, finfo.d_miniosz); */
   1228 				}
   1229 			} else {
   1230 				fprintf(stderr,
   1231 					"iogen%s: Error %s (%d) opening file %s with flags O_CREAT|O_RDWR|O_DIRECT\n",
   1232 					TagName, SYSERR, errno, path);
   1233 				return -1;
   1234 			}
   1235 
   1236 			/*
   1237 			 * nb is nbytes adjusted down by an even d_miniosz block
   1238 			 *
   1239 			 * Note: the first adjustment can cause iogen to print a warning
   1240 			 *  about not being able to create a file of <nbytes> length,
   1241 			 *  since the file will be shorter.
   1242 			 */
   1243 			nb = nbytes - finfo.d_miniosz;
   1244 			nb = nb - nb % finfo.d_miniosz;
   1245 
   1246 			/*fprintf(stderr,
   1247 			   "create_file_ow2: lseek(%d, %d {%d %d}, SEEK_SET)\n",
   1248 			   fd, nb, nbytes, finfo.d_miniosz); */
   1249 
   1250 			if (lseek(fd, nb, SEEK_SET) == -1) {
   1251 				fprintf(stderr,
   1252 					"iogen%s:  Could not lseek() to EOF of file %s: %s (%d)\n\tactual offset %d file size goal %d miniosz %lld\n",
   1253 					TagName, path, SYSERR, errno,
   1254 					nb, nbytes, (long long)finfo.d_miniosz);
   1255 				close(fd);
   1256 				return -1;
   1257 			}
   1258 
   1259 			b = buf = malloc(finfo.d_miniosz + finfo.d_mem);
   1260 
   1261 			if (((long)buf % finfo.d_mem != 0)) {
   1262 				buf += finfo.d_mem - ((long)buf % finfo.d_mem);
   1263 			}
   1264 
   1265 			memset(buf, 0, finfo.d_miniosz);
   1266 
   1267 			if ((rval =
   1268 			     write(fd, buf,
   1269 				   finfo.d_miniosz)) != finfo.d_miniosz) {
   1270 				fprintf(stderr,
   1271 					"iogen%s:  Could not write %d byte length file %s: %s (%d)\n",
   1272 					TagName, nb, path, SYSERR, errno);
   1273 				fprintf(stderr, "\twrite(%d, 0x%lx, %d) = %d\n",
   1274 					fd, (long)buf, finfo.d_miniosz, rval);
   1275 				fprintf(stderr,
   1276 					"\toffset %d file size goal %d, miniosz=%d\n",
   1277 					nb, nbytes, finfo.d_miniosz);
   1278 				close(fd);
   1279 				return -1;
   1280 			}
   1281 			free(b);
   1282 		} else
   1283 #endif /* sgi */
   1284 		if (Owrite) {
   1285 			/*fprintf(stderr,
   1286 			   "create_file_Owrite: lseek(%d, %d {%d}, SEEK_SET)\n",
   1287 			   fd, nbytes-1, nbytes); */
   1288 
   1289 			if (lseek(fd, nbytes - 1, SEEK_SET) == -1) {
   1290 				fprintf(stderr,
   1291 					"iogen%s:  Could not lseek() to EOF in file %s:  %s (%d)\n\toffset goal %d\n",
   1292 					TagName, path, SYSERR, errno,
   1293 					nbytes - 1);
   1294 				close(fd);
   1295 				return -1;
   1296 			}
   1297 
   1298 			if ((rval = write(fd, &c, 1)) != 1) {
   1299 				fprintf(stderr,
   1300 					"iogen%s:  Could not create a %d byte length file %s: %s (%d)\n",
   1301 					TagName, nbytes, path, SYSERR, errno);
   1302 				fprintf(stderr,
   1303 					"\twrite(%d, 0x%lx, %d) = %d\n",
   1304 					fd, (long)&c, 1, rval);
   1305 				fprintf(stderr,
   1306 					"\toffset %d file size goal %d\n",
   1307 					nbytes - 1, nbytes);
   1308 				close(fd);
   1309 				return -1;
   1310 			}
   1311 		}
   1312 	}
   1313 
   1314 	fstat(fd, &sbuf);
   1315 	close(fd);
   1316 
   1317 	return sbuf.st_size;
   1318 }
   1319 
   1320 /*
   1321  * Function to convert a string to its corresponding value in a strmap array.
   1322  * If the string is not found in the array, the value corresponding to the
   1323  * NULL string (the last element in the array) is returned.
   1324  */
   1325 
   1326 int str_to_value(struct strmap *map, char *str)
   1327 {
   1328 	struct strmap *mp;
   1329 
   1330 	for (mp = map; mp->m_string != NULL; mp++)
   1331 		if (strcmp(mp->m_string, str) == 0)
   1332 			break;
   1333 
   1334 	return mp->m_value;
   1335 }
   1336 
   1337 /*
   1338  * Function to convert a string to its corresponding entry in a strmap array.
   1339  * If the string is not found in the array, a NULL is returned.
   1340  */
   1341 
   1342 struct strmap *str_lookup(struct strmap *map, char *str)
   1343 {
   1344 	struct strmap *mp;
   1345 
   1346 	for (mp = map; mp->m_string != NULL; mp++)
   1347 		if (strcmp(mp->m_string, str) == 0)
   1348 			break;
   1349 
   1350 	return ((mp->m_string == NULL) ? NULL : mp);
   1351 }
   1352 
   1353 /*
   1354  * Function to convert a value to its corresponding string in a strmap array.
   1355  * If the value is not found in the array, NULL is returned.
   1356  */
   1357 
   1358 char *value_to_string(struct strmap *map, int val)
   1359 {
   1360 	struct strmap *mp;
   1361 
   1362 	for (mp = map; mp->m_string != NULL; mp++)
   1363 		if (mp->m_value == val)
   1364 			break;
   1365 
   1366 	return mp->m_string;
   1367 }
   1368 
   1369 /*
   1370  * Interpret cmdline options/arguments.  Exit with 1 if something on the
   1371  * cmdline isn't kosher.
   1372  */
   1373 
   1374 int parse_cmdline(int argc, char **argv, char *opts)
   1375 {
   1376 	int o, len, nb, format_error;
   1377 	struct strmap *flgs, *sc;
   1378 	char *file, *cp, ch;
   1379 	extern int opterr;
   1380 	extern int optind;
   1381 	extern char *optarg;
   1382 	struct strmap *mp;
   1383 	struct file_info *fptr;
   1384 	int nopenargs;
   1385 	char *openargs[5];	/* Flags, cbits, cblks */
   1386 	char *errmsg;
   1387 	int str_to_int();
   1388 	opterr = 0;
   1389 #ifndef linux
   1390 	char *ranges;
   1391 	struct strmap *type;
   1392 #endif
   1393 
   1394 	while ((o = getopt(argc, argv, opts)) != EOF) {
   1395 		switch ((char)o) {
   1396 
   1397 		case 'a':
   1398 #ifdef linux
   1399 			fprintf(stderr,
   1400 				"iogen%s:  Unrecognized option -a on this platform\n",
   1401 				TagName);
   1402 			exit(2);
   1403 #else
   1404 			cp = strtok(optarg, ",");
   1405 			while (cp != NULL) {
   1406 				if ((type =
   1407 				     str_lookup(Aio_Strat_Map, cp)) == NULL) {
   1408 					fprintf(stderr,
   1409 						"iogen%s:  Unrecognized aio completion strategy:  %s\n",
   1410 						TagName, cp);
   1411 					exit(2);
   1412 				}
   1413 
   1414 				Aio_Strat_List[Naio_Strat_Types++] = type;
   1415 				cp = strtok(NULL, ",");
   1416 			}
   1417 			a_opt++;
   1418 #endif
   1419 			break;
   1420 
   1421 		case 'f':
   1422 			cp = strtok(optarg, ",");
   1423 			while (cp != NULL) {
   1424 				if ((flgs = str_lookup(Flag_Map, cp)) == NULL) {
   1425 					fprintf(stderr,
   1426 						"iogen%s:  Unrecognized flags:  %s\n",
   1427 						TagName, cp);
   1428 					exit(2);
   1429 				}
   1430 
   1431 				cp = strtok(NULL, ",");
   1432 
   1433 #ifdef O_SSD
   1434 				if (flgs->m_value & O_SSD && !Sds_Avail) {
   1435 					fprintf(stderr,
   1436 						"iogen%s:  Warning - no sds available, ignoring ssd flag\n",
   1437 						TagName);
   1438 					continue;
   1439 				}
   1440 #endif
   1441 
   1442 				Flag_List[Nflags++] = flgs;
   1443 			}
   1444 			f_opt++;
   1445 			break;
   1446 
   1447 		case 'h':
   1448 			help(stdout);
   1449 			exit(0);
   1450 			break;
   1451 
   1452 		case 'i':
   1453 			format_error = 0;
   1454 
   1455 			switch (sscanf(optarg, "%i%c", &Iterations, &ch)) {
   1456 			case 1:
   1457 				Time_Mode = 0;
   1458 				break;
   1459 
   1460 			case 2:
   1461 				if (ch == 's')
   1462 					Time_Mode = 1;
   1463 				else
   1464 					format_error = 1;
   1465 				break;
   1466 
   1467 			default:
   1468 				format_error = 1;
   1469 			}
   1470 
   1471 			if (Iterations < 0)
   1472 				format_error = 1;
   1473 
   1474 			if (format_error) {
   1475 				fprintf(stderr,
   1476 					"iogen%s:  Illegal -i arg (%s):  Must be of the format:  number[s]\n",
   1477 					TagName, optarg);
   1478 				fprintf(stderr,
   1479 					"        where 'number' is >= 0\n");
   1480 				exit(1);
   1481 			}
   1482 
   1483 			i_opt++;
   1484 			break;
   1485 
   1486 		case 'L':
   1487 #ifdef linux
   1488 			fprintf(stderr,
   1489 				"iogen%s:  Unrecognized option -L on this platform\n",
   1490 				TagName);
   1491 			exit(2);
   1492 #else
   1493 			if (parse_ranges(optarg, 1, 255, 1, NULL, &ranges,
   1494 					 &errmsg) == -1) {
   1495 				fprintf(stderr,
   1496 					"iogen%s: error parsing listio range '%s': %s\n",
   1497 					TagName, optarg, errmsg);
   1498 				exit(1);
   1499 			}
   1500 
   1501 			Minstrides = range_min(ranges, 0);
   1502 			Maxstrides = range_max(ranges, 0);
   1503 
   1504 			free(ranges);
   1505 			L_opt++;
   1506 #endif
   1507 			break;
   1508 
   1509 		case 'm':
   1510 			if ((Offset_Mode =
   1511 			     str_lookup(Omode_Map, optarg)) == NULL) {
   1512 				fprintf(stderr,
   1513 					"iogen%s:  Illegal -m arg (%s)\n",
   1514 					TagName, optarg);
   1515 				exit(1);
   1516 			}
   1517 
   1518 			m_opt++;
   1519 			break;
   1520 
   1521 		case 'N':
   1522 			sprintf(TagName, "(%.39s)", optarg);
   1523 			break;
   1524 
   1525 		case 'o':
   1526 			o_opt++;
   1527 			break;
   1528 
   1529 		case 'O':
   1530 
   1531 			nopenargs = string_to_tokens(optarg, openargs, 4, ":/");
   1532 
   1533 #ifdef CRAY
   1534 			if (nopenargs)
   1535 				sscanf(openargs[1], "%i", &Ocbits);
   1536 			if (nopenargs > 1)
   1537 				sscanf(openargs[2], "%i", &Ocblks);
   1538 
   1539 			Oflags = parse_open_flags(openargs[0], &errmsg);
   1540 			if (Oflags == -1) {
   1541 				fprintf(stderr, "iogen%s: -O %s error: %s\n",
   1542 					TagName, optarg, errmsg);
   1543 				exit(1);
   1544 			}
   1545 #endif
   1546 #ifdef linux
   1547 			Oflags = parse_open_flags(openargs[0], &errmsg);
   1548 			if (Oflags == -1) {
   1549 				fprintf(stderr, "iogen%s: -O %s error: %s\n",
   1550 					TagName, optarg, errmsg);
   1551 				exit(1);
   1552 			}
   1553 #endif
   1554 #ifdef sgi
   1555 			if (!strcmp(openargs[0], "realtime")) {
   1556 				/*
   1557 				 * -O realtime:extsize
   1558 				 */
   1559 				Orealtime = 1;
   1560 				if (nopenargs > 1)
   1561 					sscanf(openargs[1], "%i", &Oextsize);
   1562 				else
   1563 					Oextsize = 0;
   1564 			} else if (!strcmp(openargs[0], "allocate") ||
   1565 				   !strcmp(openargs[0], "allocsp")) {
   1566 				/*
   1567 				 * -O allocate
   1568 				 */
   1569 				Oreserve = 0;
   1570 				Oallocate = 1;
   1571 			} else if (!strcmp(openargs[0], "reserve")) {
   1572 				/*
   1573 				 * -O [no]reserve
   1574 				 */
   1575 				Oallocate = 0;
   1576 				Oreserve = 1;
   1577 			} else if (!strcmp(openargs[0], "noreserve")) {
   1578 				/* Oreserve=1 by default; this clears that default */
   1579 				Oreserve = 0;
   1580 			} else if (!strcmp(openargs[0], "nowrite")) {
   1581 				/* Owrite=1 by default; this clears that default */
   1582 				Owrite = 0;
   1583 			} else if (!strcmp(openargs[0], "direct")) {
   1584 				/* this means "use direct i/o to preallocate file" */
   1585 				Owrite = 2;
   1586 			} else {
   1587 				fprintf(stderr,
   1588 					"iogen%s: Error: -O %s error: unrecognized option\n",
   1589 					TagName, openargs[0]);
   1590 				exit(1);
   1591 			}
   1592 #endif
   1593 
   1594 			O_opt++;
   1595 			break;
   1596 
   1597 		case 'p':
   1598 			Outpipe = optarg;
   1599 			p_opt++;
   1600 			break;
   1601 
   1602 		case 'r':
   1603 			if ((Rawmult = bytes_by_prefix(optarg)) == -1 ||
   1604 			    Rawmult < 11 || Rawmult % BSIZE) {
   1605 				fprintf(stderr,
   1606 					"iogen%s:  Illegal -r arg (%s).  Must be > 0 and multipe of BSIZE (%d)\n",
   1607 					TagName, optarg, BSIZE);
   1608 				exit(1);
   1609 			}
   1610 
   1611 			r_opt++;
   1612 			break;
   1613 
   1614 		case 's':
   1615 			cp = strtok(optarg, ",");
   1616 			while (cp != NULL) {
   1617 				if ((sc = str_lookup(Syscall_Map, cp)) == NULL) {
   1618 					fprintf(stderr,
   1619 						"iogen%s:  Unrecognized syscall:  %s\n",
   1620 						TagName, cp);
   1621 					exit(2);
   1622 				}
   1623 
   1624 				do {
   1625 					/* >>> sc->m_flags & FLG_SDS */
   1626 					if (sc->m_value != SSREAD
   1627 					    && sc->m_value != SSWRITE)
   1628 						Fileio++;
   1629 
   1630 					Syscall_List[Nsyscalls++] = sc;
   1631 				} while ((sc = str_lookup(++sc, cp)) != NULL);
   1632 
   1633 				cp = strtok(NULL, ",");
   1634 			}
   1635 			s_opt++;
   1636 			break;
   1637 
   1638 		case 't':
   1639 			if ((Mintrans = bytes_by_prefix(optarg)) == -1) {
   1640 				fprintf(stderr,
   1641 					"iogen%s:  Illegal -t arg (%s):  Must have the form num[bkm]\n",
   1642 					TagName, optarg);
   1643 				exit(1);
   1644 			}
   1645 			t_opt++;
   1646 			break;
   1647 
   1648 		case 'T':
   1649 			if ((Maxtrans = bytes_by_prefix(optarg)) == -1) {
   1650 				fprintf(stderr,
   1651 					"iogen%s:  Illegal -T arg (%s):  Must have the form num[bkm]\n",
   1652 					TagName, optarg);
   1653 				exit(1);
   1654 			}
   1655 			T_opt++;
   1656 			break;
   1657 
   1658 		case 'q':
   1659 			q_opt++;
   1660 			break;
   1661 
   1662 		case '?':
   1663 			usage(stderr);
   1664 			exit(1);
   1665 		}
   1666 	}
   1667 
   1668 	/*
   1669 	 * Supply defaults
   1670 	 */
   1671 
   1672 	if (!L_opt) {
   1673 		Minstrides = 1;
   1674 		Maxstrides = 255;
   1675 	}
   1676 
   1677 	if (!m_opt)
   1678 		Offset_Mode = str_lookup(Omode_Map, "sequential");
   1679 
   1680 	if (!i_opt)
   1681 		Iterations = 0;
   1682 
   1683 	if (!t_opt)
   1684 		Mintrans = 1;
   1685 
   1686 	if (!T_opt)
   1687 		Maxtrans = 256 * BSIZE;
   1688 
   1689 	if (!O_opt)
   1690 		Oflags = Ocbits = Ocblks = 0;
   1691 
   1692 	/*
   1693 	 * Supply default async io completion strategy types.
   1694 	 */
   1695 
   1696 	if (!a_opt) {
   1697 		for (mp = Aio_Strat_Map; mp->m_string != NULL; mp++) {
   1698 			Aio_Strat_List[Naio_Strat_Types++] = mp;
   1699 		}
   1700 	}
   1701 
   1702 	/*
   1703 	 * Supply default syscalls.  Default is read,write,reada,writea,listio.
   1704 	 */
   1705 
   1706 	if (!s_opt) {
   1707 		Nsyscalls = 0;
   1708 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "read");
   1709 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "write");
   1710 #ifdef CRAY
   1711 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "reada");
   1712 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writea");
   1713 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lread");
   1714 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lreada");
   1715 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwrite");
   1716 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwritea");
   1717 #endif
   1718 
   1719 #ifdef sgi
   1720 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pread");
   1721 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pwrite");
   1722 		/*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "aread"); */
   1723 		/*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "awrite"); */
   1724 #endif
   1725 
   1726 #ifndef CRAY
   1727 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "readv");
   1728 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writev");
   1729 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmread");
   1730 		Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmwrite");
   1731 #endif
   1732 
   1733 		Fileio = 1;
   1734 	}
   1735 
   1736 	if (Fileio && (argc - optind < 1)) {
   1737 		fprintf(stderr, "iogen%s:  No files specified on the cmdline\n",
   1738 			TagName);
   1739 		exit(1);
   1740 	}
   1741 
   1742 	/*
   1743 	 * Supply default file io flags - defaut is 'buffered,raw,sync,ldraw'.
   1744 	 */
   1745 
   1746 	if (!f_opt && Fileio) {
   1747 		Nflags = 0;
   1748 		Flag_List[Nflags++] = str_lookup(Flag_Map, "buffered");
   1749 		Flag_List[Nflags++] = str_lookup(Flag_Map, "sync");
   1750 #ifdef CRAY
   1751 		Flag_List[Nflags++] = str_lookup(Flag_Map, "raw+wf");
   1752 		Flag_List[Nflags++] = str_lookup(Flag_Map, "ldraw");
   1753 #endif
   1754 
   1755 #ifdef sgi
   1756 		/* Warning: cannot mix direct i/o with others! */
   1757 		Flag_List[Nflags++] = str_lookup(Flag_Map, "dsync");
   1758 		Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync");
   1759 		/* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+sync"); */
   1760 		/* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+dsync"); */
   1761 #endif
   1762 	}
   1763 
   1764 	if (Fileio) {
   1765 		if (optind >= argc) {
   1766 			fprintf(stderr,
   1767 				"iogen%s:  No files listed on the cmdline\n",
   1768 				TagName);
   1769 			exit(1);
   1770 		}
   1771 
   1772 		/*
   1773 		 * Initialize File_List[] - only necessary if doing file io.  First
   1774 		 * space for the File_List array, then fill it in.
   1775 		 */
   1776 
   1777 		File_List = malloc((argc - optind) * sizeof(struct file_info));
   1778 
   1779 		if (File_List == NULL) {
   1780 			fprintf(stderr,
   1781 				"iogen%s:  Could not malloc space for %d file_info structures\n",
   1782 				TagName, argc - optind);
   1783 			exit(2);
   1784 		}
   1785 
   1786 		memset(File_List, 0,
   1787 		       (argc - optind) * sizeof(struct file_info));
   1788 
   1789 		Nfiles = 0;
   1790 		while (optind < argc) {
   1791 			len = -1;
   1792 
   1793 			/*
   1794 			 * Pick off leading len: if it's there and create/extend/trunc
   1795 			 * the file to the desired length.  Otherwise, just make sure
   1796 			 * the file is accessable.
   1797 			 */
   1798 
   1799 			if ((cp = strchr(argv[optind], ':')) != NULL) {
   1800 				*cp = '\0';
   1801 				if ((len = bytes_by_prefix(argv[optind])) == -1) {
   1802 					fprintf(stderr,
   1803 						"iogen%s:  illegal file length (%s) for file %s\n",
   1804 						TagName, argv[optind], cp + 1);
   1805 					exit(2);
   1806 				}
   1807 				*cp = ':';
   1808 				file = cp + 1;
   1809 
   1810 				if (strlen(file) > MAX_FNAME_LENGTH) {
   1811 					fprintf(stderr,
   1812 						"iogen%s:  Max fname length is %d chars - ignoring file %s\n",
   1813 						TagName, MAX_FNAME_LENGTH,
   1814 						file);
   1815 					optind++;
   1816 					continue;
   1817 				}
   1818 
   1819 				nb = create_file(file, len);
   1820 
   1821 				if (nb < len) {
   1822 					fprintf(stderr,
   1823 						"iogen%s warning:  Couldn't create file %s of %d bytes\n",
   1824 						TagName, file, len);
   1825 
   1826 					if (nb <= 0) {
   1827 						optind++;
   1828 						continue;
   1829 					}
   1830 				}
   1831 			} else {
   1832 				file = argv[optind];
   1833 				if (access(file, R_OK | W_OK) == -1) {
   1834 					fprintf(stderr,
   1835 						"iogen%s:  file %s cannot be accessed for reading and/or writing:  %s (%d)\n",
   1836 						TagName, file, SYSERR, errno);
   1837 					exit(2);
   1838 				}
   1839 			}
   1840 
   1841 			/*
   1842 			 * get per-file information
   1843 			 */
   1844 
   1845 			fptr = &File_List[Nfiles];
   1846 
   1847 			if (file[0] == '/') {
   1848 				strcpy(fptr->f_path, file);
   1849 			} else {
   1850 				if (getcwd
   1851 				    (fptr->f_path,
   1852 				     sizeof(fptr->f_path) - 1) == NULL)
   1853 					perror
   1854 					    ("Could not get current working directory");
   1855 				strcat(fptr->f_path, "/");
   1856 				strcat(fptr->f_path, file);
   1857 			}
   1858 
   1859 			if (get_file_info(fptr) == -1) {
   1860 				fprintf(stderr,
   1861 					"iogen%s warning:  Error getting file info for %s\n",
   1862 					TagName, file);
   1863 			} else {
   1864 
   1865 				/*
   1866 				 * If the file length is smaller than our min transfer size,
   1867 				 * ignore it.
   1868 				 */
   1869 
   1870 				if (fptr->f_length < Mintrans) {
   1871 					fprintf(stderr,
   1872 						"iogen%s warning:  Ignoring file %s\n",
   1873 						TagName, fptr->f_path);
   1874 					fprintf(stderr,
   1875 						"                length (%d) is < min transfer size (%d)\n",
   1876 						fptr->f_length, Mintrans);
   1877 					optind++;
   1878 					continue;
   1879 				}
   1880 
   1881 				/*
   1882 				 * If the file length is smaller than our max transfer size,
   1883 				 * ignore it.
   1884 				 */
   1885 
   1886 				if (fptr->f_length < Maxtrans) {
   1887 					fprintf(stderr,
   1888 						"iogen%s warning:  Ignoring file %s\n",
   1889 						TagName, fptr->f_path);
   1890 					fprintf(stderr,
   1891 						"                length (%d) is < max transfer size (%d)\n",
   1892 						fptr->f_length, Maxtrans);
   1893 					optind++;
   1894 					continue;
   1895 				}
   1896 
   1897 				if (fptr->f_length > 0) {
   1898 					switch (Offset_Mode->m_value) {
   1899 					case M_SEQUENTIAL:
   1900 						fptr->f_lastoffset = 0;
   1901 						fptr->f_lastlength = 0;
   1902 						break;
   1903 
   1904 					case M_REVERSE:
   1905 						fptr->f_lastoffset =
   1906 						    fptr->f_length;
   1907 						fptr->f_lastlength = 0;
   1908 						break;
   1909 
   1910 					case M_RANDOM:
   1911 						fptr->f_lastoffset =
   1912 						    fptr->f_length / 2;
   1913 						fptr->f_lastlength = 0;
   1914 						break;
   1915 					}
   1916 
   1917 					Nfiles++;
   1918 				}
   1919 			}
   1920 
   1921 			optind++;
   1922 		}
   1923 
   1924 		if (Nfiles == 0) {
   1925 			fprintf(stderr,
   1926 				"iogen%s:  Could not create, or gather info for any test files\n",
   1927 				TagName);
   1928 			exit(2);
   1929 		}
   1930 	}
   1931 
   1932 	return 0;
   1933 }
   1934 
   1935 int help(FILE * stream)
   1936 {
   1937 	usage(stream);
   1938 	fprintf(stream, "\n");
   1939 #ifndef linux
   1940 	fprintf(stream,
   1941 		"\t-a aio_type,...  Async io completion types to choose.  Supported types\n");
   1942 #ifdef CRAY
   1943 #if _UMK || RELEASE_LEVEL >= 8000
   1944 	fprintf(stream,
   1945 		"\t                 are:  poll, signal, recall, recalla, and recalls.\n");
   1946 #else
   1947 	fprintf(stream,
   1948 		"\t                 are:  poll, signal, recalla, and recalls.\n");
   1949 #endif
   1950 #else
   1951 	fprintf(stream,
   1952 		"\t                 are:  poll, signal, suspend, and callback.\n");
   1953 #endif
   1954 	fprintf(stream, "\t                 Default is all of the above.\n");
   1955 #else /* !linux */
   1956 	fprintf(stream, "\t-a               (Not used on Linux).\n");
   1957 #endif /* !linux */
   1958 	fprintf(stream,
   1959 		"\t-f flag,...      Flags to use for file IO.  Supported flags are\n");
   1960 #ifdef CRAY
   1961 	fprintf(stream,
   1962 		"\t                 raw, ssd, buffered, ldraw, sync,\n");
   1963 	fprintf(stream,
   1964 		"\t                 raw+wf, raw+wf+ldraw, raw+wf+ldraw+sync,\n");
   1965 	fprintf(stream,
   1966 		"\t                 and parallel (unicos/mk on MPP only).\n");
   1967 	fprintf(stream,
   1968 		"\t                 Default is 'raw,ldraw,sync,buffered'.\n");
   1969 #else
   1970 #ifdef sgi
   1971 	fprintf(stream,
   1972 		"\t                 buffered, direct, sync, dsync, rsync,\n");
   1973 	fprintf(stream, "\t                 rsync+dsync.\n");
   1974 	fprintf(stream,
   1975 		"\t                 Default is 'buffered,sync,dsync,rsync'.\n");
   1976 #else
   1977 	fprintf(stream, "\t                 buffered, sync.\n");
   1978 	fprintf(stream, "\t                 Default is 'buffered,sync'.\n");
   1979 #endif /* sgi */
   1980 #endif /* CRAY */
   1981 	fprintf(stream, "\t-h               This help.\n");
   1982 	fprintf(stream,
   1983 		"\t-i iterations[s] # of requests to generate.  0 means causes iogen\n");
   1984 	fprintf(stream,
   1985 		"\t                 to run until it's killed.  If iterations is suffixed\n");
   1986 	fprintf(stream,
   1987 		"\t                 with 's', then iterations is the number of seconds\n");
   1988 	fprintf(stream,
   1989 		"\t                 that iogen should run for.  Default is '0'.\n");
   1990 #ifndef linux
   1991 	fprintf(stream,
   1992 		"\t-L min:max       listio nstrides / nrequests range\n");
   1993 #else
   1994 	fprintf(stream, "\t-L               (Not used on Linux).\n");
   1995 #endif /* !linux */
   1996 	fprintf(stream,
   1997 		"\t-m offset-mode   The mode by which iogen chooses the offset for\n");
   1998 	fprintf(stream,
   1999 		"\t                 consectutive transfers within a given file.\n");
   2000 	fprintf(stream,
   2001 		"\t                 Allowed values are 'random', 'sequential',\n");
   2002 	fprintf(stream, "\t                 and 'reverse'.\n");
   2003 	fprintf(stream, "\t                 sequential is the default.\n");
   2004 	fprintf(stream, "\t-N tagname       Tag name, for Monster.\n");
   2005 	fprintf(stream,
   2006 		"\t-o               Form overlapping consecutive requests.\n");
   2007 	fprintf(stream, "\t-O               Open flags for creating files\n");
   2008 #ifdef CRAY
   2009 	fprintf(stream,
   2010 		"\t                 {O_PLACE,O_BIG,etc}[:CBITS[:CBLKS]]\n");
   2011 #endif
   2012 #ifdef sgi
   2013 	fprintf(stream,
   2014 		"\t                 realtime:extsize - put file on real-time volume\n");
   2015 	fprintf(stream,
   2016 		"\t                 allocate - allocate space with F_ALLOCSP\n");
   2017 	fprintf(stream,
   2018 		"\t                 reserve - reserve space with F_RESVSP (default)\n");
   2019 	fprintf(stream,
   2020 		"\t                 noreserve - do not reserve with F_RESVSP\n");
   2021 	fprintf(stream,
   2022 		"\t                 direct - use O_DIRECT I/O to write to the file\n");
   2023 #endif
   2024 #ifdef linux
   2025 	fprintf(stream, "\t                 {O_SYNC,etc}\n");
   2026 #endif
   2027 	fprintf(stream,
   2028 		"\t-p               Output pipe.  Default is stdout.\n");
   2029 	fprintf(stream,
   2030 		"\t-q               Quiet mode.  Normally iogen spits out info\n");
   2031 	fprintf(stream,
   2032 		"\t                 about test files, options, etc. before starting.\n");
   2033 	fprintf(stream,
   2034 		"\t-s syscall,...   Syscalls to do.  Supported syscalls are\n");
   2035 #ifdef sgi
   2036 	fprintf(stream,
   2037 		"\t                 read, write, pread, pwrite, readv, writev\n");
   2038 	fprintf(stream,
   2039 		"\t                 aread, awrite, resvsp, unresvsp, ffsync,\n");
   2040 	fprintf(stream,
   2041 		"\t                 mmread, mmwrite, fsync2, fdatasync,\n");
   2042 	fprintf(stream,
   2043 		"\t                 Default is 'read,write,pread,pwrite,readv,writev,mmread,mmwrite'.\n");
   2044 #endif
   2045 #ifdef CRAY
   2046 	fprintf(stream,
   2047 		"\t                 read, write, reada, writea, listio,\n");
   2048 	fprintf(stream,
   2049 		"\t                 ssread (PVP only), and sswrite (PVP only).\n");
   2050 	fprintf(stream,
   2051 		"\t                 Default is 'read,write,reada,writea,listio'.\n");
   2052 #endif
   2053 #ifdef linux
   2054 	fprintf(stream, "\t                 read, write, readv, writev,\n");
   2055 	fprintf(stream,
   2056 		"\t                 mmread, mmwrite, fsync2, fdatasync,\n");
   2057 	fprintf(stream,
   2058 		"\t                 Default is 'read,write,readv,writev,mmread,mmwrite'.\n");
   2059 #endif
   2060 	fprintf(stream, "\t-t mintrans      Min transfer length\n");
   2061 	fprintf(stream, "\t-T maxtrans      Max transfer length\n");
   2062 	fprintf(stream, "\n");
   2063 	fprintf(stream,
   2064 		"\t[len:]file,...   Test files to do IO against (note ssread/sswrite\n");
   2065 	fprintf(stream,
   2066 		"\t                 don't need a test file).  The len: syntax\n");
   2067 	fprintf(stream,
   2068 		"\t                 informs iogen to first create/expand/truncate the\n");
   2069 	fprintf(stream, "\t                 to the desired length.\n");
   2070 	fprintf(stream, "\n");
   2071 	fprintf(stream,
   2072 		"\tNote:  The ssd flag causes sds transfers to also be done.\n");
   2073 	fprintf(stream,
   2074 		"\t       To totally eliminate sds transfers, you must eleminate sds\n");
   2075 	fprintf(stream,
   2076 		"\t       from the flags (-f) and ssread,ssrite from the syscalls (-s)\n");
   2077 	fprintf(stream,
   2078 		"\tThe mintrans, maxtrans, and len: parameters are numbers of the\n");
   2079 	fprintf(stream,
   2080 		"\tform [0-9]+[bkm].  The optional trailing b, k, or m multiplies\n");
   2081 	fprintf(stream,
   2082 		"\tthe number by blocks, kilobytes, or megabytes.  If no trailing\n");
   2083 	fprintf(stream,
   2084 		"\tmultiplier is present, the number is interpreted as bytes\n");
   2085 
   2086 	return 0;
   2087 }
   2088 
   2089 /*
   2090  * Obvious - usage clause
   2091  */
   2092 
   2093 int usage(FILE * stream)
   2094 {
   2095 	fprintf(stream,
   2096 		"usage%s:  iogen [-hoq] [-a aio_type,...] [-f flag[,flag...]] [-i iterations] [-p outpipe] [-m offset-mode] [-s syscall[,syscall...]] [-t mintrans] [-T maxtrans] [ -O file-create-flags ] [[len:]file ...]\n",
   2097 		TagName);
   2098 	return 0;
   2099 }
   2100