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 
main(int argc,char ** argv)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 
startup_info(FILE * stream,int seed)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  */
init_output(void)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 
form_iorequest(struct io_req * req)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 
get_file_info(struct file_info * rec)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 
create_file(char * path,int nbytes)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 
str_to_value(struct strmap * map,char * str)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 
str_lookup(struct strmap * map,char * str)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 
value_to_string(struct strmap * map,int val)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 
parse_cmdline(int argc,char ** argv,char * opts)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 
help(FILE * stream)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 
usage(FILE * stream)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