xfstests: remove unsupported conditionals
[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         { NULL,         -1              }
150 };
151
152 /*
153  * Offset_Mode #defines
154  */
155
156 #define M_RANDOM        1
157 #define M_SEQUENTIAL    2
158 #define M_REVERSE       3
159
160 /*
161  * Map offset mode (-m args) names to values
162  */
163
164 struct strmap   Omode_Map[] = {
165         { "random",             M_RANDOM        },
166         { "sequential",         M_SEQUENTIAL    },
167         { "reverse",            M_REVERSE       },
168         { NULL,                 -1              }
169 };
170
171 /*
172  * Map syscall names (-s args) to values - macros are defined in doio.h.
173  */
174 #define SY_ASYNC        00001
175 #define SY_WRITE        00002
176 #define SY_SDS          00010
177 #define SY_LISTIO       00020
178 #define SY_NENT         00100   /* multi entry vs multi stride >>> */
179
180 struct strmap   Syscall_Map[] = {
181         { "read",               READ,           0                       },
182         { "write",              WRITE,          SY_WRITE                },
183         { "pread",              PREAD                                   },
184         { "pwrite",             PWRITE,         SY_WRITE                },
185 #ifndef NO_XFS
186         { "resvsp",             RESVSP,         SY_WRITE                },
187         { "unresvsp",           UNRESVSP,       SY_WRITE                },
188         { "reserve",            RESVSP,         SY_WRITE                },
189         { "unreserve",          UNRESVSP,       SY_WRITE                },
190 #endif
191         { "readv",              READV                                   },
192         { "writev",             WRITEV,         SY_WRITE                },
193         { "mmread",             MMAPR                                   },
194         { "mmwrite",            MMAPW,          SY_WRITE                },
195         { "fsync2",             FSYNC2,         SY_WRITE                },
196         { "fdatasync",          FDATASYNC,      SY_WRITE                },
197         { NULL,                 -1      }
198 };
199
200 /*
201  * Map open flags (-f args) to values
202  */
203 #define FLG_RAW         00001
204
205 struct strmap   Flag_Map[] = {
206         { "buffered",           0,                      0       },
207         { "sync",               O_SYNC,                 0       },
208         { "direct",             O_DIRECT,               FLG_RAW },
209         { NULL,             -1          }
210 };
211
212 /*
213  * Map file types to strings
214  */
215
216 struct strmap   Ftype_Map[] = {
217         { "regular",    S_IFREG },
218         { "blk-spec",   S_IFBLK },
219         { "chr-spec",   S_IFCHR },
220         { NULL,         0 }
221 };
222
223 /*
224  * Misc declarations
225  */
226
227 int             Sds_Avail;
228
229 char    Byte_Patterns[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
230                               'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
231                               'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
232                               'Y', 'Z' };
233
234
235 int form_iorequest(struct io_req *);
236 int init_output();
237 int parse_cmdline(int argc, char **argv, char *opts);
238 int help(FILE *stream);
239 int usage(FILE *stream);
240
241
242 int
243 main(argc, argv)
244 int     argc;
245 char    **argv;
246 {
247     int             rseed, outfd, infinite;
248     time_t          start_time;
249     struct io_req   req;
250     
251     umask(0);
252     Sds_Avail = 0;
253     TagName[0] = '\0';
254     parse_cmdline(argc, argv, OPTS);
255
256     /*
257      * Initialize output descriptor.  
258      */
259     if (! p_opt) {
260         outfd = 1;
261     } else {
262         outfd = init_output();
263     }
264
265     rseed = getpid();
266     random_range_seed(rseed);       /* initialize random number generator */
267
268     /*
269      * Print out startup information, unless we're running in quiet mode
270      */
271     if (!q_opt)
272         startup_info(stderr, rseed);
273
274     start_time = time(0);
275
276     /*
277      * While iterations (or forever if Iterations == 0) - compute an
278      * io request, and write the structure to the output descriptor
279      */
280
281     infinite = !Iterations;
282
283     while (infinite ||
284            (! Time_Mode && Iterations--) ||
285            (Time_Mode && time(0) - start_time <= Iterations)) {
286
287         memset(&req, 0, sizeof(struct io_req));
288         if (form_iorequest(&req) == -1) {
289             fprintf(stderr, "iogen%s:  form_iorequest() failed\n", TagName);
290             continue;
291         }
292
293         req.r_magic = DOIO_MAGIC;
294         write(outfd, (char *)&req, sizeof(req));
295     }
296
297     exit(0);
298
299 }   /* main */
300
301 void
302 startup_info(FILE *stream, int seed)
303 {
304     char        *value_to_string(), *type;
305     int         i;
306
307     fprintf(stream, "\n");
308     fprintf(stream, "iogen%s starting up with the following:\n", TagName);
309     fprintf(stream, "\n");
310
311     fprintf(stream, "Out-pipe:              %s\n", 
312             p_opt ? Outpipe : "stdout");
313
314     if (Iterations) {
315         fprintf(stream, "Iterations:            %d", Iterations);
316         if (Time_Mode)
317             fprintf(stream, " seconds");
318
319         fprintf(stream, "\n");
320     } else {
321         fprintf(stream, "Iterations:            Infinite\n");
322     }
323
324     fprintf(stream,
325             "Seed:                  %d\n", seed);
326
327     fprintf(stream,
328             "Offset-Mode:           %s\n", Offset_Mode->m_string);
329
330     fprintf(stream, "Overlap Flag:          %s\n",
331             o_opt ? "on" : "off");
332
333     fprintf(stream,
334             "Mintrans:              %-11d (%d blocks)\n",
335             Mintrans, (Mintrans+BSIZE-1)/BSIZE);
336
337     fprintf(stream,
338             "Maxtrans:              %-11d (%d blocks)\n",
339             Maxtrans, (Maxtrans+BSIZE-1)/BSIZE);
340
341     if (! r_opt) 
342         fprintf(stream,
343                 "O_RAW/O_SSD Multiple:  (Determined by device)\n");
344     else
345         fprintf(stream,
346                 "O_RAW/O_SSD Multiple:  %-11d (%d blocks)\n",
347                 Rawmult, (Rawmult+BSIZE-1)/BSIZE);
348
349     fprintf(stream, "Syscalls:              ");
350     for (i = 0; i < Nsyscalls; i++)
351         fprintf(stream,
352                 "%s ", Syscall_List[i]->m_string);
353     fprintf(stream, "\n");
354
355     fprintf(stream, "Aio completion types:  ");
356     for (i = 0; i < Naio_Strat_Types; i++)
357         fprintf(stream,
358                 "%s ", Aio_Strat_List[i]->m_string);
359     fprintf(stream, "\n");
360
361     if (Fileio) {
362         fprintf(stream, "Flags:                 ");
363         for (i = 0; i < Nflags; i++)
364             fprintf(stream,
365                     "%s ", Flag_List[i]->m_string);
366
367         fprintf(stream, "\n");
368         fprintf(stream, "\n");
369         fprintf(stream, "Test Files:  \n");
370         fprintf(stream, "\n");
371         fprintf(stream,
372                 "Path                                          Length    iou   raw iou file\n");
373         fprintf(stream,
374                 "                                              (bytes) (bytes) (bytes) type\n"); 
375         fprintf(stream,
376                 "-----------------------------------------------------------------------------\n");
377
378         for (i = 0; i < Nfiles; i++) {
379             type = value_to_string(Ftype_Map, File_List[i].f_type);
380             fprintf(stream, "%-40s %12d %7d %7d %s\n",
381                     File_List[i].f_path, File_List[i].f_length,
382                     File_List[i].f_iou, File_List[i].f_riou, type);
383         }
384     }
385 }
386
387 /*
388  * Initialize output descriptor.  If going to stdout, its easy,
389  * otherwise, attempt to create a FIFO on path Outpipe.  Exit with an
390  * error code if this cannot be done.
391  */
392 int
393 init_output()
394 {
395     int  outfd;
396     struct stat     sbuf;
397
398     if (stat(Outpipe, &sbuf) == -1) {
399         if (errno == ENOENT) {
400             if (mkfifo(Outpipe, 0666) == -1) {
401                 fprintf(stderr, "iogen%s:  Could not mkfifo %s:  %s\n",
402                         TagName, Outpipe, SYSERR);
403                 exit(2);
404             }
405         } else {
406             fprintf(stderr, "iogen%s:  Could not stat outpipe %s:  %s\n",
407                     TagName, Outpipe, SYSERR);
408             exit(2);
409         }
410     } else {
411         if (! S_ISFIFO(sbuf.st_mode)) {
412             fprintf(stderr,
413                     "iogen%s:  Output file %s exists, but is not a FIFO\n",
414                     TagName, Outpipe);
415             exit(2);
416         }
417     }
418
419     if ((outfd = open(Outpipe, O_RDWR)) == -1) {
420         fprintf(stderr,
421                 "iogen%s:  Couldn't open outpipe %s with flags O_RDWR: %s\n",
422                 TagName, Outpipe, SYSERR);
423         exit(2);
424     }
425
426     return(outfd);
427 }
428
429
430 /*
431  * Main io generation function.  form_iorequest() selects a system call to
432  * do based on cmdline arguments, and proceeds to select parameters for that
433  * system call.
434  *
435  * Returns 0 if req is filled in with a complete doio request, otherwise
436  * returns -1.
437  */
438
439 int
440 form_iorequest(req)
441 struct io_req   *req;
442 {
443     int                 mult, offset = 0, length = 0, slength;
444     int                 minlength, maxlength, laststart, lastend;
445     int                 minoffset, maxoffset;
446     int                 maxstride, nstrides;
447     char                pattern, *errp;
448     struct strmap       *flags, *sc, *aio_strat;
449     struct file_info    *fptr;
450
451     /*
452      * Choose system call, flags, and file
453      */
454
455     sc = Syscall_List[random_range(0, Nsyscalls-1, 1, NULL)];
456     req->r_type = sc->m_value;
457
458     if( sc->m_flags & SY_WRITE )
459             pattern = Byte_Patterns[random_range(0, sizeof(Byte_Patterns) - 1, 1, NULL)];
460     else
461             pattern = 0;
462
463     /*
464      * otherwise, we're doing file io.  Choose starting offset, length,
465      * open flags, and possibly a pattern (for write/writea).
466      */
467
468     fptr = &File_List[random_range(0, Nfiles-1, 1, NULL)];
469     flags = Flag_List[random_range(0, Nflags-1, 1, NULL)];
470
471     /*
472      * Choose offset/length multiple.  IO going to a device, or regular
473      * IO that is O_RAW or O_SSD must be aligned on the file r_iou.  Otherwise
474      * it must be aligned on the regular iou (normally 1).
475      */
476
477     if ( fptr->f_type == S_IFREG && (flags->m_flags & FLG_RAW) )
478             mult = fptr->f_riou;
479     else
480             mult = fptr->f_iou;
481
482     /*
483      * Choose offset and length.  Both must be a multiple of mult
484      */
485
486     /*
487      * Choose length first - it must be a multiple of mult
488      */
489
490     laststart = fptr->f_lastoffset;
491     lastend = fptr->f_lastoffset + fptr->f_lastlength - 1;
492
493     minlength = (Mintrans > mult) ? Mintrans : mult;
494
495     switch (Offset_Mode->m_value) {
496     case M_SEQUENTIAL:
497         if (o_opt && lastend > laststart)
498             offset = random_range(laststart, lastend, 1, NULL);
499         else
500             offset = lastend + 1;
501         if (offset && (offset%mult))
502             offset += mult - (offset % mult);
503
504         if (minlength > fptr->f_length - offset)
505             offset = 0;
506
507         maxlength = fptr->f_length - offset;
508         if (maxlength > Maxtrans)
509             maxlength = Maxtrans;
510
511         length = random_range(minlength, maxlength, mult, &errp);
512         if (errp != NULL) {
513             fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
514                     TagName, minlength, maxlength, mult);
515             return -1;
516         }
517
518         break;
519
520     case M_REVERSE:
521         maxlength = laststart;
522
523         if (maxlength > Maxtrans)
524             maxlength = Maxtrans;
525
526         if (minlength > maxlength) {
527             laststart = fptr->f_length;
528             lastend = fptr->f_length;
529             maxlength = Maxtrans;
530         }
531
532         length = random_range(minlength, maxlength, mult, &errp);
533         if (errp != NULL) {
534             fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
535                     TagName, minlength, maxlength, mult);
536             return -1;
537         }
538
539         offset = laststart - length;
540
541         if (o_opt && lastend > laststart)
542             offset += random_range(1, lastend - laststart, 1, NULL);
543
544         if (offset &&  (offset%mult))
545             offset -= offset % mult;
546
547         break;
548     
549     case M_RANDOM:
550         length = random_range(Mintrans, Maxtrans, mult, NULL);
551
552         if (o_opt && lastend > laststart) {
553                 minoffset = laststart - length + 1;
554                 if (minoffset < 0) {
555                         minoffset = 0;
556                 }
557
558                 if (lastend + length > fptr->f_length) {
559                         maxoffset = fptr->f_length - length;
560                 } else {
561                         maxoffset = lastend;
562                 }
563         } else {
564             minoffset = 0;
565             maxoffset = fptr->f_length - length;
566         }
567
568         if (minoffset < 0)
569             minoffset = 0;
570
571         offset = random_range(minoffset, maxoffset, mult, &errp);
572         if (errp != NULL) {
573             fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
574                     TagName, minoffset, maxoffset, mult);
575             return -1;
576         }
577     }
578
579     fptr->f_lastoffset = offset;
580     fptr->f_lastlength = length;
581
582     /*
583      * Choose an async io completion strategy if necessary
584      */
585     if( sc->m_flags & SY_ASYNC )
586             aio_strat = Aio_Strat_List[random_range(0, Naio_Strat_Types - 1,
587                                                     1, NULL)];
588     else
589             aio_strat = NULL;
590
591     /*
592      * fill in specific syscall record data
593      */
594     switch (sc->m_value) {
595     case READ:
596     case READA:
597         strcpy(req->r_data.read.r_file, fptr->f_path);
598         req->r_data.read.r_oflags = O_RDONLY | flags->m_value;
599         req->r_data.read.r_offset = offset;
600         req->r_data.read.r_nbytes = length;
601         req->r_data.read.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
602         req->r_data.read.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
603         req->r_data.read.r_nstrides = 1;
604         req->r_data.read.r_nent = 1;
605         break;
606
607     case WRITE:
608     case WRITEA:
609         strcpy(req->r_data.write.r_file, fptr->f_path);
610         req->r_data.write.r_oflags = O_WRONLY | flags->m_value;
611         req->r_data.write.r_offset = offset;
612         req->r_data.write.r_nbytes = length;
613         req->r_data.write.r_pattern = pattern;
614         req->r_data.write.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
615         req->r_data.write.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
616         req->r_data.write.r_nstrides = 1;
617         req->r_data.write.r_nent = 1;
618         break;
619
620     case READV:
621     case AREAD:
622     case PREAD:
623     case WRITEV:
624     case AWRITE:
625     case PWRITE:
626
627     case LREAD:
628     case LREADA:
629     case LWRITE:
630     case LWRITEA:
631
632     case RESVSP:
633     case UNRESVSP:
634     case FSYNC2:
635     case FDATASYNC:
636
637         strcpy(req->r_data.io.r_file, fptr->f_path);
638         req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
639         req->r_data.io.r_offset = offset;
640         req->r_data.io.r_nbytes = length;
641         req->r_data.io.r_pattern = pattern;
642         req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
643         req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
644         req->r_data.io.r_nstrides = 1;
645         req->r_data.io.r_nent = 1;
646         break;
647
648     case MMAPR:
649     case MMAPW:
650         strcpy(req->r_data.io.r_file, fptr->f_path);
651         /* a subtle "feature" of mmap: a write-map requires
652            the file open read/write */
653         req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_RDWR : O_RDONLY) | flags->m_value;
654         req->r_data.io.r_offset = offset;
655         req->r_data.io.r_nbytes = length;
656         req->r_data.io.r_pattern = pattern;
657         req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
658         req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
659         req->r_data.io.r_nstrides = 1;
660         req->r_data.io.r_nent = 1;
661         break;
662
663     case LSREAD:
664     case LSREADA:
665     case LEREAD:
666     case LEREADA:
667     case LSWRITE:
668     case LSWRITEA:
669     case LEWRITE:
670     case LEWRITEA:
671         /* multi-strided */
672         strcpy(req->r_data.io.r_file, fptr->f_path);
673         req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
674         req->r_data.io.r_offset = offset;
675         req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
676         req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
677         req->r_data.io.r_pattern = pattern;
678
679         /* multi-strided request...
680          *  random number of strides (1...MaxStrides)
681          *  length of stride must be > minlength
682          *  length of stride must be % mult
683          *
684          * maxstrides = min(length / mult, overall.max#strides)
685          * nstrides = random #
686          * while( length / nstrides < minlength )
687          *      nstrides = new random #
688          */
689         maxstride = length / mult;
690         if(maxstride > Maxstrides)
691             maxstride = Maxstrides;
692
693         if(!Minstrides)
694                 Minstrides=1;
695         nstrides = random_range(Minstrides, maxstride, 1, &errp);
696         if (errp != NULL) {
697             fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
698                     TagName, Minstrides, maxstride, 1);
699             return -1;
700         }
701
702         slength = length / nstrides;
703         if(slength % mult != 0) {
704             if( mult > slength) {
705                 slength = mult;
706             } else {
707                 slength -= slength % mult;
708             }
709             nstrides = length / slength;
710             if(nstrides > Maxstrides)
711                     nstrides = Maxstrides;
712         }
713
714         req->r_data.io.r_nbytes = slength;
715         if( sc->m_flags & SY_NENT ) {
716                 req->r_data.io.r_nstrides = 1;
717                 req->r_data.io.r_nent = nstrides;
718         } else {
719                 req->r_data.io.r_nstrides = nstrides;
720                 req->r_data.io.r_nent = 1;
721         }
722         break;
723
724     case LISTIO:
725         break;
726     }
727
728     return 0;
729 }
730
731 /*
732  * Get information about a file that iogen uses to choose io length and
733  * offset.  Information gathered is file length, iounit, and raw iounit.
734  * For regurlar files, iounit is 1, and raw iounit is the iounit of the
735  * device on which the file resides.  For block/character special files
736  * the iounit and raw iounit are both the iounit of the device.
737  *
738  * Note:        buffered and osync io must be iounit aligned
739  *              raw and ossd io must be raw iounit aligned
740  */
741
742 int
743 get_file_info(rec)
744 struct file_info    *rec;
745 {
746     struct stat                 sbuf;
747 #ifndef NO_XFS
748     int                         fd;
749     struct dioattr              finfo;
750 #endif
751
752     /*
753      * Figure out if the files is regular, block or character special.  Any
754      * other type is an error.
755      */
756
757     if (stat(rec->f_path, &sbuf) == -1) {
758         fprintf(stderr, "iogen%s: get_file_info():  Could not stat() %s:  %s\n",
759                 TagName, rec->f_path, SYSERR);
760         return -1;
761     }
762
763     rec->f_type = sbuf.st_mode & S_IFMT;
764
765     /*
766      * If regular, iou is 1, and we must figure out the device on
767      * which the file resides.  riou is the iou (logical sector size) of
768      * this device.
769      */
770
771     if (S_ISREG(sbuf.st_mode)) {
772         rec->f_iou = 1;
773         rec->f_length = sbuf.st_size;
774
775         /*
776          * If -r used, take Rawmult as the raw/ssd io multiple.  Otherwise
777          * attempt to determine it by looking at the device the file
778          * resides on.
779          */
780
781         if (r_opt) {
782             rec->f_riou = Rawmult;
783             return 0;
784         }
785
786         rec->f_riou = BSIZE;
787 #ifndef NO_XFS
788         if( (fd = open(rec->f_path, O_RDWR|O_DIRECT, 0)) != -1 ) {
789 #ifdef XFS_IOC_DIOINFO
790             if(xfsctl(rec->f_path, fd, XFS_IOC_DIOINFO, &finfo) != -1) {
791 #else
792 #ifdef F_DIOINFO
793             if(fcntl(fd, F_DIOINFO, &finfo) != -1) {
794 #else
795 bozo!
796 #endif
797 #endif
798                 rec->f_riou = finfo.d_miniosz;
799             } else {
800                 fprintf(stderr,
801                         "iogen%s: Error %s (%d) getting direct I/O info of file %s\n",
802                         TagName, strerror(errno), errno, rec->f_path);
803             }
804             close(fd);
805         } else {
806             rec->f_riou = BBSIZE;
807         }
808 #endif
809     } else {
810
811         rec->f_riou = BSIZE;
812         rec->f_length = BSIZE;
813     }
814
815     return 0;
816 }
817
818 /*
819  * Create file path as nbytes long.  If path exists, the file will either be
820  * extended or truncated to be nbytes long.  Returns final size of file,
821  * or -1 if there was a failure.
822  */
823
824 int
825 create_file(path, nbytes)
826 char    *path;
827 int     nbytes;
828 {
829     int         fd, rval;
830     char        c;
831     struct stat sbuf;
832 #ifndef NO_XFS
833     int         nb;
834     struct flock64 f;
835     struct fsxattr xattr;
836     struct dioattr finfo;
837     char        *b, *buf;
838 #endif
839
840     errno = 0;
841     rval = stat(path, &sbuf);
842
843     if (rval == -1) {
844         if (errno == ENOENT) {
845             sbuf.st_size = 0;
846         } else {
847             fprintf(stderr, "iogen%s:  Could not stat file %s:  %s (%d)\n",
848                     TagName, path, SYSERR, errno);
849             return -1;
850         }
851     } else {
852         if (! S_ISREG(sbuf.st_mode)) {
853             fprintf(stderr,
854                     "iogen%s:  file %s exists, but is not a regular file - cannot modify length\n",
855                     TagName, path);
856             return -1;
857         }
858     }
859
860     if (sbuf.st_size == nbytes)
861         return nbytes;
862
863     Oflags |= O_CREAT | O_WRONLY;
864
865     if ((fd = open(path, Oflags, 0666)) == -1) {
866         fprintf(stderr, "iogen%s:  Could not create/open file %s: %s (%d)\n",
867                 TagName, path, SYSERR, errno);
868         return -1;
869     }
870
871     /*
872      * Truncate file if it is longer than nbytes, otherwise attempt to
873      * pre-allocate file blocks.
874      */
875
876     if (sbuf.st_size > nbytes) {
877         if (ftruncate(fd, nbytes) == -1) {
878             fprintf(stderr,
879                     "iogen%s:  Could not ftruncate() %s to %d bytes:  %s (%d)\n",
880                     TagName, path, nbytes, SYSERR, errno);
881             close(fd);
882             return -1;
883         }
884     } else {
885
886 #ifndef NO_XFS
887         /*
888          *  The file must be designated as Real-Time before any data
889          *  is allocated to it.
890          *
891          */
892         if(Orealtime != 0) {
893             bzero(&xattr, sizeof(xattr));
894             xattr.fsx_xflags = XFS_XFLAG_REALTIME;
895             /*fprintf(stderr, "set: fsx_xflags = 0x%x\n", xattr.fsx_xflags);*/
896 #ifdef XFS_IOC_FSSETXATTR
897             if( xfsctl(path, fd, XFS_IOC_FSSETXATTR, &xattr) == -1 ) {
898 #else
899 #ifdef F_FSSETXATTR
900                     if (fcntl(fd, F_FSSETXATTR, &xattr) < 0) {
901 #else
902 bozo!
903 #endif
904 #endif
905                 fprintf(stderr, "iogen%s: Error %s (%d) setting XFS XATTR->Realtime on file %s\n",
906                         TagName, SYSERR, errno, path);
907                 close(fd);
908                 return -1;
909             }
910
911 #ifdef DEBUG
912 #ifdef XFS_IOC_FSGETXATTR
913             if( xfsctl(path, fd, XFS_IOC_FSGETXATTR, &xattr) == -1 ) {
914 #else
915 #ifdef F_FSGETXATTR
916             if (fcntl(fd, F_FSGETXATTR, &xattr) < 0) {
917 #else
918 bozo!
919 #endif
920 #endif
921                 fprintf(stderr, "iogen%s: Error getting realtime flag %s (%d)\n",
922                         TagName, SYSERR, errno);
923                 close(fd);
924                 return -1;
925             } else {
926                 fprintf(stderr, "get: fsx_xflags = 0x%x\n", 
927                         xattr.fsx_xflags);
928             }
929 #endif
930         }
931
932         /*
933          * Reserve space
934          *
935          * Failure is ignored since XFS_IOC_RESVSP only works on XFS and the
936          * filesystem could be on some otehr filesystem.
937          */
938         if( Oreserve ) {
939             f.l_whence = SEEK_SET;
940             f.l_start = 0;
941             f.l_len = nbytes;
942             
943             /*fprintf(stderr,
944                     "create_file: xfsctl(%d, RESVSP, { %d, %lld, %lld })\n",
945                    fd, f.l_whence, (long long)f.l_start, (long long)f.l_len);*/
946
947             /* non-zeroing reservation */
948 #ifdef XFS_IOC_RESVSP
949             if( xfsctl( path, fd, XFS_IOC_RESVSP, &f ) == -1) {
950                 fprintf(stderr,
951                         "iogen%s:  Could not xfsctl(XFS_IOC_RESVSP) %d bytes in file %s: %s (%d)\n",
952                         TagName, nbytes, path, SYSERR, errno);
953                 close(fd);
954                 return -1;
955             }
956 #else
957 #ifdef F_RESVSP
958             if( fcntl( fd, F_RESVSP, &f ) == -1) {
959                 fprintf(stderr,
960                         "iogen%s:  Could not fcntl(F_RESVSP) %d bytes in file %s: %s (%d)\n",
961                         TagName, nbytes, path, SYSERR, errno);
962                 close(fd);
963                 return -1;
964             }
965 #else
966 bozo!
967 #endif
968 #endif
969         }
970
971         if( Oallocate ) {
972             /* XFS_IOC_ALLOCSP allocates from the file start to l_start */
973             f.l_whence = SEEK_SET;
974             f.l_start = nbytes;
975             f.l_len = 0;
976             /*fprintf(stderr,
977                     "create_file: xfsctl(%d, XFS_IOC_ALLOCSP, { %d, %lld, %lld })\n",
978                     fd, f.l_whence, (long long)f.l_start,
979                     (long long)f.l_len);*/
980
981             /* zeroing reservation */
982 #ifdef XFS_IOC_ALLOCSP
983             if( xfsctl( path, fd, XFS_IOC_ALLOCSP, &f ) == -1) {
984                 fprintf(stderr,
985                         "iogen%s:  Could not xfsctl(XFS_IOC_ALLOCSP) %d bytes in file %s: %s (%d)\n",
986                         TagName, nbytes, path, SYSERR, errno);
987                 close(fd);
988                 return -1;
989             }
990 #else
991 #ifdef F_ALLOCSP
992             if ( fcntl(fd, F_ALLOCSP, &f) < 0) {
993                 fprintf(stderr,
994                         "iogen%s:  Could not fcntl(F_ALLOCSP) %d bytes in file %s: %s (%d)\n",
995                         TagName, nbytes, path, SYSERR, errno);
996                 close(fd);
997                 return -1;
998             }
999 #else
1000 bozo!
1001 #endif
1002 #endif
1003         }
1004 #endif
1005
1006         /*
1007          * Write a byte at the end of file so that stat() sets the right
1008          * file size.
1009          */
1010
1011 #ifndef NO_XFS
1012         if(Owrite == 2) {
1013             close(fd);
1014             if( (fd = open(path, O_CREAT|O_RDWR|O_DIRECT, 0)) != -1 ) {
1015 #ifdef XFS_IOC_DIOINFO
1016                 if(xfsctl(path, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
1017 #else
1018 #ifdef F_DIOINFO
1019                 if (fcntl(fd, F_DIOINFO, &finfo) < 0) {
1020 #else
1021 bozo!
1022 #endif
1023 #endif
1024                     fprintf(stderr,
1025                             "iogen%s: Error %s (%d) getting direct I/O info for file %s\n",
1026                             TagName, SYSERR, errno, path);
1027                     return -1;
1028                 } else {
1029                     /*fprintf(stderr, "%s: miniosz=%d\n", 
1030                             path, finfo.d_miniosz);*/
1031                 }
1032             } else {
1033                 fprintf(stderr, "iogen%s: Error %s (%d) opening file %s with flags O_CREAT|O_RDWR|O_DIRECT\n",
1034                         TagName, SYSERR, errno, path);
1035                 return -1;
1036             }
1037
1038             /*
1039              * nb is nbytes adjusted down by an even d_miniosz block
1040              *
1041              * Note: the first adjustment can cause iogen to print a warning 
1042              *  about not being able to create a file of <nbytes> length, 
1043              *  since the file will be shorter.
1044              */
1045             nb = nbytes-finfo.d_miniosz;
1046             nb = nb-nb%finfo.d_miniosz;
1047
1048             /*fprintf(stderr,
1049                     "create_file_ow2: lseek(%d, %d {%d %d}, SEEK_SET)\n",
1050                     fd, nb, nbytes, finfo.d_miniosz);*/
1051
1052             if (lseek(fd, nb, SEEK_SET) == -1) {
1053                 fprintf(stderr,
1054                         "iogen%s:  Could not lseek() to EOF of file %s: %s (%d)\n\tactual offset %d file size goal %d miniosz %lld\n",
1055                         TagName, path, SYSERR, errno,
1056                         nb, nbytes, (long long)finfo.d_miniosz);
1057                 close(fd);
1058                 return -1;
1059             }
1060
1061             b = buf = (char *)malloc(finfo.d_miniosz+finfo.d_mem);
1062
1063             if( ((long)buf % finfo.d_mem != 0) ) {
1064                 buf += finfo.d_mem - ((long)buf % finfo.d_mem);
1065             }
1066             
1067             memset(buf, 0, finfo.d_miniosz);
1068
1069             if ( (rval=write(fd, buf, finfo.d_miniosz)) != finfo.d_miniosz) {
1070                 fprintf(stderr,
1071                         "iogen%s:  Could not write %d byte length file %s: %s (%d)\n",
1072                         TagName, nb, path, SYSERR, errno);
1073                 fprintf(stderr,
1074                         "\twrite(%d, 0x%lx, %d) = %d\n",
1075                         fd, (long)buf, finfo.d_miniosz, rval);
1076                 fprintf(stderr,
1077                         "\toffset %d file size goal %d, miniosz=%d\n",
1078                         nb, nbytes, finfo.d_miniosz);
1079                 close(fd);
1080                 return -1;
1081             }
1082             free(b);
1083         } else
1084 #endif
1085             if(Owrite) {
1086             /*fprintf(stderr,
1087                     "create_file_Owrite: lseek(%d, %d {%d}, SEEK_SET)\n",
1088                     fd, nbytes-1, nbytes);*/
1089
1090             if (lseek(fd, nbytes-1, SEEK_SET) == -1) {
1091                 fprintf(stderr,
1092                         "iogen%s:  Could not lseek() to EOF in file %s:  %s (%d)\n\toffset goal %d\n",
1093                         TagName, path, SYSERR, errno,
1094                         nbytes-1);
1095                 close(fd);
1096                 return -1;
1097             }
1098
1099             if ( (rval=write(fd, &c, 1)) != 1) {
1100                 fprintf(stderr,
1101                         "iogen%s:  Could not create a %d byte length file %s: %s (%d)\n",
1102                         TagName, nbytes, path, SYSERR, errno);
1103                 fprintf(stderr,
1104                         "\twrite(%d, 0x%lx, %d) = %d\n",
1105                         fd, (long)&c, 1, rval);
1106                 fprintf(stderr,
1107                         "\toffset %d file size goal %d\n",
1108                         nbytes-1, nbytes);
1109                 close(fd);
1110                 return -1;
1111             }
1112         }
1113     }
1114
1115     fstat(fd, &sbuf);
1116     close(fd);
1117
1118     return sbuf.st_size;
1119 }
1120
1121 /*
1122  * Function to convert a string to its corresponding value in a strmap array.
1123  * If the string is not found in the array, the value corresponding to the
1124  * NULL string (the last element in the array) is returned.
1125  */
1126
1127 int
1128 str_to_value(map, str)
1129 struct strmap   *map;
1130 char            *str;
1131 {
1132     struct strmap   *mp;
1133
1134     for (mp = map; mp->m_string != NULL; mp++)
1135         if (strcmp(mp->m_string, str) == 0)
1136             break;
1137
1138     return mp->m_value;
1139 }
1140     
1141 /*
1142  * Function to convert a string to its corresponding entry in a strmap array.
1143  * If the string is not found in the array, a NULL is returned.
1144  */
1145
1146 struct strmap *
1147 str_lookup(map, str)
1148 struct strmap   *map;
1149 char            *str;
1150 {
1151     struct strmap   *mp;
1152
1153     for (mp = map; mp->m_string != NULL; mp++)
1154         if (strcmp(mp->m_string, str) == 0)
1155             break;
1156
1157     return((mp->m_string == NULL) ? NULL : mp);
1158 }
1159     
1160
1161 /*
1162  * Function to convert a value to its corresponding string in a strmap array.
1163  * If the value is not found in the array, NULL is returned.
1164  */
1165
1166 char *
1167 value_to_string(map, val)
1168 struct strmap   *map;
1169 int             val;
1170 {
1171     struct strmap  *mp;
1172
1173     for (mp = map; mp->m_string != NULL; mp++)
1174         if (mp->m_value == val)
1175             break;
1176
1177     return mp->m_string;
1178 }
1179
1180 /*
1181  * Interpret cmdline options/arguments.  Exit with 1 if something on the
1182  * cmdline isn't kosher.
1183  */
1184
1185 int
1186 parse_cmdline(argc, argv, opts)
1187 int     argc;
1188 char    **argv;
1189 char    *opts;
1190 {
1191     int                 o, len, nb, format_error;
1192     struct strmap       *flgs, *sc;
1193     char                *file, *cp, ch;
1194     struct strmap       *mp;
1195     struct file_info    *fptr;
1196     int                 nopenargs;
1197     char                *openargs[5];   /* Flags, cbits, cblks */
1198     while ((o = getopt(argc, argv, opts)) != EOF) {
1199         switch ((char)o) {
1200
1201         case 'a':
1202             fprintf(stderr, "iogen%s:  Unrecognized option -a on this platform\n", TagName);
1203             exit(2);
1204             break;
1205
1206         case 'f':
1207             cp = strtok(optarg, ",");
1208             while (cp != NULL) {
1209                 if( (flgs = str_lookup(Flag_Map, cp)) == NULL ) {
1210                     fprintf(stderr, "iogen%s:  Unrecognized flags:  %s\n", TagName, cp);
1211                     exit(2);
1212                 }
1213
1214                 cp = strtok(NULL, ",");
1215
1216 #ifdef O_SSD
1217                 if (flgs->m_value & O_SSD && ! Sds_Avail) {
1218                     fprintf(stderr, "iogen%s:  Warning - no sds available, ignoring ssd flag\n", TagName);
1219                     continue;
1220                 }
1221 #endif
1222
1223                 Flag_List[Nflags++] = flgs;
1224             }
1225             f_opt++;
1226             break;
1227
1228         case 'h':
1229             help(stdout);
1230             exit(0);
1231             break;
1232
1233         case 'i':
1234             format_error = 0;
1235
1236             switch (sscanf(optarg, "%i%c", &Iterations, &ch)) {
1237             case 1:
1238                 Time_Mode = 0;
1239                 break;
1240
1241             case 2:
1242                 if (ch == 's')
1243                     Time_Mode = 1;
1244                 else
1245                     format_error = 1;
1246                 break;
1247
1248             default:
1249                 format_error = 1;
1250             }
1251
1252             if (Iterations < 0)
1253                 format_error = 1;
1254
1255             if (format_error) {
1256                 fprintf(stderr, "iogen%s:  Illegal -i arg (%s):  Must be of the format:  number[s]\n", TagName, optarg);
1257                 fprintf(stderr, "        where 'number' is >= 0\n");
1258                 exit(1);
1259             }
1260
1261             i_opt++;
1262             break;
1263
1264         case 'L':
1265             fprintf(stderr, "iogen%s:  Unrecognized option -L on this platform\n", TagName);
1266             exit(2);
1267             break;
1268
1269         case 'm':
1270             if ((Offset_Mode = str_lookup(Omode_Map, optarg)) == NULL) {
1271                 fprintf(stderr, "iogen%s:  Illegal -m arg (%s)\n", TagName, optarg);
1272                 exit(1);
1273             }
1274
1275             m_opt++;
1276             break;
1277
1278         case 'N':
1279             sprintf( TagName, "(%.39s)", optarg );
1280             break;
1281
1282         case 'o':
1283             o_opt++;
1284             break;
1285
1286         case 'O':
1287
1288             nopenargs = string_to_tokens(optarg, openargs, 4, ":/");
1289 #ifndef NO_XFS
1290             if(!strcmp(openargs[0], "realtime")) {
1291                 /*
1292                  * -O realtime:extsize
1293                  */
1294                 Orealtime = 1;
1295                 if(nopenargs > 1)
1296                     sscanf(openargs[1],"%i", &Oextsize);
1297                 else
1298                     Oextsize=0;
1299             } else if( !strcmp(openargs[0], "allocate") ||
1300                        !strcmp(openargs[0], "allocsp")) {
1301                 /*
1302                  * -O allocate
1303                  */
1304                 Oreserve=0;
1305                 Oallocate=1;
1306             } else if(!strcmp(openargs[0], "reserve")) {
1307                 /*
1308                  * -O [no]reserve
1309                  */
1310                 Oallocate=0;
1311                 Oreserve=1;
1312             } else if(!strcmp(openargs[0], "noreserve")) {
1313                 /* Oreserve=1 by default; this clears that default */
1314                 Oreserve=0;
1315             } else if(!strcmp(openargs[0], "nowrite")) {
1316                 /* Owrite=1 by default; this clears that default */
1317                 Owrite=0;
1318             } else if(!strcmp(openargs[0], "direct")) {
1319                 /* this means "use direct i/o to preallocate file" */
1320                 Owrite=2;
1321             } else {
1322                 fprintf(stderr, "iogen%s: Error: -O %s error: unrecognized option\n",
1323                         TagName, openargs[0]);
1324                 exit(1);
1325             }
1326 #else
1327             Oflags = parse_open_flags(openargs[0], &errmsg);
1328             if(Oflags == -1) {
1329                 fprintf(stderr, "iogen%s: -O %s error: %s\n", TagName, optarg, errmsg);
1330                 exit(1);
1331             }
1332 #endif
1333
1334             O_opt++;
1335             break;
1336
1337         case 'p':
1338             Outpipe = optarg;
1339             p_opt++;
1340             break;
1341
1342         case 'r':
1343             if ((Rawmult = str_to_bytes(optarg)) == -1 ||
1344                           Rawmult < 11 || Rawmult % BSIZE) {
1345                 fprintf(stderr, "iogen%s:  Illegal -r arg (%s).  Must be > 0 and multipe of BSIZE (%d)\n",
1346                         TagName, optarg, BSIZE);
1347                 exit(1);
1348             }
1349
1350             r_opt++;
1351             break;
1352
1353         case 's':
1354             cp = strtok(optarg, ",");
1355             while (cp != NULL) {
1356                 if ((sc = str_lookup(Syscall_Map, cp)) == NULL) {
1357                     fprintf(stderr, "iogen%s:  Unrecognized syscall:  %s\n", TagName, cp);
1358                     exit(2);
1359                 }
1360
1361                 do {
1362                     /* >>> sc->m_flags & FLG_SDS */
1363                     if (sc->m_value != SSREAD && sc->m_value != SSWRITE)
1364                         Fileio++;
1365
1366                     Syscall_List[Nsyscalls++] = sc;
1367                 } while ( (sc = str_lookup(++sc, cp)) != NULL);
1368
1369                 cp = strtok(NULL, ",");
1370             }
1371             s_opt++;
1372             break;
1373
1374         case 't':
1375             if ((Mintrans = str_to_bytes(optarg)) == -1) {
1376                 fprintf(stderr, "iogen%s:  Illegal -t arg (%s):  Must have the form num[bkm]\n", TagName, optarg);
1377                 exit(1);
1378             }
1379             t_opt++;
1380             break;
1381
1382         case 'T':
1383             if ((Maxtrans = str_to_bytes(optarg)) == -1) {
1384                 fprintf(stderr, "iogen%s:  Illegal -T arg (%s):  Must have the form num[bkm]\n", TagName, optarg);
1385                 exit(1);
1386             }
1387             T_opt++;
1388             break;
1389
1390         case 'q':
1391             q_opt++;
1392             break;
1393
1394         case '?':
1395             usage(stderr);
1396             exit(1);
1397         }
1398     }
1399
1400     /*
1401      * Supply defaults
1402      */
1403
1404     if( ! L_opt ) {
1405             Minstrides = 1;
1406             Maxstrides = 255;
1407     }
1408
1409     if (! m_opt)
1410         Offset_Mode = str_lookup(Omode_Map, "sequential");
1411
1412     if (! i_opt)
1413         Iterations = 0;
1414
1415     if (! t_opt)
1416         Mintrans = 1;
1417
1418     if (! T_opt)
1419         Maxtrans = 256 * BSIZE;
1420
1421     if( ! O_opt) 
1422         Oflags = Ocbits = Ocblks = 0;
1423
1424     /*
1425      * Supply default async io completion strategy types.
1426      */
1427
1428     if (! a_opt) {
1429             for (mp = Aio_Strat_Map; mp->m_string != NULL; mp++) {
1430                     Aio_Strat_List[Naio_Strat_Types++] = mp;
1431             }
1432     }
1433
1434     /*
1435      * Supply default syscalls.  Default is read,write,reada,writea,listio.
1436      */
1437
1438     if (! s_opt) {
1439         Nsyscalls = 0;
1440         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "read");
1441         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "write");
1442         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pread");
1443         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pwrite");
1444         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "readv");
1445         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writev");
1446         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmread");
1447         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmwrite");
1448
1449         Fileio = 1;
1450     }
1451
1452     if (Fileio && (argc - optind < 1)) {
1453         fprintf(stderr, "iogen%s:  No files specified on the cmdline\n", TagName);
1454         exit(1);
1455     }
1456
1457     /*
1458      * Supply default file io flags - defaut is 'buffered,raw,sync,ldraw'.
1459      */
1460
1461     if (! f_opt && Fileio) {
1462             Nflags = 0;
1463             Flag_List[Nflags++] = str_lookup(Flag_Map, "buffered");
1464             Flag_List[Nflags++] = str_lookup(Flag_Map, "sync");
1465     }
1466
1467     if (Fileio) {
1468         if (optind >= argc) {
1469             fprintf(stderr, "iogen%s:  No files listed on the cmdline\n", TagName);
1470             exit(1);
1471         }
1472
1473         /*
1474          * Initialize File_List[] - only necessary if doing file io.  First 
1475          * space for the File_List array, then fill it in.
1476          */
1477         
1478         File_List = (struct file_info *)
1479             malloc((argc-optind) * sizeof(struct file_info));
1480         
1481         if (File_List == NULL) {
1482             fprintf(stderr, "iogen%s:  Could not malloc space for %d file_info structures\n", TagName, argc-optind);
1483             exit(2);
1484         }
1485
1486         memset(File_List, 0, (argc-optind) * sizeof(struct file_info));
1487
1488         Nfiles = 0;
1489         while (optind < argc) {
1490             len = -1;
1491
1492             /*
1493              * Pick off leading len: if it's there and create/extend/trunc
1494              * the file to the desired length.  Otherwise, just make sure
1495              * the file is accessable.
1496              */
1497
1498             if ((cp = strchr(argv[optind], ':')) != NULL) {
1499                 *cp = '\0';
1500                 if ((len = str_to_bytes(argv[optind])) == -1) {
1501                     fprintf(stderr,
1502                             "iogen%s:  illegal file length (%s) for file %s\n",
1503                             TagName, argv[optind], cp+1);
1504                     exit(2);
1505                 }
1506                 *cp = ':';
1507                 file = cp+1;
1508
1509                 if (strlen(file) > MAX_FNAME_LENGTH) {
1510                     fprintf(stderr, "iogen%s:  Max fname length is %d chars - ignoring file %s\n",
1511                             TagName, MAX_FNAME_LENGTH, file);
1512                     optind++;
1513                     continue;
1514                 }
1515
1516                 nb = create_file(file, len);
1517
1518                 if (nb < len) {
1519                     fprintf(stderr,
1520                             "iogen%s warning:  Couldn't create file %s of %d bytes\n",
1521                             TagName, file, len);
1522
1523                     if (nb <= 0) {
1524                         optind++;
1525                         continue;
1526                     }
1527                 }
1528             } else {
1529                 file = argv[optind];
1530                 if (access(file, R_OK | W_OK) == -1) {
1531                     fprintf(stderr, "iogen%s:  file %s cannot be accessed for reading and/or writing:  %s (%d)\n",
1532                             TagName, file, SYSERR, errno);
1533                     exit(2);
1534                 }
1535             }
1536
1537             /*
1538              * get per-file information
1539              */
1540
1541             fptr = &File_List[Nfiles];
1542
1543             if (file[0] == '/') {
1544                 strcpy(fptr->f_path, file);
1545             } else {
1546                 getcwd(fptr->f_path,
1547                        sizeof(fptr->f_path)-1);
1548                 strcat(fptr->f_path, "/");
1549                 strcat(fptr->f_path, file);
1550             }
1551
1552             if (get_file_info(fptr) == -1) {
1553                 fprintf(stderr, "iogen%s warning:  Error getting file info for %s\n", TagName, file);
1554             } else {
1555
1556                 /*
1557                  * If the file length is smaller than our min transfer size,
1558                  * ignore it.
1559                  */
1560
1561                 if (fptr->f_length < Mintrans) {
1562                     fprintf(stderr, "iogen%s warning:  Ignoring file %s\n",
1563                             TagName, fptr->f_path);
1564                     fprintf(stderr, "                length (%d) is < min transfer size (%d)\n",
1565                             fptr->f_length, Mintrans);
1566                     optind++;
1567                     continue;
1568                 }
1569
1570                 /*
1571                  * If the file length is smaller than our max transfer size,
1572                  * ignore it.
1573                  */
1574
1575                 if (fptr->f_length < Maxtrans) {
1576                     fprintf(stderr, "iogen%s warning:  Ignoring file %s\n",
1577                             TagName, fptr->f_path);
1578                     fprintf(stderr, "                length (%d) is < max transfer size (%d)\n",
1579                             fptr->f_length, Maxtrans);
1580                     optind++;
1581                     continue;
1582                 }
1583
1584                 if (fptr->f_length > 0) {
1585                     switch (Offset_Mode->m_value) {
1586                     case M_SEQUENTIAL:
1587                         fptr->f_lastoffset = 0;
1588                         fptr->f_lastlength = 0;
1589                         break;
1590                         
1591                     case M_REVERSE:
1592                         fptr->f_lastoffset = fptr->f_length;
1593                         fptr->f_lastlength = 0;
1594                         break;
1595                         
1596                     case M_RANDOM:
1597                         fptr->f_lastoffset = fptr->f_length / 2;
1598                         fptr->f_lastlength = 0;
1599                         break;
1600                     }
1601                     
1602                     Nfiles++;
1603                 }
1604             }
1605
1606             optind++;
1607         }
1608
1609         if (Nfiles == 0) {
1610             fprintf(stderr, "iogen%s:  Could not create, or gather info for any test files\n", TagName);
1611             exit(2);
1612         }
1613     }
1614
1615     return 0;
1616 }
1617
1618 int
1619 help(stream)
1620 FILE    *stream;
1621 {
1622     usage(stream);
1623     fprintf(stream, "\n");
1624 #ifndef linux
1625     fprintf(stream, "\t-a aio_type,...  Async io completion types to choose.  Supported types\n");
1626     fprintf(stream, "\t                 are:  poll, signal, suspend, and callback.\n");
1627     fprintf(stream, "\t                 Default is all of the above.\n");
1628 #else /* !linux */
1629     fprintf(stream, "\t-a               (Not used on Linux).\n");
1630 #endif /* !linux */
1631     fprintf(stream, "\t-f flag,...      Flags to use for file IO.  Supported flags are\n");
1632 #ifndef NO_XFS
1633     fprintf(stream, "\t                 buffered, direct, sync.\n");
1634     fprintf(stream, "\t                 Default is 'buffered,sync'.\n");
1635 #else
1636     fprintf(stream, "\t                 buffered, sync.\n");
1637     fprintf(stream, "\t                 Default is 'buffered,sync'.\n");
1638 #endif /* sgi */
1639     fprintf(stream, "\t-h               This help.\n");
1640     fprintf(stream, "\t-i iterations[s] # of requests to generate.  0 means causes iogen\n");
1641     fprintf(stream, "\t                 to run until it's killed.  If iterations is suffixed\n");
1642     fprintf(stream, "\t                 with 's', then iterations is the number of seconds\n");
1643     fprintf(stream, "\t                 that iogen should run for.  Default is '0'.\n");
1644     fprintf(stream, "\t-L min:max       listio nstrides / nrequests range\n");
1645     fprintf(stream, "\t-m offset-mode   The mode by which iogen chooses the offset for\n");
1646     fprintf(stream, "\t                 consectutive transfers within a given file.\n");
1647     fprintf(stream, "\t                 Allowed values are 'random', 'sequential',\n");
1648     fprintf(stream, "\t                 and 'reverse'.\n");
1649     fprintf(stream, "\t                 sequential is the default.\n");
1650     fprintf(stream, "\t-N tagname       Tag name, for Monster.\n");
1651     fprintf(stream, "\t-o               Form overlapping consecutive requests.\n");
1652     fprintf(stream, "\t-O               Open flags for creating files\n");
1653 #ifndef NO_XFS
1654     fprintf(stream, "\t                 realtime:extsize - put file on real-time volume\n");
1655     fprintf(stream, "\t                 allocate - allocate space with F_ALLOCSP\n");
1656     fprintf(stream, "\t                 reserve - reserve space with F_RESVSP (default)\n");
1657     fprintf(stream, "\t                 noreserve - do not reserve with F_RESVSP\n");
1658     fprintf(stream, "\t                 direct - use O_DIRECT I/O to write to the file\n");
1659 #else
1660     fprintf(stream, "\t                 {O_SYNC,etc}\n");
1661 #endif
1662     fprintf(stream, "\t-p               Output pipe.  Default is stdout.\n");
1663     fprintf(stream, "\t-q               Quiet mode.  Normally iogen spits out info\n");
1664     fprintf(stream, "\t                 about test files, options, etc. before starting.\n");
1665     fprintf(stream, "\t-s syscall,...   Syscalls to do.  Supported syscalls are\n");
1666 #ifdef linux
1667     fprintf(stream, "\t                 read, write, pread, pwrite, readv, writev,\n");
1668     fprintf(stream, "\t                 mmread, mmwrite, fsync2, fdatasync,\n");
1669     fprintf(stream, "\t                 Default is 'read,write,readv,writev,mmread,mmwrite'.\n");
1670 #endif
1671     fprintf(stream, "\t-t mintrans      Min transfer length\n");
1672     fprintf(stream, "\t-T maxtrans      Max transfer length\n");
1673     fprintf(stream, "\n");
1674     fprintf(stream, "\t[len:]file,...   Test files to do IO against (note ssread/sswrite\n");
1675     fprintf(stream, "\t                 don't need a test file).  The len: syntax\n");
1676     fprintf(stream, "\t                 informs iogen to first create/expand/truncate the\n");
1677     fprintf(stream, "\t                 to the desired length.\n");
1678     fprintf(stream, "\n");
1679     fprintf(stream, "\tNote:  The ssd flag causes sds transfers to also be done.\n");
1680     fprintf(stream, "\t       To totally eliminate sds transfers, you must eleminate sds\n");
1681     fprintf(stream, "\t       from the flags (-f) and ssread,ssrite from the syscalls (-s)\n");
1682     fprintf(stream, "\tThe mintrans, maxtrans, and len: parameters are numbers of the\n");
1683     fprintf(stream, "\tform [0-9]+[bkm].  The optional trailing b, k, or m multiplies\n");
1684     fprintf(stream, "\tthe number by blocks, kilobytes, or megabytes.  If no trailing\n");
1685     fprintf(stream, "\tmultiplier is present, the number is interpreted as bytes\n");
1686
1687     return 0;
1688 }
1689
1690 /*
1691  * Obvious - usage clause
1692  */
1693
1694 int
1695 usage(stream)
1696 FILE    *stream;
1697 {
1698     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);
1699     return 0;
1700 }