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