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