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