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 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 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 */ 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 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 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 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 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 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 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 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 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 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