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