1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000 Silicon Graphics, Inc.
7 * iogen - a tool for generating file/sds io for a doio process
12 #ifdef HAVE_SYS_SYSSGI_H
13 #include <sys/syssgi.h>
16 #ifdef HAVE_SYS_UUID_H
20 #ifdef HAVE_SYS_FS_XFS_FSOPS_H
21 #include <sys/fs/xfs_fsops.h>
24 #ifdef HAVE_SYS_FS_XFS_ITABLE_H
25 #include <sys/fs/xfs_itable.h>
30 #include "str_to_bytes.h"
31 #include "string_to_tokens.h"
32 #include "open_flags.h"
33 #include "random_range.h"
39 #define RAW_IO(_flags_) ((_flags_) & (O_RAW | O_SSD))
41 #define SYSERR strerror(errno)
44 * Structure for retaining test file information
48 char f_path[MAX_FNAME_LENGTH+1]; /* file name (full path) */
49 int f_length; /* length in bytes */
50 int f_iou; /* file iounit */
51 int f_riou; /* file raw iounit (for O_RAW/O_SSD) */
52 int f_dalign; /* direct I/O alignment */
53 int f_nextoff; /* offset of end of last io operation */
54 int f_type; /* file type S_IFREG, etc... */
55 int f_lastoffset; /* offset of last io operation */
56 int f_lastlength; /* length of last io operation */
60 * Simple structure for associating strings with values - useful for converting
61 * cmdline args to internal values, as well as printing internal values in
62 * a human readable form.
72 * Declare cmdline option flags/variables initialized in parse_cmdline()
75 #define OPTS "a:dhf:i:L:m:op:qr:s:t:T:O:N:"
77 int a_opt = 0; /* async io comp. types supplied */
78 int o_opt = 0; /* form overlapping requests */
79 int f_opt = 0; /* test flags */
80 int i_opt = 0; /* iterations - 0 implies infinite */
81 int L_opt = 0; /* listio min-max nstrides & nents */
82 int m_opt = 0; /* offset mode */
83 int O_opt = 0; /* file creation Open flags */
84 int p_opt = 0; /* output pipe - default is stdout */
85 int r_opt = 0; /* specify raw io multiple instead of */
86 /* getting it from the mounted on device. */
87 /* Only applies to regular files. */
88 int s_opt = 0; /* syscalls */
89 int t_opt = 0; /* min transfer size (bytes) */
90 int T_opt = 0; /* max transfer size (bytes) */
91 int q_opt = 0; /* quiet operation on startup */
92 char TagName[40]; /* name of this iogen (see Monster) */
93 struct strmap *Offset_Mode; /* M_SEQUENTIAL, M_RANDOM, etc. */
94 int Iterations; /* # requests to generate (0 --> infinite) */
95 int Time_Mode = 0; /* non-zero if Iterations is in seconds */
96 /* (ie. -i arg was suffixed with 's') */
97 char *Outpipe; /* Pipe to write output to if p_opt */
98 int Mintrans; /* min io transfer size */
99 int Maxtrans; /* max io transfer size */
100 int Rawmult; /* raw/ssd io multiple (from -r) */
101 int Minstrides; /* min # of listio strides per request */
102 int Maxstrides; /* max # of listio strides per request */
103 int Oflags; /* open(2) flags for creating files */
104 int Ocbits; /* open(2) cbits for creating files */
105 int Ocblks; /* open(2) cblks for creating files */
106 int Orealtime=0; /* flag set for -O REALTIME */
107 int Oextsize=0; /* real-time extent size */
108 int Oreserve=1; /* flag for -O [no]reserve */
109 int Oallocate=0; /* flag for -O allocate */
110 int Owrite=1; /* flag for -O nowrite */
112 int Nfiles = 0; /* # files on cmdline */
113 struct file_info *File_List; /* info about each file */
114 int Nflags = 0; /* # flags on cmdline */
115 struct strmap *Flag_List[128]; /* flags selected from cmdline */
116 int Nsyscalls = 0; /* # syscalls on cmdline */
117 struct strmap *Syscall_List[128]; /* syscalls selected on cmdline */
118 int Fileio = 0; /* flag indicating that a file */
119 /* io syscall has been chosen. */
120 int Naio_Strat_Types = 0; /* # async io completion types */
121 struct strmap *Aio_Strat_List[128]; /* Async io completion types */
123 void startup_info(FILE *stream, int seed);
126 * Map async io completion modes (-a args) names to values. Macros are
130 struct strmap Aio_Strat_Map[] = {
133 { "signal", A_SIGNAL },
141 * Offset_Mode #defines
145 #define M_SEQUENTIAL 2
149 * Map offset mode (-m args) names to values
152 struct strmap Omode_Map[] = {
153 { "random", M_RANDOM },
154 { "sequential", M_SEQUENTIAL },
155 { "reverse", M_REVERSE },
160 * Map syscall names (-s args) to values - macros are defined in doio.h.
162 #define SY_ASYNC 00001
163 #define SY_WRITE 00002
165 #define SY_LISTIO 00020
166 #define SY_NENT 00100 /* multi entry vs multi stride >>> */
168 struct strmap Syscall_Map[] = {
170 { "write", WRITE, SY_WRITE },
172 { "pwrite", PWRITE, SY_WRITE },
173 { "resvsp", RESVSP, SY_WRITE },
174 { "unresvsp", UNRESVSP, SY_WRITE },
175 { "reserve", RESVSP, SY_WRITE },
176 { "unreserve", UNRESVSP, SY_WRITE },
178 { "writev", WRITEV, SY_WRITE },
180 { "mmwrite", MMAPW, SY_WRITE },
181 { "fsync2", FSYNC2, SY_WRITE },
182 { "fdatasync", FDATASYNC, SY_WRITE },
187 * Map open flags (-f args) to values
189 #define FLG_RAW 00001
191 struct strmap Flag_Map[] = {
192 { "buffered", 0, 0 },
193 { "sync", O_SYNC, 0 },
194 { "direct", O_DIRECT, FLG_RAW },
199 * Map file types to strings
202 struct strmap Ftype_Map[] = {
203 { "regular", S_IFREG },
204 { "blk-spec", S_IFBLK },
205 { "chr-spec", S_IFCHR },
215 char Byte_Patterns[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
216 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
217 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
221 int form_iorequest(struct io_req *);
223 int parse_cmdline(int argc, char **argv, char *opts);
224 int help(FILE *stream);
225 int usage(FILE *stream);
233 int rseed, outfd, infinite;
240 parse_cmdline(argc, argv, OPTS);
243 * Initialize output descriptor.
248 outfd = init_output();
252 random_range_seed(rseed); /* initialize random number generator */
255 * Print out startup information, unless we're running in quiet mode
258 startup_info(stderr, rseed);
260 start_time = time(0);
263 * While iterations (or forever if Iterations == 0) - compute an
264 * io request, and write the structure to the output descriptor
267 infinite = !Iterations;
270 (! Time_Mode && Iterations--) ||
271 (Time_Mode && time(0) - start_time <= Iterations)) {
273 memset(&req, 0, sizeof(struct io_req));
274 if (form_iorequest(&req) == -1) {
275 fprintf(stderr, "iogen%s: form_iorequest() failed\n", TagName);
279 req.r_magic = DOIO_MAGIC;
280 write(outfd, (char *)&req, sizeof(req));
288 startup_info(FILE *stream, int seed)
290 char *value_to_string(struct strmap *map, int val), *type;
293 fprintf(stream, "\n");
294 fprintf(stream, "iogen%s starting up with the following:\n", TagName);
295 fprintf(stream, "\n");
297 fprintf(stream, "Out-pipe: %s\n",
298 p_opt ? Outpipe : "stdout");
301 fprintf(stream, "Iterations: %d", Iterations);
303 fprintf(stream, " seconds");
305 fprintf(stream, "\n");
307 fprintf(stream, "Iterations: Infinite\n");
314 "Offset-Mode: %s\n", Offset_Mode->m_string);
316 fprintf(stream, "Overlap Flag: %s\n",
317 o_opt ? "on" : "off");
320 "Mintrans: %-11d (%d blocks)\n",
321 Mintrans, (Mintrans+BSIZE-1)/BSIZE);
324 "Maxtrans: %-11d (%d blocks)\n",
325 Maxtrans, (Maxtrans+BSIZE-1)/BSIZE);
329 "O_RAW/O_SSD Multiple: (Determined by device)\n");
332 "O_RAW/O_SSD Multiple: %-11d (%d blocks)\n",
333 Rawmult, (Rawmult+BSIZE-1)/BSIZE);
335 fprintf(stream, "Syscalls: ");
336 for (i = 0; i < Nsyscalls; i++)
338 "%s ", Syscall_List[i]->m_string);
339 fprintf(stream, "\n");
341 fprintf(stream, "Aio completion types: ");
342 for (i = 0; i < Naio_Strat_Types; i++)
344 "%s ", Aio_Strat_List[i]->m_string);
345 fprintf(stream, "\n");
348 fprintf(stream, "Flags: ");
349 for (i = 0; i < Nflags; i++)
351 "%s ", Flag_List[i]->m_string);
353 fprintf(stream, "\n");
354 fprintf(stream, "\n");
355 fprintf(stream, "Test Files: \n");
356 fprintf(stream, "\n");
358 "Path Length iou raw iou file\n");
360 " (bytes) (bytes) (bytes) type\n");
362 "-----------------------------------------------------------------------------\n");
364 for (i = 0; i < Nfiles; i++) {
365 type = value_to_string(Ftype_Map, File_List[i].f_type);
366 fprintf(stream, "%-40s %12d %7d %7d %s\n",
367 File_List[i].f_path, File_List[i].f_length,
368 File_List[i].f_iou, File_List[i].f_riou, type);
374 * Initialize output descriptor. If going to stdout, its easy,
375 * otherwise, attempt to create a FIFO on path Outpipe. Exit with an
376 * error code if this cannot be done.
384 if (stat(Outpipe, &sbuf) == -1) {
385 if (errno == ENOENT) {
386 if (mkfifo(Outpipe, 0666) == -1) {
387 fprintf(stderr, "iogen%s: Could not mkfifo %s: %s\n",
388 TagName, Outpipe, SYSERR);
392 fprintf(stderr, "iogen%s: Could not stat outpipe %s: %s\n",
393 TagName, Outpipe, SYSERR);
397 if (! S_ISFIFO(sbuf.st_mode)) {
399 "iogen%s: Output file %s exists, but is not a FIFO\n",
405 if ((outfd = open(Outpipe, O_RDWR)) == -1) {
407 "iogen%s: Couldn't open outpipe %s with flags O_RDWR: %s\n",
408 TagName, Outpipe, SYSERR);
417 * Main io generation function. form_iorequest() selects a system call to
418 * do based on cmdline arguments, and proceeds to select parameters for that
421 * Returns 0 if req is filled in with a complete doio request, otherwise
429 int mult, offset = 0, length = 0, slength;
430 int minlength, maxlength, laststart, lastend;
431 int minoffset, maxoffset;
432 int maxstride, nstrides;
434 struct strmap *flags, *sc, *aio_strat;
435 struct file_info *fptr;
438 * Choose system call, flags, and file
441 sc = Syscall_List[random_range(0, Nsyscalls-1, 1, NULL)];
442 req->r_type = sc->m_value;
444 if( sc->m_flags & SY_WRITE )
445 pattern = Byte_Patterns[random_range(0, sizeof(Byte_Patterns) - 1, 1, NULL)];
450 * otherwise, we're doing file io. Choose starting offset, length,
451 * open flags, and possibly a pattern (for write/writea).
454 fptr = &File_List[random_range(0, Nfiles-1, 1, NULL)];
455 flags = Flag_List[random_range(0, Nflags-1, 1, NULL)];
458 * Choose offset/length multiple. IO going to a device, or regular
459 * IO that is O_RAW or O_SSD must be aligned on the file r_iou. Otherwise
460 * it must be aligned on the regular iou (normally 1).
463 if ( fptr->f_type == S_IFREG && (flags->m_flags & FLG_RAW) )
469 * Choose offset and length. Both must be a multiple of mult
473 * Choose length first - it must be a multiple of mult
476 laststart = fptr->f_lastoffset;
477 lastend = fptr->f_lastoffset + fptr->f_lastlength - 1;
479 minlength = (Mintrans > mult) ? Mintrans : mult;
481 switch (Offset_Mode->m_value) {
483 if (o_opt && lastend > laststart)
484 offset = random_range(laststart, lastend, 1, NULL);
486 offset = lastend + 1;
487 if (offset && (offset%mult))
488 offset += mult - (offset % mult);
490 if (minlength > fptr->f_length - offset)
493 maxlength = fptr->f_length - offset;
494 if (maxlength > Maxtrans)
495 maxlength = Maxtrans;
497 length = random_range(minlength, maxlength, mult, &errp);
499 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
500 TagName, minlength, maxlength, mult);
507 maxlength = laststart;
509 if (maxlength > Maxtrans)
510 maxlength = Maxtrans;
512 if (minlength > maxlength) {
513 laststart = fptr->f_length;
514 lastend = fptr->f_length;
515 maxlength = Maxtrans;
518 length = random_range(minlength, maxlength, mult, &errp);
520 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
521 TagName, minlength, maxlength, mult);
525 offset = laststart - length;
527 if (o_opt && lastend > laststart)
528 offset += random_range(1, lastend - laststart, 1, NULL);
530 if (offset && (offset%mult))
531 offset -= offset % mult;
536 length = random_range(Mintrans, Maxtrans, mult, NULL);
538 if (o_opt && lastend > laststart) {
539 minoffset = laststart - length + 1;
544 if (lastend + length > fptr->f_length) {
545 maxoffset = fptr->f_length - length;
551 maxoffset = fptr->f_length - length;
557 offset = random_range(minoffset, maxoffset, mult, &errp);
559 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
560 TagName, minoffset, maxoffset, mult);
565 fptr->f_lastoffset = offset;
566 fptr->f_lastlength = length;
569 * Choose an async io completion strategy if necessary
571 if( sc->m_flags & SY_ASYNC )
572 aio_strat = Aio_Strat_List[random_range(0, Naio_Strat_Types - 1,
578 * fill in specific syscall record data
580 switch (sc->m_value) {
583 strcpy(req->r_data.read.r_file, fptr->f_path);
584 req->r_data.read.r_oflags = O_RDONLY | flags->m_value;
585 req->r_data.read.r_offset = offset;
586 req->r_data.read.r_nbytes = length;
587 req->r_data.read.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
588 req->r_data.read.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
589 req->r_data.read.r_nstrides = 1;
590 req->r_data.read.r_nent = 1;
595 strcpy(req->r_data.write.r_file, fptr->f_path);
596 req->r_data.write.r_oflags = O_WRONLY | flags->m_value;
597 req->r_data.write.r_offset = offset;
598 req->r_data.write.r_nbytes = length;
599 req->r_data.write.r_pattern = pattern;
600 req->r_data.write.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
601 req->r_data.write.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
602 req->r_data.write.r_nstrides = 1;
603 req->r_data.write.r_nent = 1;
623 strcpy(req->r_data.io.r_file, fptr->f_path);
624 req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
625 req->r_data.io.r_offset = offset;
626 req->r_data.io.r_nbytes = length;
627 req->r_data.io.r_pattern = pattern;
628 req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
629 req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
630 req->r_data.io.r_nstrides = 1;
631 req->r_data.io.r_nent = 1;
636 strcpy(req->r_data.io.r_file, fptr->f_path);
637 /* a subtle "feature" of mmap: a write-map requires
638 the file open read/write */
639 req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_RDWR : O_RDONLY) | flags->m_value;
640 req->r_data.io.r_offset = offset;
641 req->r_data.io.r_nbytes = length;
642 req->r_data.io.r_pattern = pattern;
643 req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
644 req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
645 req->r_data.io.r_nstrides = 1;
646 req->r_data.io.r_nent = 1;
658 strcpy(req->r_data.io.r_file, fptr->f_path);
659 req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
660 req->r_data.io.r_offset = offset;
661 req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
662 req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
663 req->r_data.io.r_pattern = pattern;
665 /* multi-strided request...
666 * random number of strides (1...MaxStrides)
667 * length of stride must be > minlength
668 * length of stride must be % mult
670 * maxstrides = min(length / mult, overall.max#strides)
671 * nstrides = random #
672 * while( length / nstrides < minlength )
673 * nstrides = new random #
675 maxstride = length / mult;
676 if(maxstride > Maxstrides)
677 maxstride = Maxstrides;
681 nstrides = random_range(Minstrides, maxstride, 1, &errp);
683 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
684 TagName, Minstrides, maxstride, 1);
688 slength = length / nstrides;
689 if(slength % mult != 0) {
690 if( mult > slength) {
693 slength -= slength % mult;
695 nstrides = length / slength;
696 if(nstrides > Maxstrides)
697 nstrides = Maxstrides;
700 req->r_data.io.r_nbytes = slength;
701 if( sc->m_flags & SY_NENT ) {
702 req->r_data.io.r_nstrides = 1;
703 req->r_data.io.r_nent = nstrides;
705 req->r_data.io.r_nstrides = nstrides;
706 req->r_data.io.r_nent = 1;
718 * Get information about a file that iogen uses to choose io length and
719 * offset. Information gathered is file length, iounit, and raw iounit.
720 * For regurlar files, iounit is 1, and raw iounit is the iounit of the
721 * device on which the file resides. For block/character special files
722 * the iounit and raw iounit are both the iounit of the device.
724 * Note: buffered and osync io must be iounit aligned
725 * raw and ossd io must be raw iounit aligned
730 struct file_info *rec;
734 struct dioattr finfo;
737 * Figure out if the files is regular, block or character special. Any
738 * other type is an error.
741 if (stat(rec->f_path, &sbuf) == -1) {
742 fprintf(stderr, "iogen%s: get_file_info(): Could not stat() %s: %s\n",
743 TagName, rec->f_path, SYSERR);
747 rec->f_type = sbuf.st_mode & S_IFMT;
750 * If regular, iou is 1, and we must figure out the device on
751 * which the file resides. riou is the iou (logical sector size) of
755 if (S_ISREG(sbuf.st_mode)) {
757 rec->f_length = sbuf.st_size;
760 * If -r used, take Rawmult as the raw/ssd io multiple. Otherwise
761 * attempt to determine it by looking at the device the file
766 rec->f_riou = Rawmult;
771 if( (fd = open(rec->f_path, O_RDWR|O_DIRECT, 0)) != -1 ) {
773 #ifdef XFS_IOC_DIOINFO
774 if(xfsctl(rec->f_path, fd, XFS_IOC_DIOINFO, &finfo) != -1) {
777 if(fcntl(fd, F_DIOINFO, &finfo) != -1) {
782 dio_env = getenv("XFS_DIO_MIN");
784 finfo.d_mem = finfo.d_miniosz = atoi(dio_env);
786 rec->f_riou = finfo.d_miniosz;
789 "iogen%s: Error %s (%d) getting direct I/O info of file %s\n",
790 TagName, strerror(errno), errno, rec->f_path);
794 rec->f_riou = BBSIZE;
799 rec->f_length = BSIZE;
806 * Create file path as nbytes long. If path exists, the file will either be
807 * extended or truncated to be nbytes long. Returns final size of file,
808 * or -1 if there was a failure.
812 create_file(path, nbytes)
821 struct fsxattr xattr;
822 struct dioattr finfo;
826 rval = stat(path, &sbuf);
829 if (errno == ENOENT) {
832 fprintf(stderr, "iogen%s: Could not stat file %s: %s (%d)\n",
833 TagName, path, SYSERR, errno);
837 if (! S_ISREG(sbuf.st_mode)) {
839 "iogen%s: file %s exists, but is not a regular file - cannot modify length\n",
845 if (sbuf.st_size == nbytes)
848 Oflags |= O_CREAT | O_WRONLY;
850 if ((fd = open(path, Oflags, 0666)) == -1) {
851 fprintf(stderr, "iogen%s: Could not create/open file %s: %s (%d)\n",
852 TagName, path, SYSERR, errno);
857 * Truncate file if it is longer than nbytes, otherwise attempt to
858 * pre-allocate file blocks.
861 if (sbuf.st_size > nbytes) {
862 if (ftruncate(fd, nbytes) == -1) {
864 "iogen%s: Could not ftruncate() %s to %d bytes: %s (%d)\n",
865 TagName, path, nbytes, SYSERR, errno);
872 * The file must be designated as Real-Time before any data
873 * is allocated to it.
877 bzero(&xattr, sizeof(xattr));
878 xattr.fsx_xflags = XFS_XFLAG_REALTIME;
879 /*fprintf(stderr, "set: fsx_xflags = 0x%x\n", xattr.fsx_xflags);*/
880 #ifdef XFS_IOC_FSSETXATTR
881 if( xfsctl(path, fd, XFS_IOC_FSSETXATTR, &xattr) == -1 ) {
884 if (fcntl(fd, F_FSSETXATTR, &xattr) < 0) {
889 fprintf(stderr, "iogen%s: Error %s (%d) setting XFS XATTR->Realtime on file %s\n",
890 TagName, SYSERR, errno, path);
896 #ifdef XFS_IOC_FSGETXATTR
897 if( xfsctl(path, fd, XFS_IOC_FSGETXATTR, &xattr) == -1 ) {
900 if (fcntl(fd, F_FSGETXATTR, &xattr) < 0) {
905 fprintf(stderr, "iogen%s: Error getting realtime flag %s (%d)\n",
906 TagName, SYSERR, errno);
910 fprintf(stderr, "get: fsx_xflags = 0x%x\n",
918 * Failure is ignored since XFS_IOC_RESVSP only works on XFS and the
919 * filesystem could be on some otehr filesystem.
922 f.l_whence = SEEK_SET;
927 "create_file: xfsctl(%d, RESVSP, { %d, %lld, %lld })\n",
928 fd, f.l_whence, (long long)f.l_start, (long long)f.l_len);*/
930 /* non-zeroing reservation */
931 #ifdef XFS_IOC_RESVSP
932 if( xfsctl( path, fd, XFS_IOC_RESVSP, &f ) == -1) {
934 "iogen%s: Could not xfsctl(XFS_IOC_RESVSP) %d bytes in file %s: %s (%d)\n",
935 TagName, nbytes, path, SYSERR, errno);
941 if( fcntl( fd, F_RESVSP, &f ) == -1) {
943 "iogen%s: Could not fcntl(F_RESVSP) %d bytes in file %s: %s (%d)\n",
944 TagName, nbytes, path, SYSERR, errno);
955 /* XFS_IOC_ALLOCSP allocates from the file start to l_start */
956 f.l_whence = SEEK_SET;
960 "create_file: xfsctl(%d, XFS_IOC_ALLOCSP, { %d, %lld, %lld })\n",
961 fd, f.l_whence, (long long)f.l_start,
962 (long long)f.l_len);*/
964 /* zeroing reservation */
965 #ifdef XFS_IOC_ALLOCSP
966 if( xfsctl( path, fd, XFS_IOC_ALLOCSP, &f ) == -1) {
968 "iogen%s: Could not xfsctl(XFS_IOC_ALLOCSP) %d bytes in file %s: %s (%d)\n",
969 TagName, nbytes, path, SYSERR, errno);
975 if ( fcntl(fd, F_ALLOCSP, &f) < 0) {
977 "iogen%s: Could not fcntl(F_ALLOCSP) %d bytes in file %s: %s (%d)\n",
978 TagName, nbytes, path, SYSERR, errno);
990 * Write a byte at the end of file so that stat() sets the right
996 if( (fd = open(path, O_CREAT|O_RDWR|O_DIRECT, 0)) != -1 ) {
998 #ifdef XFS_IOC_DIOINFO
999 if(xfsctl(path, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
1002 if (fcntl(fd, F_DIOINFO, &finfo) < 0) {
1008 "iogen%s: Error %s (%d) getting direct I/O info for file %s\n",
1009 TagName, SYSERR, errno, path);
1012 /*fprintf(stderr, "%s: miniosz=%d\n",
1013 path, finfo.d_miniosz);*/
1016 dio_env = getenv("XFS_DIO_MIN");
1018 finfo.d_mem = finfo.d_miniosz = atoi(dio_env);
1020 fprintf(stderr, "iogen%s: Error %s (%d) opening file %s with flags O_CREAT|O_RDWR|O_DIRECT\n",
1021 TagName, SYSERR, errno, path);
1026 * nb is nbytes adjusted down by an even d_miniosz block
1028 * Note: the first adjustment can cause iogen to print a warning
1029 * about not being able to create a file of <nbytes> length,
1030 * since the file will be shorter.
1032 nb = nbytes-finfo.d_miniosz;
1033 nb = nb-nb%finfo.d_miniosz;
1036 "create_file_ow2: lseek(%d, %d {%d %d}, SEEK_SET)\n",
1037 fd, nb, nbytes, finfo.d_miniosz);*/
1039 if (lseek(fd, nb, SEEK_SET) == -1) {
1041 "iogen%s: Could not lseek() to EOF of file %s: %s (%d)\n\tactual offset %d file size goal %d miniosz %lld\n",
1042 TagName, path, SYSERR, errno,
1043 nb, nbytes, (long long)finfo.d_miniosz);
1048 b = buf = (char *)malloc(finfo.d_miniosz+finfo.d_mem);
1050 if( ((long)buf % finfo.d_mem != 0) ) {
1051 buf += finfo.d_mem - ((long)buf % finfo.d_mem);
1054 memset(buf, 0, finfo.d_miniosz);
1056 if ( (rval=write(fd, buf, finfo.d_miniosz)) != finfo.d_miniosz) {
1058 "iogen%s: Could not write %d byte length file %s: %s (%d)\n",
1059 TagName, nb, path, SYSERR, errno);
1061 "\twrite(%d, 0x%lx, %d) = %d\n",
1062 fd, (long)buf, finfo.d_miniosz, rval);
1064 "\toffset %d file size goal %d, miniosz=%d\n",
1065 nb, nbytes, finfo.d_miniosz);
1073 "create_file_Owrite: lseek(%d, %d {%d}, SEEK_SET)\n",
1074 fd, nbytes-1, nbytes);*/
1076 if (lseek(fd, nbytes-1, SEEK_SET) == -1) {
1078 "iogen%s: Could not lseek() to EOF in file %s: %s (%d)\n\toffset goal %d\n",
1079 TagName, path, SYSERR, errno,
1085 if ( (rval=write(fd, &c, 1)) != 1) {
1087 "iogen%s: Could not create a %d byte length file %s: %s (%d)\n",
1088 TagName, nbytes, path, SYSERR, errno);
1090 "\twrite(%d, 0x%lx, %d) = %d\n",
1091 fd, (long)&c, 1, rval);
1093 "\toffset %d file size goal %d\n",
1104 return sbuf.st_size;
1108 * Function to convert a string to its corresponding value in a strmap array.
1109 * If the string is not found in the array, the value corresponding to the
1110 * NULL string (the last element in the array) is returned.
1114 str_to_value(map, str)
1120 for (mp = map; mp->m_string != NULL; mp++)
1121 if (strcmp(mp->m_string, str) == 0)
1128 * Function to convert a string to its corresponding entry in a strmap array.
1129 * If the string is not found in the array, a NULL is returned.
1133 str_lookup(map, str)
1139 for (mp = map; mp->m_string != NULL; mp++)
1140 if (strcmp(mp->m_string, str) == 0)
1143 return((mp->m_string == NULL) ? NULL : mp);
1148 * Function to convert a value to its corresponding string in a strmap array.
1149 * If the value is not found in the array, NULL is returned.
1153 value_to_string(map, val)
1159 for (mp = map; mp->m_string != NULL; mp++)
1160 if (mp->m_value == val)
1163 return mp->m_string;
1167 * Interpret cmdline options/arguments. Exit with 1 if something on the
1168 * cmdline isn't kosher.
1172 parse_cmdline(argc, argv, opts)
1177 int o, len, nb, format_error;
1178 struct strmap *flgs, *sc;
1179 char *file, *cp, ch;
1181 struct file_info *fptr;
1183 char *openargs[5]; /* Flags, cbits, cblks */
1184 while ((o = getopt(argc, argv, opts)) != EOF) {
1188 fprintf(stderr, "iogen%s: Unrecognized option -a on this platform\n", TagName);
1193 cp = strtok(optarg, ",");
1194 while (cp != NULL) {
1195 if( (flgs = str_lookup(Flag_Map, cp)) == NULL ) {
1196 fprintf(stderr, "iogen%s: Unrecognized flags: %s\n", TagName, cp);
1200 cp = strtok(NULL, ",");
1203 if (flgs->m_value & O_SSD && ! Sds_Avail) {
1204 fprintf(stderr, "iogen%s: Warning - no sds available, ignoring ssd flag\n", TagName);
1209 Flag_List[Nflags++] = flgs;
1222 switch (sscanf(optarg, "%i%c", &Iterations, &ch)) {
1242 fprintf(stderr, "iogen%s: Illegal -i arg (%s): Must be of the format: number[s]\n", TagName, optarg);
1243 fprintf(stderr, " where 'number' is >= 0\n");
1251 fprintf(stderr, "iogen%s: Unrecognized option -L on this platform\n", TagName);
1256 if ((Offset_Mode = str_lookup(Omode_Map, optarg)) == NULL) {
1257 fprintf(stderr, "iogen%s: Illegal -m arg (%s)\n", TagName, optarg);
1265 sprintf( TagName, "(%.37s)", optarg );
1274 nopenargs = string_to_tokens(optarg, openargs, 4, ":/");
1275 if(!strcmp(openargs[0], "realtime")) {
1277 * -O realtime:extsize
1281 sscanf(openargs[1],"%i", &Oextsize);
1284 } else if( !strcmp(openargs[0], "allocate") ||
1285 !strcmp(openargs[0], "allocsp")) {
1291 } else if(!strcmp(openargs[0], "reserve")) {
1297 } else if(!strcmp(openargs[0], "noreserve")) {
1298 /* Oreserve=1 by default; this clears that default */
1300 } else if(!strcmp(openargs[0], "nowrite")) {
1301 /* Owrite=1 by default; this clears that default */
1303 } else if(!strcmp(openargs[0], "direct")) {
1304 /* this means "use direct i/o to preallocate file" */
1307 fprintf(stderr, "iogen%s: Error: -O %s error: unrecognized option\n",
1308 TagName, openargs[0]);
1320 if ((Rawmult = str_to_bytes(optarg)) == -1 ||
1321 Rawmult < 11 || Rawmult % BSIZE) {
1322 fprintf(stderr, "iogen%s: Illegal -r arg (%s). Must be > 0 and multipe of BSIZE (%d)\n",
1323 TagName, optarg, BSIZE);
1331 cp = strtok(optarg, ",");
1332 while (cp != NULL) {
1333 if ((sc = str_lookup(Syscall_Map, cp)) == NULL) {
1334 fprintf(stderr, "iogen%s: Unrecognized syscall: %s\n", TagName, cp);
1339 /* >>> sc->m_flags & FLG_SDS */
1340 if (sc->m_value != SSREAD && sc->m_value != SSWRITE)
1343 Syscall_List[Nsyscalls++] = sc;
1344 } while ( (sc = str_lookup(++sc, cp)) != NULL);
1346 cp = strtok(NULL, ",");
1352 if ((Mintrans = str_to_bytes(optarg)) == -1) {
1353 fprintf(stderr, "iogen%s: Illegal -t arg (%s): Must have the form num[bkm]\n", TagName, optarg);
1360 if ((Maxtrans = str_to_bytes(optarg)) == -1) {
1361 fprintf(stderr, "iogen%s: Illegal -T arg (%s): Must have the form num[bkm]\n", TagName, optarg);
1387 Offset_Mode = str_lookup(Omode_Map, "sequential");
1396 Maxtrans = 256 * BSIZE;
1399 Oflags = Ocbits = Ocblks = 0;
1402 * Supply default async io completion strategy types.
1406 for (mp = Aio_Strat_Map; mp->m_string != NULL; mp++) {
1407 Aio_Strat_List[Naio_Strat_Types++] = mp;
1412 * Supply default syscalls. Default is read,write,reada,writea,listio.
1417 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "read");
1418 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "write");
1419 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pread");
1420 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pwrite");
1421 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "readv");
1422 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writev");
1423 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmread");
1424 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmwrite");
1429 if (Fileio && (argc - optind < 1)) {
1430 fprintf(stderr, "iogen%s: No files specified on the cmdline\n", TagName);
1435 * Supply default file io flags - defaut is 'buffered,raw,sync,ldraw'.
1438 if (! f_opt && Fileio) {
1440 Flag_List[Nflags++] = str_lookup(Flag_Map, "buffered");
1441 Flag_List[Nflags++] = str_lookup(Flag_Map, "sync");
1445 if (optind >= argc) {
1446 fprintf(stderr, "iogen%s: No files listed on the cmdline\n", TagName);
1451 * Initialize File_List[] - only necessary if doing file io. First
1452 * space for the File_List array, then fill it in.
1455 File_List = (struct file_info *)
1456 malloc((argc-optind) * sizeof(struct file_info));
1458 if (File_List == NULL) {
1459 fprintf(stderr, "iogen%s: Could not malloc space for %d file_info structures\n", TagName, argc-optind);
1463 memset(File_List, 0, (argc-optind) * sizeof(struct file_info));
1466 while (optind < argc) {
1470 * Pick off leading len: if it's there and create/extend/trunc
1471 * the file to the desired length. Otherwise, just make sure
1472 * the file is accessable.
1475 if ((cp = strchr(argv[optind], ':')) != NULL) {
1477 if ((len = str_to_bytes(argv[optind])) == -1) {
1479 "iogen%s: illegal file length (%s) for file %s\n",
1480 TagName, argv[optind], cp+1);
1486 if (strlen(file) > MAX_FNAME_LENGTH) {
1487 fprintf(stderr, "iogen%s: Max fname length is %d chars - ignoring file %s\n",
1488 TagName, MAX_FNAME_LENGTH, file);
1493 nb = create_file(file, len);
1497 "iogen%s warning: Couldn't create file %s of %d bytes\n",
1498 TagName, file, len);
1506 file = argv[optind];
1507 if (access(file, R_OK | W_OK) == -1) {
1508 fprintf(stderr, "iogen%s: file %s cannot be accessed for reading and/or writing: %s (%d)\n",
1509 TagName, file, SYSERR, errno);
1515 * get per-file information
1518 fptr = &File_List[Nfiles];
1520 if (file[0] == '/') {
1521 strcpy(fptr->f_path, file);
1523 getcwd(fptr->f_path,
1524 sizeof(fptr->f_path)-1);
1525 strcat(fptr->f_path, "/");
1526 strcat(fptr->f_path, file);
1529 if (get_file_info(fptr) == -1) {
1530 fprintf(stderr, "iogen%s warning: Error getting file info for %s\n", TagName, file);
1534 * If the file length is smaller than our min transfer size,
1538 if (fptr->f_length < Mintrans) {
1539 fprintf(stderr, "iogen%s warning: Ignoring file %s\n",
1540 TagName, fptr->f_path);
1541 fprintf(stderr, " length (%d) is < min transfer size (%d)\n",
1542 fptr->f_length, Mintrans);
1548 * If the file length is smaller than our max transfer size,
1552 if (fptr->f_length < Maxtrans) {
1553 fprintf(stderr, "iogen%s warning: Ignoring file %s\n",
1554 TagName, fptr->f_path);
1555 fprintf(stderr, " length (%d) is < max transfer size (%d)\n",
1556 fptr->f_length, Maxtrans);
1561 if (fptr->f_length > 0) {
1562 switch (Offset_Mode->m_value) {
1564 fptr->f_lastoffset = 0;
1565 fptr->f_lastlength = 0;
1569 fptr->f_lastoffset = fptr->f_length;
1570 fptr->f_lastlength = 0;
1574 fptr->f_lastoffset = fptr->f_length / 2;
1575 fptr->f_lastlength = 0;
1587 fprintf(stderr, "iogen%s: Could not create, or gather info for any test files\n", TagName);
1600 fprintf(stream, "\n");
1602 fprintf(stream, "\t-a aio_type,... Async io completion types to choose. Supported types\n");
1603 fprintf(stream, "\t are: poll, signal, suspend, and callback.\n");
1604 fprintf(stream, "\t Default is all of the above.\n");
1606 fprintf(stream, "\t-a (Not used on Linux).\n");
1608 fprintf(stream, "\t-f flag,... Flags to use for file IO. Supported flags are\n");
1609 fprintf(stream, "\t buffered, direct, sync.\n");
1610 fprintf(stream, "\t Default is 'buffered,sync'.\n");
1611 fprintf(stream, "\t-h This help.\n");
1612 fprintf(stream, "\t-i iterations[s] # of requests to generate. 0 means causes iogen\n");
1613 fprintf(stream, "\t to run until it's killed. If iterations is suffixed\n");
1614 fprintf(stream, "\t with 's', then iterations is the number of seconds\n");
1615 fprintf(stream, "\t that iogen should run for. Default is '0'.\n");
1616 fprintf(stream, "\t-L min:max listio nstrides / nrequests range\n");
1617 fprintf(stream, "\t-m offset-mode The mode by which iogen chooses the offset for\n");
1618 fprintf(stream, "\t consectutive transfers within a given file.\n");
1619 fprintf(stream, "\t Allowed values are 'random', 'sequential',\n");
1620 fprintf(stream, "\t and 'reverse'.\n");
1621 fprintf(stream, "\t sequential is the default.\n");
1622 fprintf(stream, "\t-N tagname Tag name, for Monster.\n");
1623 fprintf(stream, "\t-o Form overlapping consecutive requests.\n");
1624 fprintf(stream, "\t-O Open flags for creating files\n");
1625 fprintf(stream, "\t realtime:extsize - put file on real-time volume\n");
1626 fprintf(stream, "\t allocate - allocate space with F_ALLOCSP\n");
1627 fprintf(stream, "\t reserve - reserve space with F_RESVSP (default)\n");
1628 fprintf(stream, "\t noreserve - do not reserve with F_RESVSP\n");
1629 fprintf(stream, "\t direct - use O_DIRECT I/O to write to the file\n");
1630 fprintf(stream, "\t-p Output pipe. Default is stdout.\n");
1631 fprintf(stream, "\t-q Quiet mode. Normally iogen spits out info\n");
1632 fprintf(stream, "\t about test files, options, etc. before starting.\n");
1633 fprintf(stream, "\t-s syscall,... Syscalls to do. Supported syscalls are\n");
1635 fprintf(stream, "\t read, write, pread, pwrite, readv, writev,\n");
1636 fprintf(stream, "\t mmread, mmwrite, fsync2, fdatasync,\n");
1637 fprintf(stream, "\t Default is 'read,write,readv,writev,mmread,mmwrite'.\n");
1639 fprintf(stream, "\t-t mintrans Min transfer length\n");
1640 fprintf(stream, "\t-T maxtrans Max transfer length\n");
1641 fprintf(stream, "\n");
1642 fprintf(stream, "\t[len:]file,... Test files to do IO against (note ssread/sswrite\n");
1643 fprintf(stream, "\t don't need a test file). The len: syntax\n");
1644 fprintf(stream, "\t informs iogen to first create/expand/truncate the\n");
1645 fprintf(stream, "\t to the desired length.\n");
1646 fprintf(stream, "\n");
1647 fprintf(stream, "\tNote: The ssd flag causes sds transfers to also be done.\n");
1648 fprintf(stream, "\t To totally eliminate sds transfers, you must eleminate sds\n");
1649 fprintf(stream, "\t from the flags (-f) and ssread,ssrite from the syscalls (-s)\n");
1650 fprintf(stream, "\tThe mintrans, maxtrans, and len: parameters are numbers of the\n");
1651 fprintf(stream, "\tform [0-9]+[bkm]. The optional trailing b, k, or m multiplies\n");
1652 fprintf(stream, "\tthe number by blocks, kilobytes, or megabytes. If no trailing\n");
1653 fprintf(stream, "\tmultiplier is present, the number is interpreted as bytes\n");
1659 * Obvious - usage clause
1666 fprintf(stream, "usage%s: iogen [-hoq] [-a aio_type,...] [-f flag[,flag...]] [-i iterations] [-p outpipe] [-m offset-mode] [-s syscall[,syscall...]] [-t mintrans] [-T maxtrans] [ -O file-create-flags ] [[len:]file ...]\n", TagName);