xref: /third_party/ltp/testcases/kernel/fs/doio/iogen.c (revision f08c3bdf)
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__
84extern char *sys_errlist[];
85#endif
86#define SYSERR	strerror(errno)
87
88/*
89 * Structure for retaining test file information
90 */
91
92struct 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
110struct strmap {
111	char *m_string;
112	int m_value;
113	int m_flags;
114};
115
116void startup_info(FILE * stream, int seed);
117int init_output(void);
118int form_iorequest(struct io_req *req);
119int get_file_info(struct file_info *rec);
120int create_file(char *path, int nbytes);
121int str_to_value(struct strmap *map, char *str);
122struct strmap *str_lookup(struct strmap *map, char *str);
123char *value_to_string(struct strmap *map, int val);
124int parse_cmdline(int argc, char **argv, char *opts);
125int help(FILE * stream);
126int 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
134int a_opt = 0;			/* async io comp. types supplied            */
135int o_opt = 0;			/* form overlapping requests                */
136int f_opt = 0;			/* test flags                               */
137int i_opt = 0;			/* iterations - 0 implies infinite          */
138int L_opt = 0;			/* listio min-max nstrides & nents          */
139int m_opt = 0;			/* offset mode                              */
140int O_opt = 0;			/* file creation Open flags                 */
141int p_opt = 0;			/* output pipe - default is stdout          */
142int r_opt = 0;			/* specify raw io multiple instead of       */
143				/* getting it from the mounted on device.   */
144				/* Only applies to regular files.           */
145int s_opt = 0;			/* syscalls                                 */
146int t_opt = 0;			/* min transfer size (bytes)                */
147int T_opt = 0;			/* max transfer size (bytes)                */
148int q_opt = 0;			/* quiet operation on startup               */
149char TagName[40];		/* name of this iogen (see Monster)         */
150struct strmap *Offset_Mode;	/* M_SEQUENTIAL, M_RANDOM, etc.             */
151int Iterations;			/* # requests to generate (0 --> infinite)  */
152int Time_Mode = 0;		/* non-zero if Iterations is in seconds     */
153				/* (ie. -i arg was suffixed with 's')       */
154char *Outpipe;			/* Pipe to write output to if p_opt         */
155int Mintrans;			/* min io transfer size                     */
156int Maxtrans;			/* max io transfer size                     */
157int Rawmult;			/* raw/ssd io multiple (from -r)            */
158int Minstrides;			/* min # of listio strides per request      */
159int Maxstrides;			/* max # of listio strides per request      */
160int Oflags;			/* open(2) flags for creating files         */
161int Ocbits;			/* open(2) cbits for creating files         */
162int Ocblks;			/* open(2) cblks for creating files         */
163int Orealtime = 0;		/* flag set for -O REALTIME                 */
164int Oextsize = 0;		/* real-time extent size                    */
165int Oreserve = 1;		/* flag for -O [no]reserve                  */
166int Oallocate = 0;		/* flag for -O allocate                     */
167int Owrite = 1;			/* flag for -O nowrite                      */
168
169int Nfiles = 0;			/* # files on cmdline                       */
170struct file_info *File_List;	/* info about each file                     */
171int Nflags = 0;			/* # flags on cmdline                       */
172struct strmap *Flag_List[128];	/* flags selected from cmdline              */
173int Nsyscalls = 0;		/* # syscalls on cmdline                    */
174struct strmap *Syscall_List[128];	/* syscalls selected on cmdline          */
175int Fileio = 0;			/* flag indicating that a file              */
176				/* io syscall has been chosen.              */
177int Naio_Strat_Types = 0;	/* # async io completion types              */
178struct 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
185struct 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
222struct 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
238struct 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
321struct 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
361struct 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
372int Sds_Avail;
373
374char 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
380int 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
447void 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 */
531int 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
578int 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
948int 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
1071int 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
1326int 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
1342struct 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
1358char *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
1374int 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
1935int 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
2093int 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