xfstests: allow override of XFS_IOC_DIOINFO
[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(FILE *stream, int seed);
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(struct strmap *map, int val), *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             char *dio_env;
785 #ifdef XFS_IOC_DIOINFO
786             if(xfsctl(rec->f_path, fd, XFS_IOC_DIOINFO, &finfo) != -1) {
787 #else
788 #ifdef F_DIOINFO
789             if(fcntl(fd, F_DIOINFO, &finfo) != -1) {
790 #else
791 bozo!
792 #endif
793 #endif
794                 dio_env = getenv("XFS_DIO_MIN");
795                 if (dio_env)
796                     finfo.d_mem = finfo.d_miniosz = atoi(dio_env);
797
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     } else {
809
810         rec->f_riou = BSIZE;
811         rec->f_length = BSIZE;
812     }
813
814     return 0;
815 }
816
817 /*
818  * Create file path as nbytes long.  If path exists, the file will either be
819  * extended or truncated to be nbytes long.  Returns final size of file,
820  * or -1 if there was a failure.
821  */
822
823 int
824 create_file(path, nbytes)
825 char    *path;
826 int     nbytes;
827 {
828     int         fd, rval;
829     char        c;
830     struct stat sbuf;
831     int         nb;
832     struct flock64 f;
833     struct fsxattr xattr;
834     struct dioattr finfo;
835     char        *b, *buf;
836
837     errno = 0;
838     rval = stat(path, &sbuf);
839
840     if (rval == -1) {
841         if (errno == ENOENT) {
842             sbuf.st_size = 0;
843         } else {
844             fprintf(stderr, "iogen%s:  Could not stat file %s:  %s (%d)\n",
845                     TagName, path, SYSERR, errno);
846             return -1;
847         }
848     } else {
849         if (! S_ISREG(sbuf.st_mode)) {
850             fprintf(stderr,
851                     "iogen%s:  file %s exists, but is not a regular file - cannot modify length\n",
852                     TagName, path);
853             return -1;
854         }
855     }
856
857     if (sbuf.st_size == nbytes)
858         return nbytes;
859
860     Oflags |= O_CREAT | O_WRONLY;
861
862     if ((fd = open(path, Oflags, 0666)) == -1) {
863         fprintf(stderr, "iogen%s:  Could not create/open file %s: %s (%d)\n",
864                 TagName, path, SYSERR, errno);
865         return -1;
866     }
867
868     /*
869      * Truncate file if it is longer than nbytes, otherwise attempt to
870      * pre-allocate file blocks.
871      */
872
873     if (sbuf.st_size > nbytes) {
874         if (ftruncate(fd, nbytes) == -1) {
875             fprintf(stderr,
876                     "iogen%s:  Could not ftruncate() %s to %d bytes:  %s (%d)\n",
877                     TagName, path, nbytes, SYSERR, errno);
878             close(fd);
879             return -1;
880         }
881     } else {
882
883         /*
884          *  The file must be designated as Real-Time before any data
885          *  is allocated to it.
886          *
887          */
888         if(Orealtime != 0) {
889             bzero(&xattr, sizeof(xattr));
890             xattr.fsx_xflags = XFS_XFLAG_REALTIME;
891             /*fprintf(stderr, "set: fsx_xflags = 0x%x\n", xattr.fsx_xflags);*/
892 #ifdef XFS_IOC_FSSETXATTR
893             if( xfsctl(path, fd, XFS_IOC_FSSETXATTR, &xattr) == -1 ) {
894 #else
895 #ifdef F_FSSETXATTR
896                     if (fcntl(fd, F_FSSETXATTR, &xattr) < 0) {
897 #else
898 bozo!
899 #endif
900 #endif
901                 fprintf(stderr, "iogen%s: Error %s (%d) setting XFS XATTR->Realtime on file %s\n",
902                         TagName, SYSERR, errno, path);
903                 close(fd);
904                 return -1;
905             }
906
907 #ifdef DEBUG
908 #ifdef XFS_IOC_FSGETXATTR
909             if( xfsctl(path, fd, XFS_IOC_FSGETXATTR, &xattr) == -1 ) {
910 #else
911 #ifdef F_FSGETXATTR
912             if (fcntl(fd, F_FSGETXATTR, &xattr) < 0) {
913 #else
914 bozo!
915 #endif
916 #endif
917                 fprintf(stderr, "iogen%s: Error getting realtime flag %s (%d)\n",
918                         TagName, SYSERR, errno);
919                 close(fd);
920                 return -1;
921             } else {
922                 fprintf(stderr, "get: fsx_xflags = 0x%x\n", 
923                         xattr.fsx_xflags);
924             }
925         }
926
927         /*
928          * Reserve space
929          *
930          * Failure is ignored since XFS_IOC_RESVSP only works on XFS and the
931          * filesystem could be on some otehr filesystem.
932          */
933         if( Oreserve ) {
934             f.l_whence = SEEK_SET;
935             f.l_start = 0;
936             f.l_len = nbytes;
937             
938             /*fprintf(stderr,
939                     "create_file: xfsctl(%d, RESVSP, { %d, %lld, %lld })\n",
940                    fd, f.l_whence, (long long)f.l_start, (long long)f.l_len);*/
941
942             /* non-zeroing reservation */
943 #ifdef XFS_IOC_RESVSP
944             if( xfsctl( path, fd, XFS_IOC_RESVSP, &f ) == -1) {
945                 fprintf(stderr,
946                         "iogen%s:  Could not xfsctl(XFS_IOC_RESVSP) %d bytes in file %s: %s (%d)\n",
947                         TagName, nbytes, path, SYSERR, errno);
948                 close(fd);
949                 return -1;
950             }
951 #else
952 #ifdef F_RESVSP
953             if( fcntl( fd, F_RESVSP, &f ) == -1) {
954                 fprintf(stderr,
955                         "iogen%s:  Could not fcntl(F_RESVSP) %d bytes in file %s: %s (%d)\n",
956                         TagName, nbytes, path, SYSERR, errno);
957                 close(fd);
958                 return -1;
959             }
960 #else
961 bozo!
962 #endif
963 #endif
964         }
965
966         if( Oallocate ) {
967             /* XFS_IOC_ALLOCSP allocates from the file start to l_start */
968             f.l_whence = SEEK_SET;
969             f.l_start = nbytes;
970             f.l_len = 0;
971             /*fprintf(stderr,
972                     "create_file: xfsctl(%d, XFS_IOC_ALLOCSP, { %d, %lld, %lld })\n",
973                     fd, f.l_whence, (long long)f.l_start,
974                     (long long)f.l_len);*/
975
976             /* zeroing reservation */
977 #ifdef XFS_IOC_ALLOCSP
978             if( xfsctl( path, fd, XFS_IOC_ALLOCSP, &f ) == -1) {
979                 fprintf(stderr,
980                         "iogen%s:  Could not xfsctl(XFS_IOC_ALLOCSP) %d bytes in file %s: %s (%d)\n",
981                         TagName, nbytes, path, SYSERR, errno);
982                 close(fd);
983                 return -1;
984             }
985 #else
986 #ifdef F_ALLOCSP
987             if ( fcntl(fd, F_ALLOCSP, &f) < 0) {
988                 fprintf(stderr,
989                         "iogen%s:  Could not fcntl(F_ALLOCSP) %d bytes in file %s: %s (%d)\n",
990                         TagName, nbytes, path, SYSERR, errno);
991                 close(fd);
992                 return -1;
993             }
994 #else
995 bozo!
996 #endif
997 #endif
998         }
999 #endif
1000
1001         /*
1002          * Write a byte at the end of file so that stat() sets the right
1003          * file size.
1004          */
1005
1006         if(Owrite == 2) {
1007             close(fd);
1008             if( (fd = open(path, O_CREAT|O_RDWR|O_DIRECT, 0)) != -1 ) {
1009                 char *dio_env;
1010 #ifdef XFS_IOC_DIOINFO
1011                 if(xfsctl(path, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
1012 #else
1013 #ifdef F_DIOINFO
1014                 if (fcntl(fd, F_DIOINFO, &finfo) < 0) {
1015 #else
1016 bozo!
1017 #endif
1018 #endif
1019                     fprintf(stderr,
1020                             "iogen%s: Error %s (%d) getting direct I/O info for file %s\n",
1021                             TagName, SYSERR, errno, path);
1022                     return -1;
1023                 } else {
1024                     /*fprintf(stderr, "%s: miniosz=%d\n", 
1025                             path, finfo.d_miniosz);*/
1026                 }
1027
1028                 dio_env = getenv("XFS_DIO_MIN");
1029                 if (dio_env)
1030                         finfo.d_mem = finfo.d_miniosz = atoi(dio_env);
1031             } else {
1032                 fprintf(stderr, "iogen%s: Error %s (%d) opening file %s with flags O_CREAT|O_RDWR|O_DIRECT\n",
1033                         TagName, SYSERR, errno, path);
1034                 return -1;
1035             }
1036
1037             /*
1038              * nb is nbytes adjusted down by an even d_miniosz block
1039              *
1040              * Note: the first adjustment can cause iogen to print a warning 
1041              *  about not being able to create a file of <nbytes> length, 
1042              *  since the file will be shorter.
1043              */
1044             nb = nbytes-finfo.d_miniosz;
1045             nb = nb-nb%finfo.d_miniosz;
1046
1047             /*fprintf(stderr,
1048                     "create_file_ow2: lseek(%d, %d {%d %d}, SEEK_SET)\n",
1049                     fd, nb, nbytes, finfo.d_miniosz);*/
1050
1051             if (lseek(fd, nb, SEEK_SET) == -1) {
1052                 fprintf(stderr,
1053                         "iogen%s:  Could not lseek() to EOF of file %s: %s (%d)\n\tactual offset %d file size goal %d miniosz %lld\n",
1054                         TagName, path, SYSERR, errno,
1055                         nb, nbytes, (long long)finfo.d_miniosz);
1056                 close(fd);
1057                 return -1;
1058             }
1059
1060             b = buf = (char *)malloc(finfo.d_miniosz+finfo.d_mem);
1061
1062             if( ((long)buf % finfo.d_mem != 0) ) {
1063                 buf += finfo.d_mem - ((long)buf % finfo.d_mem);
1064             }
1065             
1066             memset(buf, 0, finfo.d_miniosz);
1067
1068             if ( (rval=write(fd, buf, finfo.d_miniosz)) != finfo.d_miniosz) {
1069                 fprintf(stderr,
1070                         "iogen%s:  Could not write %d byte length file %s: %s (%d)\n",
1071                         TagName, nb, path, SYSERR, errno);
1072                 fprintf(stderr,
1073                         "\twrite(%d, 0x%lx, %d) = %d\n",
1074                         fd, (long)buf, finfo.d_miniosz, rval);
1075                 fprintf(stderr,
1076                         "\toffset %d file size goal %d, miniosz=%d\n",
1077                         nb, nbytes, finfo.d_miniosz);
1078                 close(fd);
1079                 return -1;
1080             }
1081             free(b);
1082         } else
1083             if(Owrite) {
1084             /*fprintf(stderr,
1085                     "create_file_Owrite: lseek(%d, %d {%d}, SEEK_SET)\n",
1086                     fd, nbytes-1, nbytes);*/
1087
1088             if (lseek(fd, nbytes-1, SEEK_SET) == -1) {
1089                 fprintf(stderr,
1090                         "iogen%s:  Could not lseek() to EOF in file %s:  %s (%d)\n\toffset goal %d\n",
1091                         TagName, path, SYSERR, errno,
1092                         nbytes-1);
1093                 close(fd);
1094                 return -1;
1095             }
1096
1097             if ( (rval=write(fd, &c, 1)) != 1) {
1098                 fprintf(stderr,
1099                         "iogen%s:  Could not create a %d byte length file %s: %s (%d)\n",
1100                         TagName, nbytes, path, SYSERR, errno);
1101                 fprintf(stderr,
1102                         "\twrite(%d, 0x%lx, %d) = %d\n",
1103                         fd, (long)&c, 1, rval);
1104                 fprintf(stderr,
1105                         "\toffset %d file size goal %d\n",
1106                         nbytes-1, nbytes);
1107                 close(fd);
1108                 return -1;
1109             }
1110         }
1111     }
1112
1113     fstat(fd, &sbuf);
1114     close(fd);
1115
1116     return sbuf.st_size;
1117 }
1118
1119 /*
1120  * Function to convert a string to its corresponding value in a strmap array.
1121  * If the string is not found in the array, the value corresponding to the
1122  * NULL string (the last element in the array) is returned.
1123  */
1124
1125 int
1126 str_to_value(map, str)
1127 struct strmap   *map;
1128 char            *str;
1129 {
1130     struct strmap   *mp;
1131
1132     for (mp = map; mp->m_string != NULL; mp++)
1133         if (strcmp(mp->m_string, str) == 0)
1134             break;
1135
1136     return mp->m_value;
1137 }
1138     
1139 /*
1140  * Function to convert a string to its corresponding entry in a strmap array.
1141  * If the string is not found in the array, a NULL is returned.
1142  */
1143
1144 struct strmap *
1145 str_lookup(map, str)
1146 struct strmap   *map;
1147 char            *str;
1148 {
1149     struct strmap   *mp;
1150
1151     for (mp = map; mp->m_string != NULL; mp++)
1152         if (strcmp(mp->m_string, str) == 0)
1153             break;
1154
1155     return((mp->m_string == NULL) ? NULL : mp);
1156 }
1157     
1158
1159 /*
1160  * Function to convert a value to its corresponding string in a strmap array.
1161  * If the value is not found in the array, NULL is returned.
1162  */
1163
1164 char *
1165 value_to_string(map, val)
1166 struct strmap   *map;
1167 int             val;
1168 {
1169     struct strmap  *mp;
1170
1171     for (mp = map; mp->m_string != NULL; mp++)
1172         if (mp->m_value == val)
1173             break;
1174
1175     return mp->m_string;
1176 }
1177
1178 /*
1179  * Interpret cmdline options/arguments.  Exit with 1 if something on the
1180  * cmdline isn't kosher.
1181  */
1182
1183 int
1184 parse_cmdline(argc, argv, opts)
1185 int     argc;
1186 char    **argv;
1187 char    *opts;
1188 {
1189     int                 o, len, nb, format_error;
1190     struct strmap       *flgs, *sc;
1191     char                *file, *cp, ch;
1192     struct strmap       *mp;
1193     struct file_info    *fptr;
1194     int                 nopenargs;
1195     char                *openargs[5];   /* Flags, cbits, cblks */
1196     while ((o = getopt(argc, argv, opts)) != EOF) {
1197         switch ((char)o) {
1198
1199         case 'a':
1200             fprintf(stderr, "iogen%s:  Unrecognized option -a on this platform\n", TagName);
1201             exit(2);
1202             break;
1203
1204         case 'f':
1205             cp = strtok(optarg, ",");
1206             while (cp != NULL) {
1207                 if( (flgs = str_lookup(Flag_Map, cp)) == NULL ) {
1208                     fprintf(stderr, "iogen%s:  Unrecognized flags:  %s\n", TagName, cp);
1209                     exit(2);
1210                 }
1211
1212                 cp = strtok(NULL, ",");
1213
1214 #ifdef O_SSD
1215                 if (flgs->m_value & O_SSD && ! Sds_Avail) {
1216                     fprintf(stderr, "iogen%s:  Warning - no sds available, ignoring ssd flag\n", TagName);
1217                     continue;
1218                 }
1219 #endif
1220
1221                 Flag_List[Nflags++] = flgs;
1222             }
1223             f_opt++;
1224             break;
1225
1226         case 'h':
1227             help(stdout);
1228             exit(0);
1229             break;
1230
1231         case 'i':
1232             format_error = 0;
1233
1234             switch (sscanf(optarg, "%i%c", &Iterations, &ch)) {
1235             case 1:
1236                 Time_Mode = 0;
1237                 break;
1238
1239             case 2:
1240                 if (ch == 's')
1241                     Time_Mode = 1;
1242                 else
1243                     format_error = 1;
1244                 break;
1245
1246             default:
1247                 format_error = 1;
1248             }
1249
1250             if (Iterations < 0)
1251                 format_error = 1;
1252
1253             if (format_error) {
1254                 fprintf(stderr, "iogen%s:  Illegal -i arg (%s):  Must be of the format:  number[s]\n", TagName, optarg);
1255                 fprintf(stderr, "        where 'number' is >= 0\n");
1256                 exit(1);
1257             }
1258
1259             i_opt++;
1260             break;
1261
1262         case 'L':
1263             fprintf(stderr, "iogen%s:  Unrecognized option -L on this platform\n", TagName);
1264             exit(2);
1265             break;
1266
1267         case 'm':
1268             if ((Offset_Mode = str_lookup(Omode_Map, optarg)) == NULL) {
1269                 fprintf(stderr, "iogen%s:  Illegal -m arg (%s)\n", TagName, optarg);
1270                 exit(1);
1271             }
1272
1273             m_opt++;
1274             break;
1275
1276         case 'N':
1277             sprintf( TagName, "(%.39s)", optarg );
1278             break;
1279
1280         case 'o':
1281             o_opt++;
1282             break;
1283
1284         case 'O':
1285
1286             nopenargs = string_to_tokens(optarg, openargs, 4, ":/");
1287             if(!strcmp(openargs[0], "realtime")) {
1288                 /*
1289                  * -O realtime:extsize
1290                  */
1291                 Orealtime = 1;
1292                 if(nopenargs > 1)
1293                     sscanf(openargs[1],"%i", &Oextsize);
1294                 else
1295                     Oextsize=0;
1296             } else if( !strcmp(openargs[0], "allocate") ||
1297                        !strcmp(openargs[0], "allocsp")) {
1298                 /*
1299                  * -O allocate
1300                  */
1301                 Oreserve=0;
1302                 Oallocate=1;
1303             } else if(!strcmp(openargs[0], "reserve")) {
1304                 /*
1305                  * -O [no]reserve
1306                  */
1307                 Oallocate=0;
1308                 Oreserve=1;
1309             } else if(!strcmp(openargs[0], "noreserve")) {
1310                 /* Oreserve=1 by default; this clears that default */
1311                 Oreserve=0;
1312             } else if(!strcmp(openargs[0], "nowrite")) {
1313                 /* Owrite=1 by default; this clears that default */
1314                 Owrite=0;
1315             } else if(!strcmp(openargs[0], "direct")) {
1316                 /* this means "use direct i/o to preallocate file" */
1317                 Owrite=2;
1318             } else {
1319                 fprintf(stderr, "iogen%s: Error: -O %s error: unrecognized option\n",
1320                         TagName, openargs[0]);
1321                 exit(1);
1322             }
1323             O_opt++;
1324             break;
1325
1326         case 'p':
1327             Outpipe = optarg;
1328             p_opt++;
1329             break;
1330
1331         case 'r':
1332             if ((Rawmult = str_to_bytes(optarg)) == -1 ||
1333                           Rawmult < 11 || Rawmult % BSIZE) {
1334                 fprintf(stderr, "iogen%s:  Illegal -r arg (%s).  Must be > 0 and multipe of BSIZE (%d)\n",
1335                         TagName, optarg, BSIZE);
1336                 exit(1);
1337             }
1338
1339             r_opt++;
1340             break;
1341
1342         case 's':
1343             cp = strtok(optarg, ",");
1344             while (cp != NULL) {
1345                 if ((sc = str_lookup(Syscall_Map, cp)) == NULL) {
1346                     fprintf(stderr, "iogen%s:  Unrecognized syscall:  %s\n", TagName, cp);
1347                     exit(2);
1348                 }
1349
1350                 do {
1351                     /* >>> sc->m_flags & FLG_SDS */
1352                     if (sc->m_value != SSREAD && sc->m_value != SSWRITE)
1353                         Fileio++;
1354
1355                     Syscall_List[Nsyscalls++] = sc;
1356                 } while ( (sc = str_lookup(++sc, cp)) != NULL);
1357
1358                 cp = strtok(NULL, ",");
1359             }
1360             s_opt++;
1361             break;
1362
1363         case 't':
1364             if ((Mintrans = str_to_bytes(optarg)) == -1) {
1365                 fprintf(stderr, "iogen%s:  Illegal -t arg (%s):  Must have the form num[bkm]\n", TagName, optarg);
1366                 exit(1);
1367             }
1368             t_opt++;
1369             break;
1370
1371         case 'T':
1372             if ((Maxtrans = str_to_bytes(optarg)) == -1) {
1373                 fprintf(stderr, "iogen%s:  Illegal -T arg (%s):  Must have the form num[bkm]\n", TagName, optarg);
1374                 exit(1);
1375             }
1376             T_opt++;
1377             break;
1378
1379         case 'q':
1380             q_opt++;
1381             break;
1382
1383         case '?':
1384             usage(stderr);
1385             exit(1);
1386         }
1387     }
1388
1389     /*
1390      * Supply defaults
1391      */
1392
1393     if( ! L_opt ) {
1394             Minstrides = 1;
1395             Maxstrides = 255;
1396     }
1397
1398     if (! m_opt)
1399         Offset_Mode = str_lookup(Omode_Map, "sequential");
1400
1401     if (! i_opt)
1402         Iterations = 0;
1403
1404     if (! t_opt)
1405         Mintrans = 1;
1406
1407     if (! T_opt)
1408         Maxtrans = 256 * BSIZE;
1409
1410     if( ! O_opt) 
1411         Oflags = Ocbits = Ocblks = 0;
1412
1413     /*
1414      * Supply default async io completion strategy types.
1415      */
1416
1417     if (! a_opt) {
1418             for (mp = Aio_Strat_Map; mp->m_string != NULL; mp++) {
1419                     Aio_Strat_List[Naio_Strat_Types++] = mp;
1420             }
1421     }
1422
1423     /*
1424      * Supply default syscalls.  Default is read,write,reada,writea,listio.
1425      */
1426
1427     if (! s_opt) {
1428         Nsyscalls = 0;
1429         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "read");
1430         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "write");
1431         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pread");
1432         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pwrite");
1433         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "readv");
1434         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writev");
1435         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmread");
1436         Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmwrite");
1437
1438         Fileio = 1;
1439     }
1440
1441     if (Fileio && (argc - optind < 1)) {
1442         fprintf(stderr, "iogen%s:  No files specified on the cmdline\n", TagName);
1443         exit(1);
1444     }
1445
1446     /*
1447      * Supply default file io flags - defaut is 'buffered,raw,sync,ldraw'.
1448      */
1449
1450     if (! f_opt && Fileio) {
1451             Nflags = 0;
1452             Flag_List[Nflags++] = str_lookup(Flag_Map, "buffered");
1453             Flag_List[Nflags++] = str_lookup(Flag_Map, "sync");
1454     }
1455
1456     if (Fileio) {
1457         if (optind >= argc) {
1458             fprintf(stderr, "iogen%s:  No files listed on the cmdline\n", TagName);
1459             exit(1);
1460         }
1461
1462         /*
1463          * Initialize File_List[] - only necessary if doing file io.  First 
1464          * space for the File_List array, then fill it in.
1465          */
1466         
1467         File_List = (struct file_info *)
1468             malloc((argc-optind) * sizeof(struct file_info));
1469         
1470         if (File_List == NULL) {
1471             fprintf(stderr, "iogen%s:  Could not malloc space for %d file_info structures\n", TagName, argc-optind);
1472             exit(2);
1473         }
1474
1475         memset(File_List, 0, (argc-optind) * sizeof(struct file_info));
1476
1477         Nfiles = 0;
1478         while (optind < argc) {
1479             len = -1;
1480
1481             /*
1482              * Pick off leading len: if it's there and create/extend/trunc
1483              * the file to the desired length.  Otherwise, just make sure
1484              * the file is accessable.
1485              */
1486
1487             if ((cp = strchr(argv[optind], ':')) != NULL) {
1488                 *cp = '\0';
1489                 if ((len = str_to_bytes(argv[optind])) == -1) {
1490                     fprintf(stderr,
1491                             "iogen%s:  illegal file length (%s) for file %s\n",
1492                             TagName, argv[optind], cp+1);
1493                     exit(2);
1494                 }
1495                 *cp = ':';
1496                 file = cp+1;
1497
1498                 if (strlen(file) > MAX_FNAME_LENGTH) {
1499                     fprintf(stderr, "iogen%s:  Max fname length is %d chars - ignoring file %s\n",
1500                             TagName, MAX_FNAME_LENGTH, file);
1501                     optind++;
1502                     continue;
1503                 }
1504
1505                 nb = create_file(file, len);
1506
1507                 if (nb < len) {
1508                     fprintf(stderr,
1509                             "iogen%s warning:  Couldn't create file %s of %d bytes\n",
1510                             TagName, file, len);
1511
1512                     if (nb <= 0) {
1513                         optind++;
1514                         continue;
1515                     }
1516                 }
1517             } else {
1518                 file = argv[optind];
1519                 if (access(file, R_OK | W_OK) == -1) {
1520                     fprintf(stderr, "iogen%s:  file %s cannot be accessed for reading and/or writing:  %s (%d)\n",
1521                             TagName, file, SYSERR, errno);
1522                     exit(2);
1523                 }
1524             }
1525
1526             /*
1527              * get per-file information
1528              */
1529
1530             fptr = &File_List[Nfiles];
1531
1532             if (file[0] == '/') {
1533                 strcpy(fptr->f_path, file);
1534             } else {
1535                 getcwd(fptr->f_path,
1536                        sizeof(fptr->f_path)-1);
1537                 strcat(fptr->f_path, "/");
1538                 strcat(fptr->f_path, file);
1539             }
1540
1541             if (get_file_info(fptr) == -1) {
1542                 fprintf(stderr, "iogen%s warning:  Error getting file info for %s\n", TagName, file);
1543             } else {
1544
1545                 /*
1546                  * If the file length is smaller than our min transfer size,
1547                  * ignore it.
1548                  */
1549
1550                 if (fptr->f_length < Mintrans) {
1551                     fprintf(stderr, "iogen%s warning:  Ignoring file %s\n",
1552                             TagName, fptr->f_path);
1553                     fprintf(stderr, "                length (%d) is < min transfer size (%d)\n",
1554                             fptr->f_length, Mintrans);
1555                     optind++;
1556                     continue;
1557                 }
1558
1559                 /*
1560                  * If the file length is smaller than our max transfer size,
1561                  * ignore it.
1562                  */
1563
1564                 if (fptr->f_length < Maxtrans) {
1565                     fprintf(stderr, "iogen%s warning:  Ignoring file %s\n",
1566                             TagName, fptr->f_path);
1567                     fprintf(stderr, "                length (%d) is < max transfer size (%d)\n",
1568                             fptr->f_length, Maxtrans);
1569                     optind++;
1570                     continue;
1571                 }
1572
1573                 if (fptr->f_length > 0) {
1574                     switch (Offset_Mode->m_value) {
1575                     case M_SEQUENTIAL:
1576                         fptr->f_lastoffset = 0;
1577                         fptr->f_lastlength = 0;
1578                         break;
1579                         
1580                     case M_REVERSE:
1581                         fptr->f_lastoffset = fptr->f_length;
1582                         fptr->f_lastlength = 0;
1583                         break;
1584                         
1585                     case M_RANDOM:
1586                         fptr->f_lastoffset = fptr->f_length / 2;
1587                         fptr->f_lastlength = 0;
1588                         break;
1589                     }
1590                     
1591                     Nfiles++;
1592                 }
1593             }
1594
1595             optind++;
1596         }
1597
1598         if (Nfiles == 0) {
1599             fprintf(stderr, "iogen%s:  Could not create, or gather info for any test files\n", TagName);
1600             exit(2);
1601         }
1602     }
1603
1604     return 0;
1605 }
1606
1607 int
1608 help(stream)
1609 FILE    *stream;
1610 {
1611     usage(stream);
1612     fprintf(stream, "\n");
1613 #ifndef linux
1614     fprintf(stream, "\t-a aio_type,...  Async io completion types to choose.  Supported types\n");
1615     fprintf(stream, "\t                 are:  poll, signal, suspend, and callback.\n");
1616     fprintf(stream, "\t                 Default is all of the above.\n");
1617 #else /* !linux */
1618     fprintf(stream, "\t-a               (Not used on Linux).\n");
1619 #endif /* !linux */
1620     fprintf(stream, "\t-f flag,...      Flags to use for file IO.  Supported flags are\n");
1621     fprintf(stream, "\t                 buffered, direct, sync.\n");
1622     fprintf(stream, "\t                 Default is 'buffered,sync'.\n");
1623     fprintf(stream, "\t-h               This help.\n");
1624     fprintf(stream, "\t-i iterations[s] # of requests to generate.  0 means causes iogen\n");
1625     fprintf(stream, "\t                 to run until it's killed.  If iterations is suffixed\n");
1626     fprintf(stream, "\t                 with 's', then iterations is the number of seconds\n");
1627     fprintf(stream, "\t                 that iogen should run for.  Default is '0'.\n");
1628     fprintf(stream, "\t-L min:max       listio nstrides / nrequests range\n");
1629     fprintf(stream, "\t-m offset-mode   The mode by which iogen chooses the offset for\n");
1630     fprintf(stream, "\t                 consectutive transfers within a given file.\n");
1631     fprintf(stream, "\t                 Allowed values are 'random', 'sequential',\n");
1632     fprintf(stream, "\t                 and 'reverse'.\n");
1633     fprintf(stream, "\t                 sequential is the default.\n");
1634     fprintf(stream, "\t-N tagname       Tag name, for Monster.\n");
1635     fprintf(stream, "\t-o               Form overlapping consecutive requests.\n");
1636     fprintf(stream, "\t-O               Open flags for creating files\n");
1637     fprintf(stream, "\t                 realtime:extsize - put file on real-time volume\n");
1638     fprintf(stream, "\t                 allocate - allocate space with F_ALLOCSP\n");
1639     fprintf(stream, "\t                 reserve - reserve space with F_RESVSP (default)\n");
1640     fprintf(stream, "\t                 noreserve - do not reserve with F_RESVSP\n");
1641     fprintf(stream, "\t                 direct - use O_DIRECT I/O to write to the file\n");
1642     fprintf(stream, "\t-p               Output pipe.  Default is stdout.\n");
1643     fprintf(stream, "\t-q               Quiet mode.  Normally iogen spits out info\n");
1644     fprintf(stream, "\t                 about test files, options, etc. before starting.\n");
1645     fprintf(stream, "\t-s syscall,...   Syscalls to do.  Supported syscalls are\n");
1646 #ifdef linux
1647     fprintf(stream, "\t                 read, write, pread, pwrite, readv, writev,\n");
1648     fprintf(stream, "\t                 mmread, mmwrite, fsync2, fdatasync,\n");
1649     fprintf(stream, "\t                 Default is 'read,write,readv,writev,mmread,mmwrite'.\n");
1650 #endif
1651     fprintf(stream, "\t-t mintrans      Min transfer length\n");
1652     fprintf(stream, "\t-T maxtrans      Max transfer length\n");
1653     fprintf(stream, "\n");
1654     fprintf(stream, "\t[len:]file,...   Test files to do IO against (note ssread/sswrite\n");
1655     fprintf(stream, "\t                 don't need a test file).  The len: syntax\n");
1656     fprintf(stream, "\t                 informs iogen to first create/expand/truncate the\n");
1657     fprintf(stream, "\t                 to the desired length.\n");
1658     fprintf(stream, "\n");
1659     fprintf(stream, "\tNote:  The ssd flag causes sds transfers to also be done.\n");
1660     fprintf(stream, "\t       To totally eliminate sds transfers, you must eleminate sds\n");
1661     fprintf(stream, "\t       from the flags (-f) and ssread,ssrite from the syscalls (-s)\n");
1662     fprintf(stream, "\tThe mintrans, maxtrans, and len: parameters are numbers of the\n");
1663     fprintf(stream, "\tform [0-9]+[bkm].  The optional trailing b, k, or m multiplies\n");
1664     fprintf(stream, "\tthe number by blocks, kilobytes, or megabytes.  If no trailing\n");
1665     fprintf(stream, "\tmultiplier is present, the number is interpreted as bytes\n");
1666
1667     return 0;
1668 }
1669
1670 /*
1671  * Obvious - usage clause
1672  */
1673
1674 int
1675 usage(stream)
1676 FILE    *stream;
1677 {
1678     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);
1679     return 0;
1680 }