2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
33 * doio - a general purpose io initiator with system call and
34 * write logging. See doio.h for the structure which defines
35 * what doio requests should look like.
40 * messages should generally be printed using doio_fprintf().
47 #include <aio.h> /* for aio_read,write */
48 #include <inttypes.h> /* for uint64_t type */
49 #include <siginfo.h> /* signal handlers & SA_SIGINFO */
52 #include <sys/uio.h> /* for struct iovec (readv)*/
53 #include <sys/mman.h> /* for mmap(2) */
54 #include <sys/ipc.h> /* for i/o buffer in shared memory */
55 #include <sys/shm.h> /* for i/o buffer in shared memory */
57 #include <sys/time.h> /* for delays */
62 int do_xfsctl(struct io_req *);
67 #include "write_log.h"
68 #include "random_range.h"
69 #include "string_to_tokens.h"
72 #define O_SSD 0 /* so code compiles on a CRAY2 */
75 #define UINT64_T unsigned long long
78 #define O_PARALLEL 0 /* so O_PARALLEL may be used in expressions */
81 #define PPID_CHECK_INTERVAL 5 /* check ppid every <-- iterations */
82 #define MAX_AIO 256 /* maximum number of async I/O ops */
84 #define MPP_BUMP 16 /* page un-alignment for MPP */
90 #define SYSERR strerror(errno)
93 * getopt() string of supported cmdline arguments.
96 #define OPTS "aC:d:ehm:n:kr:w:vU:V:M:N:"
98 #define DEF_RELEASE_INTERVAL 0
101 * Flags set in parse_cmdline() to indicate which options were selected
105 int a_opt = 0; /* abort on data compare errors */
106 int e_opt = 0; /* exec() after fork()'ing */
107 int C_opt = 0; /* Data Check Type */
108 int d_opt = 0; /* delay between operations */
109 int k_opt = 0; /* lock file regions during writes */
110 int m_opt = 0; /* generate periodic messages */
111 int n_opt = 0; /* nprocs */
112 int r_opt = 0; /* resource release interval */
113 int w_opt = 0; /* file write log file */
114 int v_opt = 0; /* verify writes if set */
115 int U_opt = 0; /* upanic() on varios conditions */
116 int V_opt = 0; /* over-ride default validation fd type */
117 int M_opt = 0; /* data buffer allocation types */
118 char TagName[40]; /* name of this doio (see Monster) */
122 * Misc globals initialized in parse_cmdline()
125 char *Prog = NULL; /* set up in parse_cmdline() */
126 int Upanic_Conditions; /* set by args to -U */
127 int Release_Interval; /* arg to -r */
128 int Nprocs; /* arg to -n */
129 char *Write_Log; /* arg to -w */
130 char *Infile; /* input file (defaults to stdin) */
131 int *Children; /* pids of child procs */
133 int Nsiblings = 0; /* tfork'ed siblings */
135 int Message_Interval = 0;
136 int Npes = 0; /* non-zero if built as an mpp multi-pe app */
137 int Vpe = -1; /* Virtual pe number if Npes >= 0 */
138 int Reqno = 1; /* request # - used in some error messages */
139 int Reqskipcnt = 0; /* count of I/O requests that are skipped */
140 int Validation_Flags;
141 char *(*Data_Check)(); /* function to call for data checking */
142 int (*Data_Fill)(); /* function to call for data filling */
143 int Nmemalloc = 0; /* number of memory allocation strategies */
144 int delayop = 0; /* delay between operations - type of delay */
145 int delaytime = 0; /* delay between operations - how long */
147 struct wlog_file Wlog;
149 int active_mmap_rw = 0; /* Indicates that mmapped I/O is occurring. */
150 /* Used by sigbus_action() in the child doio. */
153 #define SKIP_REQ -2 /* skip I/O request */
156 #define MEM_DATA 1 /* data space */
157 #define MEM_SHMEM 2 /* System V shared memory */
158 #define MEM_T3ESHMEM 3 /* T3E Shared Memory */
159 #define MEM_MMAP 4 /* mmap(2) */
161 #define MEMF_PRIVATE 0001
162 #define MEMF_AUTORESRV 0002
163 #define MEMF_LOCAL 0004
164 #define MEMF_SHARED 0010
166 #define MEMF_FIXADDR 0100
167 #define MEMF_ADDR 0200
168 #define MEMF_AUTOGROW 0400
169 #define MEMF_FILE 01000 /* regular file -- unlink on close */
170 #define MEMF_MPIN 010000 /* use mpin(2) to lock pages in memory */
177 void *space; /* memory address of allocated space */
178 int fd; /* FD open for mmaping */
180 } Memalloc[NMEMALLOC];
183 * Global file descriptors
186 int Wfd_Append; /* for appending to the write-log */
187 int Wfd_Random; /* for overlaying write-log entries */
190 * Structure for maintaining open file test descriptors. Used by
195 char c_file[MAX_FNAME_LENGTH+1];
200 int c_memalign; /* from xfsctl(XFS_IOC_DIOINFO) */
205 void *c_memaddr; /* mmapped address */
206 int c_memlen; /* length of above region */
210 #define FD_ALLOC_INCR 32 /* allocate this many fd_map structs */
214 * Globals for tracking Sds and Core usage
217 char *Memptr; /* ptr to core buffer space */
218 int Memsize; /* # bytes pointed to by Memptr */
219 /* maintained by alloc_mem() */
221 int Sdsptr; /* sds offset (always 0) */
222 int Sdssize; /* # bytes of allocated sds space */
223 /* Maintained by alloc_sds() */
229 * Signal handlers, and related globals
232 void sigint_handler(); /* Catch SIGINT in parent doio, propagate
233 * to children, does not die. */
235 void die_handler(); /* Bad sig in child doios, exit 1. */
236 void cleanup_handler(); /* Normal kill, exit 0. */
239 void sigbus_handler(); /* Handle sigbus--check active_mmap_rw to
240 decide if this should be a normal exit. */
243 void cb_handler(); /* Posix aio callback handler. */
244 void noop_handler(); /* Delayop alarm, does nothing. */
248 char *format_listio();
250 int doio_fprintf(FILE *stream, char *format, ...);
255 int alloc_fd( char *, int );
256 int alloc_mem( int );
257 int do_read( struct io_req * );
258 int do_write( struct io_req * );
259 int do_rw( struct io_req * );
260 int do_sync( struct io_req * );
262 int aio_unregister( int );
263 int parse_cmdline( int, char **, char * );
264 int lock_file_region( char *, int, int, int, int );
265 struct fd_cache *alloc_fdcache(char *, int);
266 int aio_register( int, int, int );
272 * Upanic conditions, and a map from symbolics to values
275 #define U_CORRUPTION 0001 /* upanic on data corruption */
276 #define U_IOSW 0002 /* upanic on bad iosw */
277 #define U_RVAL 0004 /* upanic on bad rval */
279 #define U_ALL (U_CORRUPTION | U_IOSW | U_RVAL)
283 * Used to map cmdline arguments to values
290 struct smap Upanic_Args[] = {
291 { "corruption", U_CORRUPTION },
309 int aio_ret; /* from aio_return */
310 int aio_errno; /* from aio_error */
314 struct sigaction osa;
317 struct aio_info Aio_Info[MAX_AIO];
319 struct aio_info *aio_slot();
320 int aio_done( struct aio_info * );
322 /* -C data-fill/check type */
324 struct smap checkmap[] = {
325 { "default", C_DEFAULT },
329 /* -d option delay types */
330 #define DELAY_SELECT 1
331 #define DELAY_SLEEP 2
332 #define DELAY_SGINAP 3
333 #define DELAY_ALARM 4
334 #define DELAY_ITIMER 5 /* POSIX timer */
336 struct smap delaymap[] = {
337 { "select", DELAY_SELECT },
338 { "sleep", DELAY_SLEEP },
340 { "sginap", DELAY_SGINAP },
342 { "alarm", DELAY_ALARM },
348 * strerror() does similar actions.
353 static char sys_errno[10];
354 sprintf(sys_errno, "%d", errno);
365 int i, pid, stat, ex_stat;
368 umask(0); /* force new file modes to known values */
370 Npes = sysconf(_SC_CRAY_NPES); /* must do this before parse_cmdline */
371 Vpe = sysconf(_SC_CRAY_VPE);
375 parse_cmdline(argc, argv, OPTS);
377 random_range_seed(getpid()); /* initialize random number generator */
380 * If this is a re-exec of doio, jump directly into the doio function.
389 * Stop on all but a few signals...
391 sigemptyset(&sa.sa_mask);
392 sa.sa_handler = sigint_handler;
393 sa.sa_flags = SA_RESETHAND; /* sigint is ignored after the */
395 for (i = 1; i <= NSIG; i++) {
416 sigaction(i, &sa, NULL);
421 * If we're logging write operations, make a dummy call to wlog_open
422 * to initialize the write history file. This call must be done in
423 * the parent, to ensure that the history file exists and/or has
424 * been truncated before any children attempt to open it, as the doio
425 * children are not allowed to truncate the file.
429 strcpy(Wlog.w_file, Write_Log);
431 if (wlog_open(&Wlog, 1, 0666) < 0) {
433 "Could not create/truncate write log %s\n",
442 * Malloc space for the children pid array. Initialize all entries
446 Children = (int *)malloc(sizeof(int) * Nprocs);
447 for (i = 0; i < Nprocs; i++) {
451 omask = sigblock(sigmask(SIGCLD));
454 * Fork Nprocs. This [parent] process is a watchdog, to notify the
455 * invoker of procs which exit abnormally, and to make sure that all
456 * child procs get cleaned up. If the -e option was used, we will also
457 * re-exec. This is mostly for unicos/mk on mpp's, to ensure that not
458 * all of the doio's don't end up in the same pe.
460 * Note - if Nprocs is 1, or this doio is a multi-pe app (Npes > 1),
461 * jump directly to doio(). multi-pe apps can't fork(), and there is
462 * no reason to fork() for 1 proc.
465 if (Nprocs == 1 || Npes > 1) {
469 for (i = 0; i < Nprocs; i++) {
470 if ((pid = fork()) == -1) {
472 "(parent) Could not fork %d children: %s (%d)\n",
477 Children[Nchildren] = pid;
485 argv[0] = (char *)malloc(strlen(exec_path + 1));
486 sprintf(argv[0], "-%s", exec_path);
488 execvp(exec_path, argv);
490 "(parent) Could not execvp %s: %s (%d)\n",
491 exec_path, SYSERR, errno);
501 * Parent spins on wait(), until all children exit.
507 if ((pid = wait(&stat)) == -1) {
512 for (i = 0; i < Nchildren; i++)
513 if (Children[i] == pid)
518 if (WIFEXITED(stat)) {
519 switch (WEXITSTATUS(stat)) {
526 "(parent) pid %d exited because of an internal error\n",
528 ex_stat |= E_INTERNAL;
533 "(parent) pid %d exited because of a setup error\n",
540 "(parent) pid %d exited because of data compare errors\n",
543 ex_stat |= E_COMPARE;
552 "(parent) pid %d exited because of a usage error\n",
560 "(parent) pid %d exited with unknown status %d\n",
561 pid, WEXITSTATUS(stat));
562 ex_stat |= E_INTERNAL;
565 } else if (WIFSIGNALED(stat) && WTERMSIG(stat) != SIGINT) {
567 "(parent) pid %d terminated by signal %d\n",
568 pid, WTERMSIG(stat));
582 * main doio function. Each doio child starts here, and never returns.
588 int rval, i, infd, nbytes;
591 struct sigaction sa, def_action, ignore_action, exit_action;
593 struct sigaction sigbus_action;
596 Memsize = Sdssize = 0;
599 * Initialize the Pattern - write-type syscalls will replace Pattern[1]
600 * with the pattern passed in the request. Make sure that
601 * strlen(Pattern) is not mod 16 so that out of order words will be
605 gethostname(Host, sizeof(Host));
606 if ((cp = strchr(Host, '.')) != NULL)
609 Pattern_Length = sprintf(Pattern, "-:%d:%s:%s*", (int)getpid(), Host, Prog);
611 if (!(Pattern_Length % 16)) {
612 Pattern_Length = sprintf(Pattern, "-:%d:%s:%s**",
613 (int)getpid(), Host, Prog);
617 * Open a couple of descriptors for the write-log file. One descriptor
618 * is for appending, one for random access. Write logging is done for
619 * file corruption detection. The program doio_check is capable of
620 * doing corruption detection based on a doio write-log.
625 strcpy(Wlog.w_file, Write_Log);
627 if (wlog_open(&Wlog, 0, 0666) == -1) {
629 "Could not open write log file (%s): wlog_open() failed\n",
636 * Open the input stream - either a file or stdin
639 if (Infile == NULL) {
642 if ((infd = open(Infile, O_RDWR)) == -1) {
644 "Could not open input file (%s): %s (%d)\n",
645 Infile, SYSERR, errno);
651 * Define a set of signals that should never be masked. Receipt of
652 * these signals generally indicates a programming error, and we want
653 * a corefile at the point of error. We put SIGQUIT in this list so
654 * that ^\ will force a user core dump.
656 * Note: the handler for these should be SIG_DFL, all of them
657 * produce a corefile as the default action.
660 ignore_action.sa_handler = SIG_IGN;
661 ignore_action.sa_flags = 0;
662 sigemptyset(&ignore_action.sa_mask);
664 def_action.sa_handler = SIG_DFL;
665 def_action.sa_flags = 0;
666 sigemptyset(&def_action.sa_mask);
669 exit_action.sa_sigaction = cleanup_handler;
670 exit_action.sa_flags = SA_SIGINFO;
671 sigemptyset(&exit_action.sa_mask);
673 sa.sa_sigaction = die_handler;
674 sa.sa_flags = SA_SIGINFO;
675 sigemptyset(&sa.sa_mask);
677 sigbus_action.sa_sigaction = sigbus_handler;
678 sigbus_action.sa_flags = SA_SIGINFO;
679 sigemptyset(&sigbus_action.sa_mask);
681 exit_action.sa_handler = cleanup_handler;
682 exit_action.sa_flags = 0;
683 sigemptyset(&exit_action.sa_mask);
685 sa.sa_handler = die_handler;
687 sigemptyset(&sa.sa_mask);
690 sigbus_action.sa_handler = sigbus_handler;
691 sigbus_action.sa_flags = 0;
692 sigemptyset(&sigbus_action.sa_mask);
696 for (i = 1; i <= NSIG; i++) {
698 /* Signals to terminate program on */
700 sigaction(i, &exit_action, NULL);
704 /* This depends on active_mmap_rw */
706 sigaction(i, &sigbus_action, NULL);
710 /* Signals to Ignore... */
716 sigaction(i, &ignore_action, NULL);
719 /* Signals to trap & report & die */
722 #ifdef SIGERR /* cray only signals */
735 sigaction(i, &sa, NULL);
739 /* Default Action for all other signals */
741 sigaction(i, &def_action, NULL);
747 * Main loop - each doio proc does this until the read returns eof (0).
748 * Call the appropriate io function based on the request type.
751 while ((nbytes = read(infd, (char *)&ioreq, sizeof(ioreq)))) {
754 * Periodically check our ppid. If it is 1, the child exits to
755 * help clean up in the case that the main doio process was
759 if (Reqno && ((Reqno % PPID_CHECK_INTERVAL) == 0)) {
760 if (getppid() == 1) {
762 "Parent doio process has exited\n");
770 "read of %d bytes from input failed: %s (%d)\n",
771 sizeof(ioreq), SYSERR, errno);
776 if (nbytes != sizeof(ioreq)) {
778 "read wrong # bytes from input stream, expected %d, got %d\n",
779 sizeof(ioreq), nbytes);
784 if (ioreq.r_magic != DOIO_MAGIC) {
786 "got a bad magic # from input stream. Expected 0%o, got 0%o\n",
787 DOIO_MAGIC, ioreq.r_magic);
793 * If we're on a Release_Interval multiple, relase all ssd and
794 * core space, and close all fd's in Fd_Map[].
797 if (Reqno && Release_Interval && ! (Reqno%Release_Interval)) {
808 ssbreak(-1 * btoc(Sdssize));
817 switch (ioreq.r_type) {
820 rval = do_read(&ioreq);
825 rval = do_write(&ioreq);
848 rval = do_rw(&ioreq);
854 rval = do_ssdio(&ioreq);
858 rval = do_listio(&ioreq);
865 rval = do_xfsctl(&ioreq);
872 rval = do_sync(&ioreq);
877 "Don't know how to handle io request type %d\n",
883 if (rval == SKIP_REQ){
886 else if (rval != 0) {
889 "doio(): operation %d returned != 0\n",
894 if (Message_Interval && Reqno % Message_Interval == 0) {
895 doio_fprintf(stderr, "Info: %d requests done (%d skipped) by this process\n", Reqno, Reqskipcnt);
905 * Child exits normally
915 struct timeval tv_delay;
916 struct sigaction sa_al, sa_old;
921 tv_delay.tv_sec = delaytime / 1000000;
922 tv_delay.tv_usec = delaytime % 1000000;
923 /*doio_fprintf(stdout, "delay_select: %d %d\n",
924 tv_delay.tv_sec, tv_delay.tv_usec);*/
925 select(0, NULL, NULL, NULL, &tv_delay);
940 sa_al.sa_handler = noop_handler;
941 sigemptyset(&sa_al.sa_mask);
942 sigaction(SIGALRM, &sa_al, &sa_old);
943 sigemptyset(&al_mask);
945 sigsuspend(&al_mask);
946 sigaction(SIGALRM, &sa_old, 0);
953 * Format IO requests, returning a pointer to the formatted text.
955 * format_strat - formats the async i/o completion strategy
956 * format_rw - formats a read[a]/write[a] request
957 * format_sds - formats a ssread/sswrite request
958 * format_listio- formats a listio request
960 * ioreq is the doio io request structure.
963 struct smap sysnames[] = {
967 { "WRITEA", WRITEA },
968 { "SSREAD", SSREAD },
969 { "SSWRITE", SSWRITE },
970 { "LISTIO", LISTIO },
972 { "LREADA", LREADA },
973 { "LWRITE", LWRITE },
974 { "LWRITEA", LWRITEA },
975 { "LSREAD", LSREAD },
976 { "LSREADA", LSREADA },
977 { "LSWRITE", LSWRITE },
978 { "LSWRITEA", LSWRITEA },
980 /* Irix System Calls */
982 { "PWRITE", PWRITE },
984 { "AWRITE", AWRITE },
985 { "LLREAD", LLREAD },
986 { "LLAREAD", LLAREAD },
987 { "LLWRITE", LLWRITE },
988 { "LLAWRITE", LLAWRITE },
989 { "RESVSP", RESVSP },
990 { "UNRESVSP", UNRESVSP },
992 /* Irix and Linux System Calls */
994 { "WRITEV", WRITEV },
997 { "FSYNC2", FSYNC2 },
998 { "FDATASYNC", FDATASYNC },
1003 struct smap aionames[] = {
1005 { "signal", A_SIGNAL },
1006 { "recall", A_RECALL },
1007 { "recalla", A_RECALLA },
1008 { "recalls", A_RECALLS },
1009 { "suspend", A_SUSPEND },
1010 { "callback", A_CALLBACK },
1016 format_oflags(int oflags)
1022 switch(oflags & 03) {
1023 case O_RDONLY: strcat(flags,"O_RDONLY,"); break;
1024 case O_WRONLY: strcat(flags,"O_WRONLY,"); break;
1025 case O_RDWR: strcat(flags,"O_RDWR,"); break;
1026 default: strcat(flags,"O_weird"); break;
1030 strcat(flags,"O_EXCL,");
1033 strcat(flags,"O_SYNC,");
1036 strcat(flags,"O_RAW,");
1037 if(oflags & O_WELLFORMED)
1038 strcat(flags,"O_WELLFORMED,");
1041 strcat(flags,"O_SSD,");
1043 if(oflags & O_LDRAW)
1044 strcat(flags,"O_LDRAW,");
1045 if(oflags & O_PARALLEL)
1046 strcat(flags,"O_PARALLEL,");
1048 strcat(flags,"O_BIG,");
1049 if(oflags & O_PLACE)
1050 strcat(flags,"O_PLACE,");
1051 if(oflags & O_ASYNC)
1052 strcat(flags,"O_ASYNC,");
1055 if(oflags & O_DIRECT)
1056 strcat(flags,"O_DIRECT,");
1058 if(oflags & O_DSYNC)
1059 strcat(flags,"O_DSYNC,");
1060 if(oflags & O_RSYNC)
1061 strcat(flags,"O_RSYNC,");
1064 return(strdup(flags));
1068 format_strat(int strategy)
1074 case A_POLL: aio_strat = "POLL"; break;
1075 case A_SIGNAL: aio_strat = "SIGNAL"; break;
1076 case A_RECALL: aio_strat = "RECALL"; break;
1077 case A_RECALLA: aio_strat = "RECALLA"; break;
1078 case A_RECALLS: aio_strat = "RECALLS"; break;
1079 case A_SUSPEND: aio_strat = "SUSPEND"; break;
1080 case A_CALLBACK: aio_strat = "CALLBACK"; break;
1081 case 0: aio_strat = "<zero>"; break;
1083 sprintf(msg, "<error:%#o>", strategy);
1084 aio_strat = strdup(msg);
1093 struct io_req *ioreq,
1105 static char *errbuf=NULL;
1106 char *aio_strat, *cp;
1107 struct read_req *readp = &ioreq->r_data.read;
1108 struct write_req *writep = &ioreq->r_data.write;
1109 struct read_req *readap = &ioreq->r_data.read;
1110 struct write_req *writeap = &ioreq->r_data.write;
1113 errbuf = (char *)malloc(32768);
1116 cp += sprintf(cp, "Request number %d\n", Reqno);
1118 switch (ioreq->r_type) {
1120 cp += sprintf(cp, "syscall: read(%d, %#lo, %d)\n",
1121 fd, (unsigned long) buffer, readp->r_nbytes);
1122 cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
1123 fd, readp->r_file, readp->r_oflags);
1124 cp += sprintf(cp, " read done at file offset %d\n",
1129 cp += sprintf(cp, "syscall: write(%d, %#lo, %d)\n",
1130 fd, (unsigned long) buffer, writep->r_nbytes);
1131 cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
1132 fd, writep->r_file, writep->r_oflags);
1133 cp += sprintf(cp, " write done at file offset %d - pattern is %s\n",
1134 writep->r_offset, pattern);
1138 aio_strat = format_strat(readap->r_aio_strat);
1140 cp += sprintf(cp, "syscall: reada(%d, %#lo, %d, %#lo, %d)\n",
1141 fd, (unsigned long) buffer, readap->r_nbytes,
1142 (unsigned long) iosw, signo);
1143 cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
1144 fd, readap->r_file, readp->r_oflags);
1145 cp += sprintf(cp, " reada done at file offset %d\n",
1147 cp += sprintf(cp, " async io completion strategy is %s\n",
1152 aio_strat = format_strat(writeap->r_aio_strat);
1154 cp += sprintf(cp, "syscall: writea(%d, %#lo, %d, %#lo, %d)\n",
1155 fd, (unsigned long) buffer, writeap->r_nbytes,
1156 (unsigned long) iosw, signo);
1157 cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
1158 fd, writeap->r_file, writeap->r_oflags);
1159 cp += sprintf(cp, " writea done at file offset %d - pattern is %s\n",
1160 writeap->r_offset, pattern);
1161 cp += sprintf(cp, " async io completion strategy is %s\n",
1173 struct io_req *ioreq,
1180 static char *errbuf=NULL;
1183 struct ssread_req *ssreadp = &ioreq->r_data.ssread;
1184 struct sswrite_req *sswritep = &ioreq->r_data.sswrite;
1187 errbuf = (char *)malloc(32768);
1190 cp += sprintf(cp, "Request number %d\n", Reqno);
1193 switch (ioreq->r_type) {
1195 cp += sprintf(cp, "syscall: ssread(%#o, %#o, %d)\n",
1196 buffer, sds, ssreadp->r_nbytes);
1200 cp += sprintf(cp, "syscall: sswrite(%#o, %#o, %d) - pattern was %s\n",
1201 buffer, sds, sswritep->r_nbytes, pattern);
1209 * Perform the various sorts of disk reads
1216 int fd, offset, nbytes, oflags, rval;
1219 struct aio_info *aiop;
1220 int aio_id, aio_strat, signo;
1223 struct fd_cache *fdc;
1227 * Initialize common fields - assumes r_oflags, r_file, r_offset, and
1228 * r_nbytes are at the same offset in the read_req and reada_req
1232 file = req->r_data.read.r_file;
1233 oflags = req->r_data.read.r_oflags;
1234 offset = req->r_data.read.r_offset;
1235 nbytes = req->r_data.read.r_nbytes;
1237 /*printf("read: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
1240 * Grab an open file descriptor
1241 * Note: must be done before memory allocation so that the direct i/o
1242 * information is available in mem. allocate
1245 if ((fd = alloc_fd(file, oflags)) == -1)
1249 * Allocate core or sds - based on the O_SSD flag
1253 #define wtob(x) (x * sizeof(UINT64_T))
1257 if (oflags & O_SSD) {
1258 if (alloc_sds(nbytes) == -1)
1261 addr = (char *)Sdsptr;
1263 if ((rval = alloc_mem(nbytes + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
1270 * if io is not raw, bump the offset by a random amount
1271 * to generate non-word-aligned io.
1273 if (! (req->r_data.read.r_uflags & F_WORD_ALIGNED)) {
1274 addr += random_range(0, wtob(1) - 1, 1, NULL);
1279 /* get memory alignment for using DIRECT I/O */
1280 fdc = alloc_fdcache(file, oflags);
1282 if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
1289 if( (req->r_data.read.r_uflags & F_WORD_ALIGNED) ) {
1291 * Force memory alignment for Direct I/O
1293 if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
1294 addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
1297 addr += random_range(0, wtob(1) - 1, 1, NULL);
1300 if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
1305 #endif /* !CRAY && sgi */
1309 switch (req->r_type) {
1311 /* move to the desired file position. */
1312 if (lseek(fd, offset, SEEK_SET) == -1) {
1313 doio_fprintf(stderr,
1314 "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
1315 fd, offset, SYSERR, errno);
1319 if ((rval = read(fd, addr, nbytes)) == -1) {
1320 doio_fprintf(stderr,
1321 "read() request failed: %s (%d)\n%s\n",
1323 format_rw(req, fd, addr, -1, NULL, NULL));
1324 doio_upanic(U_RVAL);
1326 } else if (rval != nbytes) {
1327 doio_fprintf(stderr,
1328 "read() request returned wrong # of bytes - expected %d, got %d\n%s\n",
1330 format_rw(req, fd, addr, -1, NULL, NULL));
1331 doio_upanic(U_RVAL);
1342 /* move to the desired file position. */
1343 if (lseek(fd, offset, SEEK_SET) == -1) {
1344 doio_fprintf(stderr,
1345 "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
1346 fd, offset, SYSERR, errno);
1350 aio_strat = req->r_data.read.r_aio_strat;
1351 signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
1353 aio_id = aio_register(fd, aio_strat, signo);
1354 aiop = aio_slot(aio_id);
1356 if (reada(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
1357 doio_fprintf(stderr, "reada() failed: %s (%d)\n%s\n",
1359 format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
1360 aio_unregister(aio_id);
1361 doio_upanic(U_RVAL);
1365 * Wait for io to complete
1371 * make sure the io completed without error
1374 if (aiop->iosw.sw_count != nbytes) {
1375 doio_fprintf(stderr,
1376 "Bad iosw from reada()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
1379 aiop->iosw.sw_error,
1380 aiop->iosw.sw_count,
1381 format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
1382 aio_unregister(aio_id);
1383 doio_upanic(U_IOSW);
1386 aio_unregister(aio_id);
1397 return 0; /* if we get here, everything went ok */
1401 * Perform the verious types of disk writes.
1408 static int pid = -1;
1409 int fd, nbytes, oflags;
1412 int logged_write, rval, got_lock;
1413 long offset, woffset = 0;
1414 char *addr, pattern, *file, *msg;
1415 struct wlog_rec wrec;
1417 int aio_strat, aio_id;
1418 struct aio_info *aiop;
1421 struct fd_cache *fdc;
1425 * Misc variable setup
1429 nbytes = req->r_data.write.r_nbytes;
1430 offset = req->r_data.write.r_offset;
1431 pattern = req->r_data.write.r_pattern;
1432 file = req->r_data.write.r_file;
1433 oflags = req->r_data.write.r_oflags;
1435 /*printf("pwrite: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
1438 * Allocate core memory and possibly sds space. Initialize the data
1442 Pattern[0] = pattern;
1446 * Get a descriptor to do the io on
1449 if ((fd = alloc_fd(file, oflags)) == -1)
1452 /*printf("write: %d, %s, %#o, %d %d\n",
1453 fd, file, oflags, offset, nbytes);*/
1456 * Allocate SDS space for backdoor write if desired
1460 if (oflags & O_SSD) {
1462 if ((rval = alloc_mem(nbytes + wtob(1))) < 0) {
1466 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1467 /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
1469 if (alloc_sds(nbytes) == -1)
1472 if (sswrite((long)Memptr, Sdsptr, btoc(nbytes)) == -1) {
1473 doio_fprintf(stderr, "sswrite(%d, %d, %d) failed: %s (%d)\n",
1474 (long)Memptr, Sdsptr, btoc(nbytes),
1480 addr = (char *)Sdsptr;
1482 doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
1485 #endif /* !CRAYMPP */
1487 if ((rval = alloc_mem(nbytes + wtob(1)) < 0)) {
1494 * if io is not raw, bump the offset by a random amount
1495 * to generate non-word-aligned io.
1498 if (! (req->r_data.write.r_uflags & F_WORD_ALIGNED)) {
1499 addr += random_range(0, wtob(1) - 1, 1, NULL);
1502 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1503 if( addr != Memptr )
1504 memmove( addr, Memptr, nbytes);
1508 /* get memory alignment for using DIRECT I/O */
1509 fdc = alloc_fdcache(file, oflags);
1511 if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
1517 if( (req->r_data.write.r_uflags & F_WORD_ALIGNED) ) {
1519 * Force memory alignment for Direct I/O
1521 if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
1522 addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
1525 addr += random_range(0, wtob(1) - 1, 1, NULL);
1528 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1529 if( addr != Memptr )
1530 memmove( addr, Memptr, nbytes);
1533 if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
1539 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1540 if( addr != Memptr )
1541 memmove( addr, Memptr, nbytes);
1550 if (lock_file_region(file, fd, F_WRLCK, offset, nbytes) < 0) {
1559 * Write a preliminary write-log entry. This is done so that
1560 * doio_check can do corruption detection across an interrupt/crash.
1561 * Note that w_done is set to 0. If doio_check sees this, it
1562 * re-creates the file extents as if the write completed, but does not
1563 * do any checking - see comments in doio_check for more details.
1570 wrec.w_async = (req->r_type == WRITEA) ? 1 : 0;
1571 wrec.w_oflags = oflags;
1573 wrec.w_offset = offset;
1574 wrec.w_nbytes = nbytes;
1576 wrec.w_pathlen = strlen(file);
1577 memcpy(wrec.w_path, file, wrec.w_pathlen);
1578 wrec.w_hostlen = strlen(Host);
1579 memcpy(wrec.w_host, Host, wrec.w_hostlen);
1580 wrec.w_patternlen = Pattern_Length;
1581 memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
1585 if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
1586 doio_fprintf(stderr,
1587 "Could not append to write-log: %s (%d)\n",
1594 switch (req->r_type ) {
1600 if (lseek(fd, offset, SEEK_SET) == -1) {
1601 doio_fprintf(stderr,
1602 "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
1603 fd, offset, SYSERR, errno);
1607 rval = write(fd, addr, nbytes);
1610 doio_fprintf(stderr,
1611 "write() failed: %s (%d)\n%s\n",
1613 format_rw(req, fd, addr, -1, Pattern, NULL));
1615 doio_fprintf(stderr,
1616 "write() failed: %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%miniou(%d)=%d, oflags=%#o memalign=%d, addr%%memalign=%d\n",
1620 fdc->c_miniosz, nbytes%fdc->c_miniosz,
1621 oflags, fdc->c_memalign, (long)addr%fdc->c_memalign);
1623 doio_fprintf(stderr,
1624 "write() failed: %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%1B=%d, oflags=%#o\n",
1627 offset, nbytes%4096, oflags);
1629 doio_upanic(U_RVAL);
1630 } else if (rval != nbytes) {
1631 doio_fprintf(stderr,
1632 "write() returned wrong # bytes - expected %d, got %d\n%s\n",
1634 format_rw(req, fd, addr, -1, Pattern, NULL));
1635 doio_upanic(U_RVAL);
1646 if (lseek(fd, offset, SEEK_SET) == -1) {
1647 doio_fprintf(stderr,
1648 "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
1649 fd, offset, SYSERR, errno);
1653 aio_strat = req->r_data.write.r_aio_strat;
1654 signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
1656 aio_id = aio_register(fd, aio_strat, signo);
1657 aiop = aio_slot(aio_id);
1660 * init iosw and do the async write
1663 if (writea(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
1664 doio_fprintf(stderr,
1665 "writea() failed: %s (%d)\n%s\n",
1667 format_rw(req, fd, addr, -1, Pattern, NULL));
1668 doio_upanic(U_RVAL);
1669 aio_unregister(aio_id);
1674 * Wait for io to complete
1680 * check that iosw is ok
1683 if (aiop->iosw.sw_count != nbytes) {
1684 doio_fprintf(stderr,
1685 "Bad iosw from writea()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
1688 aiop->iosw.sw_error,
1689 aiop->iosw.sw_count,
1690 format_rw(req, fd, addr, -1, Pattern, &aiop->iosw));
1691 aio_unregister(aio_id);
1692 doio_upanic(U_IOSW);
1695 aio_unregister(aio_id);
1705 * Verify that the data was written correctly - check_file() returns
1706 * a non-null pointer which contains an error message if there are
1711 msg = check_file(file, offset, nbytes, Pattern, Pattern_Length,
1712 0, oflags & O_PARALLEL);
1714 doio_fprintf(stderr, "%s%s\n",
1717 format_rw(req, fd, addr, -1, Pattern, &aiop->iosw)
1719 format_rw(req, fd, addr, -1, Pattern, NULL)
1722 doio_upanic(U_CORRUPTION);
1729 * General cleanup ...
1731 * Write extent information to the write-log, so that doio_check can do
1732 * corruption detection. Note that w_done is set to 1, indicating that
1733 * the write has been verified as complete. We don't need to write the
1734 * filename on the second logging.
1737 if (w_opt && logged_write) {
1739 wlog_record_write(&Wlog, &wrec, woffset);
1743 * Unlock file region if necessary
1747 if (lock_file_region(file, fd, F_UNLCK, offset, nbytes) < 0) {
1753 return( (rval == -1) ? -1 : 0);
1758 * Simple routine to lock/unlock a file using fcntl()
1762 lock_file_region(fname, fd, type, start, nbytes)
1773 flk.l_start = start;
1776 if (fcntl(fd, F_SETLKW, &flk) < 0) {
1777 doio_fprintf(stderr,
1778 "fcntl(%d, %d, %#o) failed for file %s, lock type %d, offset %d, length %d: %s (%d), open flags: %#o\n",
1779 fd, F_SETLKW, &flk, fname, type,
1780 start, nbytes, SYSERR, errno,
1781 fcntl(fd, F_GETFL, 0));
1789 * Perform a listio request.
1795 struct io_req *ioreq,
1797 struct listreq *list,
1803 static char *errbuf=NULL;
1804 struct listio_req *liop = &ioreq->r_data.listio;
1805 struct listreq *listreq;
1806 char *cp, *cmd, *opcode, *aio_strat;
1810 case LC_START: cmd = "LC_START"; break;
1811 case LC_WAIT: cmd = "LC_WAIT"; break;
1812 default: cmd = "???"; break;
1816 errbuf = (char *)malloc(32768);
1819 cp += sprintf(cp, "Request number %d\n", Reqno);
1821 cp += sprintf(cp, "syscall: listio(%s, %#o, %d)\n\n",
1824 aio_strat = format_strat(liop->r_aio_strat);
1826 for (i = 0; i < nent; i++) {
1827 cp += sprintf(cp, "struct lioreq for request element %d\n", i);
1828 cp += sprintf(cp, "----------------------------------------\n");
1832 switch (listreq->li_opcode) {
1833 case LO_READ: opcode = "LO_READ"; break;
1834 case LO_WRITE: opcode = "LO_WRITE"; break;
1835 default: opcode = "???"; break;
1838 cp += sprintf(cp, " li_opcode = %s\n", opcode);
1839 cp += sprintf(cp, " li_drvr = %#o\n", listreq->li_drvr);
1840 cp += sprintf(cp, " li_flags = %#o\n", listreq->li_flags);
1841 cp += sprintf(cp, " li_offset = %d\n", listreq->li_offset);
1842 cp += sprintf(cp, " li_fildes = %d\n", listreq->li_fildes);
1843 cp += sprintf(cp, " li_buf = %#o\n", listreq->li_buf);
1844 cp += sprintf(cp, " li_nbyte = %d\n", listreq->li_nbyte);
1845 cp += sprintf(cp, " li_status = %#o (%d, %d, %d)\n", listreq->li_status, listreq->li_status->sw_flag, listreq->li_status->sw_error, listreq->li_status->sw_count);
1846 cp += sprintf(cp, " li_signo = %d\n", listreq->li_signo);
1847 cp += sprintf(cp, " li_nstride = %d\n", listreq->li_nstride);
1848 cp += sprintf(cp, " li_filstride = %d\n", listreq->li_filstride);
1849 cp += sprintf(cp, " li_memstride = %d\n", listreq->li_memstride);
1850 cp += sprintf(cp, " io completion strategy is %s\n", aio_strat);
1861 struct listio_req *lio;
1862 int fd, oflags, signo, nb, i;
1863 int logged_write, rval, got_lock;
1864 int aio_strat, aio_id;
1865 int min_byte, max_byte;
1867 int foffset, fstride, mstride, nstrides;
1869 long offset, woffset;
1871 sigset_t block_mask, omask;
1872 struct wlog_rec wrec;
1873 struct aio_info *aiop;
1874 struct listreq lio_req;
1876 lio = &req->r_data.listio;
1879 * If bytes per stride is less than the stride size, drop the request
1880 * since it will cause overlapping strides, and we cannot predict
1881 * the order they will complete in.
1884 if (lio->r_filestride && abs(lio->r_filestride) < lio->r_nbytes) {
1885 doio_fprintf(stderr, "do_listio(): Bogus listio request - abs(filestride) [%d] < nbytes [%d]\n",
1886 abs(lio->r_filestride), lio->r_nbytes);
1891 * Allocate core memory. Initialize the data to be written. Make
1892 * sure we get enough, based on the memstride.
1896 stride_bounds(0, lio->r_memstride, lio->r_nstrides,
1897 lio->r_nbytes, NULL, NULL);
1899 if ((rval = alloc_mem(mem_needed + wtob(1))) < 0) {
1904 * Set the memory address pointer. If the io is not raw, adjust
1905 * addr by a random amount, so that non-raw io is not necessarily
1911 if (! (lio->r_uflags & F_WORD_ALIGNED)) {
1912 addr += random_range(0, wtob(1) - 1, 1, NULL);
1915 if (lio->r_opcode == LO_WRITE) {
1916 Pattern[0] = lio->r_pattern;
1917 (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
1918 if( addr != Memptr )
1919 memmove( addr, Memptr, mem_needed);
1923 * Get a descriptor to do the io on. No need to do an lseek, as this
1924 * is encoded in the listio request.
1927 if ((fd = alloc_fd(lio->r_file, lio->r_oflags)) == -1) {
1936 * If the opcode is LO_WRITE, lock all regions of the file that
1937 * are touched by this listio request. Currently, we use
1938 * stride_bounds() to figure out the min and max bytes affected, and
1939 * lock the entire region, regardless of the file stride.
1942 if (lio->r_opcode == LO_WRITE && k_opt) {
1943 stride_bounds(lio->r_offset,
1944 lio->r_filestride, lio->r_nstrides,
1945 lio->r_nbytes, &min_byte, &max_byte);
1947 if (lock_file_region(lio->r_file, fd, F_WRLCK,
1948 min_byte, (max_byte-min_byte+1)) < 0) {
1949 doio_fprintf(stderr, "stride_bounds(%d, %d, %d, %d, ..., ...) set min_byte to %d, max_byte to %d\n",
1950 lio->r_offset, lio->r_filestride,
1951 lio->r_nstrides, lio->r_nbytes, min_byte,
1963 aio_strat = lio->r_aio_strat;
1964 signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
1966 aio_id = aio_register(fd, aio_strat, signo);
1967 aiop = aio_slot(aio_id);
1970 * Form the listio request, and make the call.
1973 lio_req.li_opcode = lio->r_opcode;
1974 lio_req.li_drvr = 0;
1975 lio_req.li_flags = LF_LSEEK;
1976 lio_req.li_offset = lio->r_offset;
1977 lio_req.li_fildes = fd;
1979 if (lio->r_memstride >= 0 || lio->r_nstrides <= 1) {
1980 lio_req.li_buf = addr;
1982 lio_req.li_buf = addr + mem_needed - lio->r_nbytes;
1985 lio_req.li_nbyte = lio->r_nbytes;
1986 lio_req.li_status = &aiop->iosw;
1987 lio_req.li_signo = signo;
1988 lio_req.li_nstride = lio->r_nstrides;
1989 lio_req.li_filstride = lio->r_filestride;
1990 lio_req.li_memstride = lio->r_memstride;
1993 * If signo != 0, block signo while we're in the system call, so that
1994 * we don't get interrupted syscall failures.
1998 sigemptyset(&block_mask);
1999 sigaddset(&block_mask, signo);
2000 sigprocmask(SIG_BLOCK, &block_mask, &omask);
2003 if (listio(lio->r_cmd, &lio_req, 1) < 0) {
2004 doio_fprintf(stderr,
2005 "listio() failed: %s (%d)\n%s\n",
2007 format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
2008 aio_unregister(aio_id);
2009 doio_upanic(U_RVAL);
2014 sigprocmask(SIG_SETMASK, &omask, NULL);
2018 * Wait for io to complete
2023 nstrides = lio->r_nstrides ? lio->r_nstrides : 1;
2024 if (aiop->iosw.sw_count != lio->r_nbytes * nstrides) {
2025 doio_fprintf(stderr,
2026 "Bad iosw from listio()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
2027 1, 0, lio->r_nbytes * lio->r_nstrides,
2029 aiop->iosw.sw_error, aiop->iosw.sw_count,
2030 format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
2031 aio_unregister(aio_id);
2032 doio_upanic(U_IOSW);
2036 aio_unregister(aio_id);
2039 * Verify that the data was written correctly - check_file() returns
2040 * a non-null pointer which contains an error message if there are
2043 * For listio, we basically have to make 1 call to check_file for each
2047 if (v_opt && lio_req.li_opcode == LO_WRITE) {
2048 fstride = lio->r_filestride ? lio->r_filestride : lio->r_nbytes;
2049 mstride = lio->r_memstride ? lio->r_memstride : lio->r_nbytes;
2050 foffset = lio->r_offset;
2052 if (mstride> 0 || lio->r_nstrides <= 1) {
2055 moffset = addr + mem_needed - lio->r_nbytes;
2058 for (i = 0; i < lio_req.li_nstride; i++) {
2059 msg = check_file(lio->r_file,
2060 foffset, lio->r_nbytes,
2061 Pattern, Pattern_Length,
2063 lio->r_oflags & O_PARALLEL);
2066 doio_fprintf(stderr, "%s\n%s\n",
2068 format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
2069 doio_upanic(U_CORRUPTION);
2084 * General cleanup ...
2089 * Release file locks if necessary
2093 if (lock_file_region(lio->r_file, fd, F_UNLCK,
2094 min_byte, (max_byte-min_byte+1)) < 0) {
2106 * perform ssread/sswrite operations
2118 nbytes = req->r_data.ssread.r_nbytes;
2121 * Grab core and sds space
2124 if ((nb = alloc_mem(nbytes)) < 0)
2127 if (alloc_sds(nbytes) == -1)
2130 if (req->r_type == SSWRITE) {
2133 * Init data and ship it to the ssd
2136 Pattern[0] = req->r_data.sswrite.r_pattern;
2137 /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
2138 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
2140 if (sswrite((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
2141 doio_fprintf(stderr, "sswrite() failed: %s (%d)\n%s\n",
2143 format_sds(req, Memptr, Sdsptr, Pattern));
2144 doio_upanic(U_RVAL);
2152 if (ssread((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
2153 doio_fprintf(stderr, "ssread() failed: %s (%d)\n%s\n",
2155 format_sds(req, Memptr, Sdsptr, Pattern));
2157 doio_upanic(U_RVAL);
2163 * Verify data if SSWRITE and v_opt
2166 if (v_opt && req->r_type == SSWRITE) {
2167 ssread((long)Memptr, (long)Sdsptr, btoc(nbytes));
2169 if (pattern_check(Memptr, nbytes, Pattern, Pattern_Length, 0) == -1) {
2170 doio_fprintf(stderr,
2171 "sds DATA COMPARE ERROR - ABORTING\n%s\n",
2172 format_sds(req, Memptr, Sdsptr, Pattern));
2174 doio_upanic(U_CORRUPTION);
2188 doio_fprintf(stderr,
2189 "Internal Error - do_ssdio() called on a non-cray1 system\n");
2199 /* ---------------------------------------------------------------------------
2201 * A new paradigm of doing the r/w system call where there is a "stub"
2202 * function that builds the info for the system call, then does the system
2203 * call; this is called by code that is common to all system calls and does
2204 * the syscall return checking, async I/O wait, iosw check, etc.
2207 * WRITE, ASYNC, SSD/SDS,
2208 * FILE_LOCK, WRITE_LOG, VERIFY_DATA,
2212 int rval; /* syscall return */
2213 int err; /* errno */
2214 int *aioid; /* list of async I/O structures */
2217 struct syscall_info {
2220 struct status *(*sy_syscall)();
2222 char *(*sy_format)();
2227 #define SY_WRITE 00001
2228 #define SY_ASYNC 00010
2229 #define SY_IOSW 00020
2230 #define SY_SDS 00100
2233 fmt_ioreq(struct io_req *ioreq, struct syscall_info *sy, int fd)
2235 static char *errbuf=NULL;
2244 errbuf = (char *)malloc(32768);
2246 io = &ioreq->r_data.io;
2249 * Look up async I/O completion strategy
2252 aname->value != -1 && aname->value != io->r_aio_strat;
2257 cp += sprintf(cp, "Request number %d\n", Reqno);
2259 cp += sprintf(cp, " fd %d is file %s - open flags are %#o %s\n",
2260 fd, io->r_file, io->r_oflags, format_oflags(io->r_oflags));
2262 if(sy->sy_flags & SY_WRITE) {
2263 cp += sprintf(cp, " write done at file offset %d - pattern is %c (%#o)\n",
2265 (io->r_pattern == '\0') ? '?' : io->r_pattern,
2268 cp += sprintf(cp, " read done at file offset %d\n",
2272 if(sy->sy_flags & SY_ASYNC) {
2273 cp += sprintf(cp, " async io completion strategy is %s\n",
2277 cp += sprintf(cp, " number of requests is %d, strides per request is %d\n",
2278 io->r_nent, io->r_nstrides);
2280 cp += sprintf(cp, " i/o byte count = %d\n",
2283 cp += sprintf(cp, " memory alignment is %s\n",
2284 (io->r_uflags & F_WORD_ALIGNED) ? "aligned" : "unaligned");
2287 if(io->r_oflags & O_RAW) {
2288 cp += sprintf(cp, " RAW I/O: offset %% 4096 = %d length %% 4096 = %d\n",
2289 io->r_offset % 4096, io->r_nbytes % 4096);
2291 cp += sprintf(cp, " optimal file xfer size: small: %d large: %d\n",
2292 sbuf.st_blksize, sbuf.st_oblksize);
2293 cp += sprintf(cp, " cblks %d cbits %#o\n",
2294 sbuf.st_cblks, sbuf.st_cbits);
2298 if(io->r_oflags & O_DIRECT) {
2299 struct dioattr finfo;
2301 if(xfsctl(io->r_file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
2302 cp += sprintf(cp, " Error %s (%d) getting direct I/O info\n",
2303 strerror(errno), errno);
2305 finfo.d_miniosz = 1;
2306 finfo.d_maxiosz = 1;
2309 cp += sprintf(cp, " DIRECT I/O: offset %% %d = %d length %% %d = %d\n",
2311 io->r_offset % finfo.d_miniosz,
2313 io->r_nbytes % finfo.d_miniosz);
2314 cp += sprintf(cp, " mem alignment 0x%x xfer size: small: %d large: %d\n",
2315 finfo.d_mem, finfo.d_miniosz, finfo.d_maxiosz);
2323 * Issue listio requests
2327 sy_listio(req, sysc, fd, addr)
2329 struct syscall_info *sysc;
2333 int offset, nbytes, nstrides, nents, aio_strat;
2334 int aio_id, signo, o, i, lc;
2336 struct listreq *lio_req, *l;
2337 struct aio_info *aiop;
2338 struct status *status;
2341 * Initialize common fields - assumes r_oflags, r_file, r_offset, and
2342 * r_nbytes are at the same offset in the read_req and reada_req
2345 offset = req->r_data.io.r_offset;
2346 nbytes = req->r_data.io.r_nbytes;
2347 nstrides = req->r_data.io.r_nstrides;
2348 nents = req->r_data.io.r_nent;
2349 aio_strat = req->r_data.io.r_aio_strat;
2351 lc = (sysc->sy_flags & SY_ASYNC) ? LC_START : LC_WAIT;
2353 status = (struct status *)malloc(sizeof(struct status));
2354 if( status == NULL ){
2355 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2356 __FILE__, __LINE__);
2359 status->aioid = (int *)malloc( (nents+1) * sizeof(int) );
2360 if( status->aioid == NULL ){
2361 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2362 __FILE__, __LINE__);
2366 signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
2368 lio_req = (struct listreq *)malloc(nents * sizeof(struct listreq));
2369 if( lio_req == NULL ){
2370 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2371 __FILE__, __LINE__);
2374 for(l=lio_req,a=addr,o=offset,i=0;
2376 l++, a+=nbytes, o+=nbytes, i++) {
2378 aio_id = aio_register(fd, aio_strat, signo);
2379 aiop = aio_slot(aio_id);
2380 status->aioid[i] = aio_id;
2382 l->li_opcode = (sysc->sy_flags & SY_WRITE) ? LO_WRITE : LO_READ;
2386 l->li_nbyte = nbytes;
2387 l->li_status = &aiop->iosw;
2388 l->li_signo = signo;
2389 l->li_nstride = nstrides;
2390 l->li_filstride = 0;
2391 l->li_memstride = 0;
2393 l->li_flags = LF_LSEEK;
2396 status->aioid[nents] = -1; /* end sentinel */
2398 if( (status->rval = listio(lc, lio_req, nents)) == -1) {
2399 status->err = errno;
2407 * Calculate the size of a request in bytes and min/max boundaries
2409 * This assumes filestride & memstride = 0.
2412 listio_mem(struct io_req *req, int offset, int fmstride,
2417 size = stride_bounds(offset, fmstride,
2418 req->r_data.io.r_nstrides*req->r_data.io.r_nent,
2419 req->r_data.io.r_nbytes, min, max);
2424 fmt_listio(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2426 static char *errbuf = NULL;
2432 errbuf = (char *)malloc(32768);
2433 if( errbuf == NULL ){
2434 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2435 __FILE__, __LINE__);
2440 c = (sy->sy_flags & SY_ASYNC) ? "lc_wait" : "lc_start";
2443 cp += sprintf(cp, "syscall: listio(%s, (?), %d)\n",
2444 c, req->r_data.io.r_nent);
2446 cp += sprintf(cp, " data buffer at %#o\n", addr);
2453 sy_pread(req, sysc, fd, addr)
2455 struct syscall_info *sysc;
2460 struct status *status;
2462 rc = pread(fd, addr, req->r_data.io.r_nbytes,
2463 req->r_data.io.r_offset);
2465 status = (struct status *)malloc(sizeof(struct status));
2466 if( status == NULL ){
2467 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2468 __FILE__, __LINE__);
2471 status->aioid = NULL;
2473 status->err = errno;
2479 sy_pwrite(req, sysc, fd, addr)
2481 struct syscall_info *sysc;
2486 struct status *status;
2488 rc = pwrite(fd, addr, req->r_data.io.r_nbytes,
2489 req->r_data.io.r_offset);
2491 status = (struct status *)malloc(sizeof(struct status));
2492 if( status == NULL ){
2493 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2494 __FILE__, __LINE__);
2497 status->aioid = NULL;
2499 status->err = errno;
2505 fmt_pread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2507 static char *errbuf = NULL;
2511 errbuf = (char *)malloc(32768);
2512 if( errbuf == NULL ){
2513 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2514 __FILE__, __LINE__);
2520 cp += sprintf(cp, "syscall: %s(%d, 0x%p, %d)\n",
2521 sy->sy_name, fd, addr, req->r_data.io.r_nbytes);
2527 sy_readv(req, sysc, fd, addr)
2529 struct syscall_info *sysc;
2533 struct status *sy_rwv();
2534 return sy_rwv(req, sysc, fd, addr, 0);
2538 sy_writev(req, sysc, fd, addr)
2540 struct syscall_info *sysc;
2544 struct status *sy_rwv();
2545 return sy_rwv(req, sysc, fd, addr, 1);
2549 sy_rwv(req, sysc, fd, addr, rw)
2551 struct syscall_info *sysc;
2557 struct status *status;
2558 struct iovec iov[2];
2560 status = (struct status *)malloc(sizeof(struct status));
2561 if( status == NULL ){
2562 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2563 __FILE__, __LINE__);
2566 status->aioid = NULL;
2568 /* move to the desired file position. */
2569 if ((rc=lseek(fd, req->r_data.io.r_offset, SEEK_SET)) == -1) {
2571 status->err = errno;
2575 iov[0].iov_base = addr;
2576 iov[0].iov_len = req->r_data.io.r_nbytes;
2579 rc = writev(fd, iov, 1);
2581 rc = readv(fd, iov, 1);
2582 status->aioid = NULL;
2584 status->err = errno;
2589 fmt_readv(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2591 static char errbuf[32768];
2595 cp += sprintf(cp, "syscall: %s(%d, (iov on stack), 1)\n",
2603 sy_aread(req, sysc, fd, addr)
2605 struct syscall_info *sysc;
2609 struct status *sy_arw();
2610 return sy_arw(req, sysc, fd, addr, 0);
2614 sy_awrite(req, sysc, fd, addr)
2616 struct syscall_info *sysc;
2620 struct status *sy_arw();
2621 return sy_arw(req, sysc, fd, addr, 1);
2625 #define sy_aread(A, B, C, D) sy_arw(A, B, C, D, 0)
2626 #define sy_awrite(A, B, C, D) sy_arw(A, B, C, D, 1)
2630 sy_arw(req, sysc, fd, addr, rw)
2632 struct syscall_info *sysc;
2637 /* POSIX 1003.1b-1993 Async read */
2638 struct status *status;
2640 int aio_id, aio_strat, signo;
2641 struct aio_info *aiop;
2643 status = (struct status *)malloc(sizeof(struct status));
2644 if( status == NULL ){
2645 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2646 __FILE__, __LINE__);
2649 aio_strat = req->r_data.io.r_aio_strat;
2650 signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
2652 aio_id = aio_register(fd, aio_strat, signo);
2653 aiop = aio_slot(aio_id);
2655 memset( (void *)&aiop->aiocb, 0, sizeof(aiocb_t));
2657 aiop->aiocb.aio_fildes = fd;
2658 aiop->aiocb.aio_nbytes = req->r_data.io.r_nbytes;
2659 aiop->aiocb.aio_offset = req->r_data.io.r_offset;
2660 aiop->aiocb.aio_buf = addr;
2661 aiop->aiocb.aio_reqprio = 0; /* must be 0 */
2662 aiop->aiocb.aio_lio_opcode = 0;
2664 if(aio_strat == A_SIGNAL) { /* siginfo(2) stuff */
2665 aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
2666 aiop->aiocb.aio_sigevent.sigev_signo = signo;
2667 } else if(aio_strat == A_CALLBACK) {
2668 aiop->aiocb.aio_sigevent.sigev_signo = 0;
2669 aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
2670 aiop->aiocb.aio_sigevent.sigev_func = cb_handler;
2671 aiop->aiocb.aio_sigevent.sigev_value.sival_int = aio_id;
2673 aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_NONE;
2674 aiop->aiocb.aio_sigevent.sigev_signo = 0;
2678 rc = aio_write(&aiop->aiocb);
2680 rc = aio_read(&aiop->aiocb);
2682 status->aioid = (int *)malloc( 2 * sizeof(int) );
2683 if( status->aioid == NULL ){
2684 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2685 __FILE__, __LINE__);
2688 status->aioid[0] = aio_id;
2689 status->aioid[1] = -1;
2691 status->err = errno;
2696 fmt_aread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2698 static char errbuf[32768];
2702 cp += sprintf(cp, "syscall: %s(&aiop->aiocb)\n",
2711 sy_mmread(req, sysc, fd, addr)
2713 struct syscall_info *sysc;
2717 struct status *sy_mmrw();
2718 return sy_mmrw(req, sysc, fd, addr, 0);
2722 sy_mmwrite(req, sysc, fd, addr)
2724 struct syscall_info *sysc;
2728 struct status *sy_mmrw();
2729 return sy_mmrw(req, sysc, fd, addr, 1);
2733 sy_mmrw(req, sysc, fd, addr, rw)
2735 struct syscall_info *sysc;
2742 * This version is oriented towards mmaping the file to memory
2743 * ONCE and keeping it mapped.
2745 struct status *status;
2746 void *mrc, *memaddr;
2747 struct fd_cache *fdc;
2750 status = (struct status *)malloc(sizeof(struct status));
2751 if( status == NULL ){
2752 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2753 __FILE__, __LINE__);
2756 status->aioid = NULL;
2759 fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
2761 if( fdc->c_memaddr == NULL ) {
2762 if( fstat(fd, &sbuf) < 0 ){
2763 doio_fprintf(stderr, "fstat failed, errno=%d\n",
2765 status->err = errno;
2769 fdc->c_memlen = (int)sbuf.st_size;
2770 mrc = mmap(NULL, (int)sbuf.st_size,
2771 rw ? PROT_WRITE|PROT_READ : PROT_READ,
2774 if( mrc == MAP_FAILED ) {
2775 doio_fprintf(stderr, "mmap() failed - 0x%lx %d\n",
2777 status->err = errno;
2781 fdc->c_memaddr = mrc;
2784 memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
2788 memcpy(memaddr, addr, req->r_data.io.r_nbytes);
2790 memcpy(addr, memaddr, req->r_data.io.r_nbytes);
2793 status->rval = req->r_data.io.r_nbytes;
2799 fmt_mmrw(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2801 static char errbuf[32768];
2803 struct fd_cache *fdc;
2806 fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
2809 cp += sprintf(cp, "syscall: %s(NULL, %d, %s, MAP_SHARED, %d, 0)\n",
2812 (sy->sy_flags & SY_WRITE) ? "PROT_WRITE" : "PROT_READ",
2815 cp += sprintf(cp, "\tfile is mmaped to: 0x%lx\n",
2816 (unsigned long) fdc->c_memaddr);
2818 memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
2820 cp += sprintf(cp, "\tfile-mem=0x%lx, length=%d, buffer=0x%lx\n",
2821 (unsigned long) memaddr, req->r_data.io.r_nbytes,
2822 (unsigned long) addr);
2828 struct syscall_info syscalls[] = {
2830 { "listio-read-sync", LREAD,
2831 sy_listio, NULL, fmt_listio,
2834 { "listio-read-strides-sync", LSREAD,
2835 sy_listio, listio_mem, fmt_listio,
2838 { "listio-read-reqs-sync", LEREAD,
2839 sy_listio, listio_mem, fmt_listio,
2842 { "listio-read-async", LREADA,
2843 sy_listio, NULL, fmt_listio,
2846 { "listio-read-strides-async", LSREADA,
2847 sy_listio, listio_mem, fmt_listio,
2850 { "listio-read-reqs-async", LEREADA,
2851 sy_listio, listio_mem, fmt_listio,
2854 { "listio-write-sync", LWRITE,
2855 sy_listio, listio_mem, fmt_listio,
2858 { "listio-write-strides-sync", LSWRITE,
2859 sy_listio, listio_mem, fmt_listio,
2862 { "listio-write-reqs-sync", LEWRITE,
2863 sy_listio, listio_mem, fmt_listio,
2866 { "listio-write-async", LWRITEA,
2867 sy_listio, listio_mem, fmt_listio,
2868 SY_IOSW | SY_WRITE | SY_ASYNC
2870 { "listio-write-strides-async", LSWRITEA,
2871 sy_listio, listio_mem, fmt_listio,
2872 SY_IOSW | SY_WRITE | SY_ASYNC
2874 { "listio-write-reqs-async", LEWRITEA,
2875 sy_listio, listio_mem, fmt_listio,
2876 SY_IOSW | SY_WRITE | SY_ASYNC
2882 sy_aread, NULL, fmt_aread,
2886 sy_awrite, NULL, fmt_aread,
2887 SY_IOSW | SY_WRITE | SY_ASYNC
2891 sy_pread, NULL, fmt_pread,
2895 sy_pwrite, NULL, fmt_pread,
2901 sy_readv, NULL, fmt_readv,
2905 sy_writev, NULL, fmt_readv,
2908 { "mmap-read", MMAPR,
2909 sy_mmread, NULL, fmt_mmrw,
2912 { "mmap-write", MMAPW,
2913 sy_mmwrite, NULL, fmt_mmrw,
2928 static int pid = -1;
2929 int fd, offset, nbytes, nstrides, nents, oflags;
2930 int rval, mem_needed, i;
2931 int logged_write, got_lock, woffset = 0, pattern;
2932 int min_byte, max_byte;
2933 char *addr, *file, *msg;
2935 struct wlog_rec wrec;
2936 struct syscall_info *sy;
2938 struct aio_info *aiop;
2945 struct fd_cache *fdc;
2949 * Initialize common fields - assumes r_oflags, r_file, r_offset, and
2950 * r_nbytes are at the same offset in the read_req and reada_req
2953 file = req->r_data.io.r_file;
2954 oflags = req->r_data.io.r_oflags;
2955 offset = req->r_data.io.r_offset;
2956 nbytes = req->r_data.io.r_nbytes;
2957 nstrides= req->r_data.io.r_nstrides;
2958 nents = req->r_data.io.r_nent;
2959 pattern = req->r_data.io.r_pattern;
2961 if( nents >= MAX_AIO ) {
2962 doio_fprintf(stderr, "do_rw: too many list requests, %d. Maximum is %d\n",
2968 * look up system call info
2970 for(sy=syscalls; sy->sy_name != NULL && sy->sy_type != req->r_type; sy++)
2973 if(sy->sy_name == NULL) {
2974 doio_fprintf(stderr, "do_rw: unknown r_type %d.\n",
2980 * Get an open file descriptor
2981 * Note: must be done before memory allocation so that the direct i/o
2982 * information is available in mem. allocate
2985 if ((fd = alloc_fd(file, oflags)) == -1)
2989 * Allocate core memory and possibly sds space. Initialize the
2990 * data to be written. Make sure we get enough, based on the
2994 * 1 extra word for possible partial-word address "bump"
2995 * 1 extra word for dynamic pattern overrun
2996 * MPP_BUMP extra words for T3E non-hw-aligned memory address.
2999 if( sy->sy_buffer != NULL ) {
3000 mem_needed = (*sy->sy_buffer)(req, 0, 0, NULL, NULL);
3002 mem_needed = nbytes;
3006 if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
3011 /* get memory alignment for using DIRECT I/O */
3012 fdc = alloc_fdcache(file, oflags);
3014 if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + fdc->c_memalign)) < 0) {
3018 if ((rval = alloc_mem(mem_needed + wtob(1) * 2)) < 0) {
3024 Pattern[0] = pattern;
3027 * Allocate SDS space for backdoor write if desired
3030 if (oflags & O_SSD) {
3033 if (alloc_sds(nbytes) == -1)
3036 if( sy->sy_flags & SY_WRITE ) {
3037 /*pattern_fill(Memptr, mem_needed, Pattern, Pattern_Length, 0);*/
3038 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
3040 if (sswrite((long)Memptr, Sdsptr, btoc(mem_needed)) == -1) {
3041 doio_fprintf(stderr, "sswrite(%d, %d, %d) failed: %s (%d)\n",
3042 (long)Memptr, Sdsptr,
3043 btoc(mem_needed), SYSERR, errno);
3049 addr = (char *)Sdsptr;
3051 doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
3054 #endif /* _CRAYMPP */
3056 doio_fprintf(stderr, "Invalid O_SSD flag was generated for non-Cray system\n");
3064 * if io is not raw, bump the offset by a random amount
3065 * to generate non-word-aligned io.
3067 * On MPP systems, raw I/O must start on an 0x80 byte boundary.
3068 * For non-aligned I/O, bump the address from 1 to 8 words.
3071 if (! (req->r_data.io.r_uflags & F_WORD_ALIGNED)) {
3073 addr += random_range(0, MPP_BUMP, 1, NULL) * sizeof(int);
3075 addr += random_range(0, wtob(1) - 1, 1, NULL);
3080 * Force memory alignment for Direct I/O
3082 if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
3083 addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
3088 * FILL must be done on a word-aligned buffer.
3089 * Call the fill function with Memptr which is aligned,
3090 * then memmove it to the right place.
3092 if (sy->sy_flags & SY_WRITE) {
3093 (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
3094 if( addr != Memptr )
3095 memmove( addr, Memptr, mem_needed);
3104 * Lock data if this is a write and locking option is set
3106 if (sy->sy_flags & SY_WRITE && k_opt) {
3107 if( sy->sy_buffer != NULL ) {
3108 (*sy->sy_buffer)(req, offset, 0, &min_byte, &max_byte);
3111 max_byte = offset + (nbytes * nstrides * nents);
3114 if (lock_file_region(file, fd, F_WRLCK,
3115 min_byte, (max_byte-min_byte+1)) < 0) {
3116 doio_fprintf(stderr,
3117 "file lock failed:\n%s\n",
3118 fmt_ioreq(req, sy, fd));
3119 doio_fprintf(stderr,
3120 " buffer(req, %d, 0, 0x%x, 0x%x)\n",
3121 offset, min_byte, max_byte);
3130 * Write a preliminary write-log entry. This is done so that
3131 * doio_check can do corruption detection across an interrupt/crash.
3132 * Note that w_done is set to 0. If doio_check sees this, it
3133 * re-creates the file extents as if the write completed, but does not
3134 * do any checking - see comments in doio_check for more details.
3137 if (sy->sy_flags & SY_WRITE && w_opt) {
3142 wrec.w_async = (sy->sy_flags & SY_ASYNC) ? 1 : 0;
3143 wrec.w_oflags = oflags;
3145 wrec.w_offset = offset;
3146 wrec.w_nbytes = nbytes; /* mem_needed -- total length */
3148 wrec.w_pathlen = strlen(file);
3149 memcpy(wrec.w_path, file, wrec.w_pathlen);
3150 wrec.w_hostlen = strlen(Host);
3151 memcpy(wrec.w_host, Host, wrec.w_hostlen);
3152 wrec.w_patternlen = Pattern_Length;
3153 memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
3157 if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
3158 doio_fprintf(stderr,
3159 "Could not append to write-log: %s (%d)\n",
3166 s = (*sy->sy_syscall)(req, sy, fd, addr);
3168 if( s->rval == -1 ) {
3169 doio_fprintf(stderr,
3170 "%s() request failed: %s (%d)\n%s\n%s\n",
3171 sy->sy_name, SYSERR, errno,
3172 fmt_ioreq(req, sy, fd),
3173 (*sy->sy_format)(req, sy, fd, addr));
3175 doio_upanic(U_RVAL);
3177 for(i=0; i < nents; i++) {
3178 if(s->aioid == NULL)
3180 aio_unregister(s->aioid[i]);
3185 * If the syscall was async, wait for I/O to complete
3188 if(sy->sy_flags & SY_ASYNC) {
3189 for(i=0; i < nents; i++) {
3190 aio_wait(s->aioid[i]);
3196 * Check the syscall how-much-data-written return. Look
3197 * for this in either the return value or the 'iosw'
3201 if( sy->sy_flags & SY_IOSW ) {
3203 for( i=0; i < nents; i++ ) {
3204 if(s->aioid == NULL)
3205 break; /* >>> error condition? */
3206 aiop = aio_slot(s->aioid[i]);
3208 if(iosw->sw_error != 0) {
3209 doio_fprintf(stderr,
3210 "%s() iosw error set: %s\n%s\n%s\n",
3212 strerror(iosw->sw_error),
3213 fmt_ioreq(req, sy, fd),
3214 (*sy->sy_format)(req, sy, fd, addr));
3215 doio_upanic(U_IOSW);
3217 } else if(iosw->sw_count != nbytes*nstrides) {
3218 doio_fprintf(stderr,
3219 "Bad iosw from %s() #%d\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n%s\n",
3221 1, 0, nbytes*nstrides,
3225 fmt_ioreq(req, sy, fd),
3226 (*sy->sy_format)(req, sy, fd, addr));
3227 doio_upanic(U_IOSW);
3231 aio_unregister(s->aioid[i]);
3235 for( i=0; s->aioid[i] != -1; i++ ) {
3236 if(s->aioid == NULL) {
3237 doio_fprintf(stderr,
3238 "aioid == NULL!\n");
3241 aiop = aio_slot(s->aioid[i]);
3244 * make sure the io completed without error
3246 if (aiop->aio_errno != 0) {
3247 doio_fprintf(stderr,
3248 "%s() aio error set: %s (%d)\n%s\n%s\n",
3250 strerror(aiop->aio_errno),
3252 fmt_ioreq(req, sy, fd),
3253 (*sy->sy_format)(req, sy, fd, addr));
3254 doio_upanic(U_IOSW);
3256 } else if (aiop->aio_ret != nbytes) {
3257 doio_fprintf(stderr,
3258 "Bad aio return from %s() #%d\nExpected (%d,%d), got (%d,%d)\n%s\n%s\n",
3263 fmt_ioreq(req, sy, fd),
3264 (*sy->sy_format)(req, sy, fd, addr));
3265 aio_unregister(s->aioid[i]);
3266 doio_upanic(U_IOSW);
3269 aio_unregister(s->aioid[i]);
3276 if(s->rval != mem_needed) {
3277 doio_fprintf(stderr,
3278 "%s() request returned wrong # of bytes - expected %d, got %d\n%s\n%s\n",
3279 sy->sy_name, nbytes, s->rval,
3280 fmt_ioreq(req, sy, fd),
3281 (*sy->sy_format)(req, sy, fd, addr));
3283 doio_upanic(U_RVAL);
3290 * Verify that the data was written correctly - check_file() returns
3291 * a non-null pointer which contains an error message if there are
3295 if ( rval == 0 && sy->sy_flags & SY_WRITE && v_opt) {
3296 msg = check_file(file, offset, nbytes*nstrides*nents,
3297 Pattern, Pattern_Length, 0,
3298 oflags & O_PARALLEL);
3300 doio_fprintf(stderr, "%s\n%s\n%s\n",
3302 fmt_ioreq(req, sy, fd),
3303 (*sy->sy_format)(req, sy, fd, addr));
3304 doio_upanic(U_CORRUPTION);
3310 * General cleanup ...
3312 * Write extent information to the write-log, so that doio_check can do
3313 * corruption detection. Note that w_done is set to 1, indicating that
3314 * the write has been verified as complete. We don't need to write the
3315 * filename on the second logging.
3318 if (w_opt && logged_write) {
3320 wlog_record_write(&Wlog, &wrec, woffset);
3324 * Unlock file region if necessary
3328 if (lock_file_region(file, fd, F_UNLCK,
3329 min_byte, (max_byte-min_byte+1)) < 0) {
3335 if(s->aioid != NULL)
3338 return (rval == -1) ? -1 : 0;
3343 * xfsctl-based requests
3345 * - XFS_IOC_UNRESVSP
3352 int fd, oflags, offset, nbytes;
3355 int min_byte = 0, max_byte = 0;
3356 char *file, *msg = NULL;
3357 struct xfs_flock64 flk;
3360 * Initialize common fields - assumes r_oflags, r_file, r_offset, and
3361 * r_nbytes are at the same offset in the read_req and reada_req
3364 file = req->r_data.io.r_file;
3365 oflags = req->r_data.io.r_oflags;
3366 offset = req->r_data.io.r_offset;
3367 nbytes = req->r_data.io.r_nbytes;
3370 flk.l_whence=SEEK_SET;
3375 * Get an open file descriptor
3378 if ((fd = alloc_fd(file, oflags)) == -1)
3385 * Lock data if this is locking option is set
3389 max_byte = offset + nbytes;
3391 if (lock_file_region(file, fd, F_WRLCK,
3392 min_byte, (nbytes+1)) < 0) {
3393 doio_fprintf(stderr,
3394 "file lock failed:\n");
3395 doio_fprintf(stderr,
3396 " buffer(req, %d, 0, 0x%x, 0x%x)\n",
3397 offset, min_byte, max_byte);
3405 switch (req->r_type) {
3406 case RESVSP: op=XFS_IOC_RESVSP; msg="resvsp"; break;
3407 case UNRESVSP: op=XFS_IOC_UNRESVSP; msg="unresvsp"; break;
3410 rval = xfsctl(file, fd, op, &flk);
3413 doio_fprintf(stderr,
3414 "xfsctl %s request failed: %s (%d)\n\txfsctl(%d, %s %d, {%d %lld ==> %lld}\n",
3416 fd, msg, op, flk.l_whence,
3417 (long long)flk.l_start,
3418 (long long)flk.l_len);
3420 doio_upanic(U_RVAL);
3425 * Unlock file region if necessary
3429 if (lock_file_region(file, fd, F_UNLCK,
3430 min_byte, (max_byte-min_byte+1)) < 0) {
3436 return (rval == -1) ? -1 : 0;
3441 * fsync(2) and fdatasync(2)
3453 * Initialize common fields - assumes r_oflags, r_file, r_offset, and
3454 * r_nbytes are at the same offset in the read_req and reada_req
3457 file = req->r_data.io.r_file;
3458 oflags = req->r_data.io.r_oflags;
3461 * Get an open file descriptor
3464 if ((fd = alloc_fd(file, oflags)) == -1)
3468 switch(req->r_type) {
3473 rval = fdatasync(fd);
3478 return (rval == -1) ? -1 : 0;
3484 doio_pat_fill(char *addr, int mem_needed, char *Pattern, int Pattern_Length,
3487 return pattern_fill(addr, mem_needed, Pattern, Pattern_Length, 0);
3491 doio_pat_check(buf, offset, length, pattern, pattern_length, patshift)
3499 static char errbuf[4096];
3500 int nb, i, pattern_index;
3501 char *cp, *bufend, *ep;
3502 char actual[33], expected[33];
3504 if (pattern_check(buf, length, pattern, pattern_length, patshift) != 0) {
3506 ep += sprintf(ep, "Corrupt regions follow - unprintable chars are represented as '.'\n");
3507 ep += sprintf(ep, "-----------------------------------------------------------------\n");
3509 pattern_index = patshift % pattern_length;;
3511 bufend = buf + length;
3513 while (cp < bufend) {
3514 if (*cp != pattern[pattern_index]) {
3516 if (nb > sizeof(expected)-1) {
3517 nb = sizeof(expected)-1;
3520 ep += sprintf(ep, "corrupt bytes starting at file offset %d\n", offset + (int)(cp-buf));
3523 * Fill in the expected and actual patterns
3525 bzero(expected, sizeof(expected));
3526 bzero(actual, sizeof(actual));
3528 for (i = 0; i < nb; i++) {
3529 expected[i] = pattern[(pattern_index + i) % pattern_length];
3530 if (! isprint((int)expected[i])) {
3535 if (! isprint((int)actual[i])) {
3540 ep += sprintf(ep, " 1st %2d expected bytes: %s\n", nb, expected);
3541 ep += sprintf(ep, " 1st %2d actual bytes: %s\n", nb, actual);
3548 if (pattern_index == pattern_length) {
3561 * Check the contents of a file beginning at offset, for length bytes. It
3562 * is assumed that there is a string of pattern bytes in this area of the
3563 * file. Use normal buffered reads to do the verification.
3565 * If there is a data mismatch, write a detailed message into a static buffer
3566 * suitable for the caller to print. Otherwise print NULL.
3568 * The fsa flag is set to non-zero if the buffer should be read back through
3569 * the FSA (unicos/mk). This implies the file will be opened
3570 * O_PARALLEL|O_RAW|O_WELLFORMED to do the validation. We must do this because
3571 * FSA will not allow the file to be opened for buffered io if it was
3572 * previously opened for O_PARALLEL io.
3576 check_file(file, offset, length, pattern, pattern_length, patshift, fsa)
3585 static char errbuf[4096];
3587 char *buf, *em, *ep;
3589 struct fd_cache *fdc;
3595 flags = Validation_Flags | O_RDONLY;
3600 flags |= O_PARALLEL | O_RAW | O_WELLFORMED;
3605 if ((fd = alloc_fd(file, flags)) == -1) {
3607 "Could not open file %s with flags %#o (%s) for data comparison: %s (%d)\n",
3608 file, flags, format_oflags(flags),
3613 if (lseek(fd, offset, SEEK_SET) == -1) {
3615 "Could not lseek to offset %d in %s for verification: %s (%d)\n",
3616 offset, file, SYSERR, errno);
3621 /* Guarantee a properly aligned address on Direct I/O */
3622 fdc = alloc_fdcache(file, flags);
3623 if( (flags & O_DIRECT) && ((long)buf % fdc->c_memalign != 0) ) {
3624 buf += fdc->c_memalign - ((long)buf % fdc->c_memalign);
3628 if ((nb = read(fd, buf, length)) == -1) {
3631 "Could not read %d bytes from %s for verification: %s (%d)\n\tread(%d, 0x%p, %d)\n\tbuf %% alignment(%d) = %ld\n",
3632 length, file, SYSERR, errno,
3634 fdc->c_memalign, (long)buf % fdc->c_memalign);
3637 "Could not read %d bytes from %s for verification: %s (%d)\n",
3638 length, file, SYSERR, errno);
3646 "Read wrong # bytes from %s. Expected %d, got %d\n",
3651 if( (em = (*Data_Check)(buf, offset, length, pattern, pattern_length, patshift)) != NULL ) {
3653 ep += sprintf(ep, "*** DATA COMPARISON ERROR ***\n");
3654 ep += sprintf(ep, "check_file(%s, %d, %d, %s, %d, %d) failed\n\n",
3655 file, offset, length, pattern, pattern_length, patshift);
3656 ep += sprintf(ep, "Comparison fd is %d, with open flags %#o\n",
3665 * Function to single-thread stdio output.
3669 doio_fprintf(FILE *stream, char *format, ...)
3671 static int pid = -1;
3677 date = hms(time(0));
3683 flk.l_whence = flk.l_start = flk.l_len = 0;
3684 flk.l_type = F_WRLCK;
3685 fcntl(fileno(stream), F_SETLKW, &flk);
3687 va_start(arglist, format);
3688 rval = fprintf(stream, "\n%s%s (%5d) %s\n", Prog, TagName, pid, date);
3689 rval += fprintf(stream, "---------------------\n");
3690 vfprintf(stream, format, arglist);
3695 flk.l_type = F_UNLCK;
3696 fcntl(fileno(stream), F_SETLKW, &flk);
3702 * Simple function for allocating core memory. Uses Memsize and Memptr to
3703 * keep track of the current amount allocated.
3712 int me = 0, flags, key, shmid;
3713 static int mturn = 0; /* which memory type to use */
3717 struct shmid_ds shm_ds;
3721 bzero( &shm_ds, sizeof(struct shmid_ds) );
3724 /* nbytes = -1 means "free all allocated memory" */
3725 if( nbytes == -1 ) {
3727 for(me=0; me < Nmemalloc; me++) {
3728 if(Memalloc[me].space == NULL)
3731 switch(Memalloc[me].memtype) {
3734 if(Memalloc[me].flags & MEMF_MPIN)
3735 munpin(Memalloc[me].space,
3738 free(Memalloc[me].space);
3739 Memalloc[me].space = NULL;
3745 if(Memalloc[me].flags & MEMF_MPIN)
3746 munpin(Memalloc[me].space,
3749 shmdt(Memalloc[me].space);
3750 Memalloc[me].space = NULL;
3752 shmctl(Memalloc[me].fd, IPC_RMID);
3754 shmctl(Memalloc[me].fd, IPC_RMID, &shm_ds);
3759 if(Memalloc[me].flags & MEMF_MPIN)
3760 munpin(Memalloc[me].space,
3763 munmap(Memalloc[me].space,
3765 close(Memalloc[me].fd);
3766 if(Memalloc[me].flags & MEMF_FILE) {
3767 unlink(Memalloc[me].name);
3769 Memalloc[me].space = NULL;
3772 doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
3773 Memalloc[me].memtype, me);
3781 * Select a memory area (currently round-robbin)
3784 if(mturn >= Nmemalloc)
3787 M = &Memalloc[mturn];
3789 switch(M->memtype) {
3791 if( nbytes > M->size ) {
3792 if( M->space != NULL ){
3794 if( M->flags & MEMF_MPIN )
3795 munpin( M->space, M->size );
3803 if( M->space == NULL ) {
3804 if( (cp = malloc( nbytes )) == NULL ) {
3805 doio_fprintf(stderr, "malloc(%d) failed: %s (%d)\n",
3806 nbytes, SYSERR, errno);
3810 if(M->flags & MEMF_MPIN) {
3811 if( mpin(cp, nbytes) == -1 ) {
3812 doio_fprintf(stderr, "mpin(0x%lx, %d) failed: %s (%d)\n",
3813 cp, nbytes, SYSERR, errno);
3817 M->space = (void *)cp;
3823 if( nbytes > M->size ) {
3824 if( M->space != NULL ) {
3826 if( M->flags & MEMF_MPIN )
3827 munpin(M->space, M->size);
3829 munmap(M->space, M->size);
3831 if( M->flags & MEMF_FILE )
3838 if( M->space == NULL ) {
3839 if(strchr(M->name, '%')) {
3840 sprintf(filename, M->name, getpid());
3841 M->name = strdup(filename);
3844 if( (M->fd = open(M->name, O_CREAT|O_RDWR, 0666)) == -1) {
3845 doio_fprintf(stderr, "alloc_mmap: error %d (%s) opening '%s'\n",
3853 M->size = nbytes * 4;
3855 /* bias addr if MEMF_ADDR | MEMF_FIXADDR */
3856 /* >>> how to pick a memory address? */
3858 /* bias flags on MEMF_PRIVATE etc */
3859 if(M->flags & MEMF_PRIVATE)
3860 flags |= MAP_PRIVATE;
3862 if(M->flags & MEMF_LOCAL)
3864 if(M->flags & MEMF_AUTORESRV)
3865 flags |= MAP_AUTORESRV;
3866 if(M->flags & MEMF_AUTOGROW)
3867 flags |= MAP_AUTOGROW;
3869 if(M->flags & MEMF_SHARED)
3870 flags |= MAP_SHARED;
3872 /*printf("alloc_mem, about to mmap, fd=%d, name=(%s)\n", M->fd, M->name);*/
3873 if( (M->space = mmap(addr, M->size,
3874 PROT_READ|PROT_WRITE,
3877 doio_fprintf(stderr, "alloc_mem: mmap error. errno %d (%s)\n\tmmap(addr 0x%x, size %d, read|write 0x%x, mmap flags 0x%x [%#o], fd %d, 0)\n\tfile %s\n",
3880 PROT_READ|PROT_WRITE,
3881 flags, M->flags, M->fd,
3883 doio_fprintf(stderr, "\t%s%s%s%s%s",
3884 (flags & MAP_PRIVATE) ? "private " : "",
3886 (flags & MAP_LOCAL) ? "local " : "",
3887 (flags & MAP_AUTORESRV) ? "autoresrv " : "",
3888 (flags & MAP_AUTOGROW) ? "autogrow " : "",
3890 (flags & MAP_SHARED) ? "shared" : "");
3897 if( nbytes > M->size ) {
3898 if( M->space != NULL ) {
3900 if( M->flags & MEMF_MPIN )
3901 munpin(M->space, M->size);
3905 shmctl( M->fd, IPC_RMID );
3907 shmctl( M->fd, IPC_RMID, &shm_ds );
3914 if(M->space == NULL) {
3915 if(!strcmp(M->name, "private")) {
3918 sscanf(M->name, "%i", &key);
3921 M->size = M->nblks ? M->nblks * 512 : nbytes;
3923 if( nbytes > M->size ){
3925 doio_fprintf(stderr, "MEM_SHMEM: nblks(%d) too small: nbytes=%d Msize=%d, skipping this req.\n",
3926 M->nblks, nbytes, M->size );
3931 shmid = shmget(key, M->size, IPC_CREAT|0666);
3933 doio_fprintf(stderr, "shmget(0x%x, %d, CREAT) failed: %s (%d)\n",
3934 key, M->size, SYSERR, errno);
3938 M->space = shmat(shmid, NULL, SHM_RND);
3939 if( M->space == (void *)-1 ) {
3940 doio_fprintf(stderr, "shmat(0x%x, NULL, SHM_RND) failed: %s (%d)\n",
3941 shmid, SYSERR, errno);
3945 if(M->flags & MEMF_MPIN) {
3946 if( mpin(M->space, M->size) == -1 ) {
3947 doio_fprintf(stderr, "mpin(0x%lx, %d) failed: %s (%d)\n",
3948 M->space, M->size, SYSERR, errno);
3956 doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
3957 Memalloc[me].memtype, mturn);
3976 static char *malloc_space;
3979 * The "unicos" version of this did some stuff with sbrk;
3980 * this caused problems with async I/O on irix, and now appears
3981 * to be causing problems with FSA I/O on unicos/mk.
3984 if (nbytes > Memsize) {
3985 if ((cp = (char *)sbrk(nbytes - Memsize)) == (char *)-1) {
3986 doio_fprintf(stderr, "sbrk(%d) failed: %s (%d)\n",
3987 nbytes - Memsize, SYSERR, errno);
3993 Memsize += nbytes - Memsize;
3997 /* nbytes = -1 means "free all allocated memory" */
3998 if( nbytes == -1 ) {
3999 free( malloc_space );
4005 if( nbytes > Memsize ) {
4007 free( malloc_space );
4009 if( (cp = malloc_space = malloc( nbytes )) == NULL ) {
4010 doio_fprintf(stderr, "malloc(%d) failed: %s (%d)\n",
4011 nbytes, SYSERR, errno);
4016 /* T3E requires memory to be aligned on 0x40 word boundaries */
4018 if( ip & 0x3F != 0 ) {
4019 doio_fprintf(stderr, "malloc(%d) = 0x%x(0x%x) not aligned by 0x%x\n",
4020 nbytes, cp, ip, ip & 0x3f);
4023 if( (cp = malloc_space = malloc( nbytes + 0x40 )) == NULL ) {
4024 doio_fprintf(stderr, "malloc(%d) failed: %s (%d)\n",
4025 nbytes, SYSERR, errno);
4029 cp += (0x40 - (ip & 0x3F));
4031 #endif /* _CRAYT3E */
4041 * Simple function for allocating sds space. Uses Sdssize and Sdsptr to
4042 * keep track of location and size of currently allocated chunk.
4053 if (nbytes > Sdssize) {
4054 if ((nblks = ssbreak(btoc(nbytes - Sdssize))) == -1) {
4055 doio_fprintf(stderr, "ssbreak(%d) failed: %s (%d)\n",
4056 btoc(nbytes - Sdssize), SYSERR, errno);
4060 Sdssize = ctob(nblks);
4075 doio_fprintf(stderr,
4076 "Internal Error - alloc_sds() called on a CRAY2 system\n");
4086 * Function to maintain a file descriptor cache, so that doio does not have
4087 * to do so many open() and close() calls. Descriptors are stored in the
4088 * cache by file name, and open flags. Each entry also has a _rtc value
4089 * associated with it which is used in aging. If doio cannot open a file
4090 * because it already has too many open (ie. system limit hit) it will close
4091 * the one in the cache that has the oldest _rtc value.
4093 * If alloc_fd() is called with a file of NULL, it will close all descriptors
4094 * in the cache, and free the memory in the cache.
4098 alloc_fd(file, oflags)
4102 struct fd_cache *fdc;
4103 struct fd_cache *alloc_fdcache(char *file, int oflags);
4105 fdc = alloc_fdcache(file, oflags);
4113 alloc_fdcache(file, oflags)
4118 struct fd_cache *free_slot, *oldest_slot, *cp;
4119 static int cache_size = 0;
4120 static struct fd_cache *cache = NULL;
4122 struct dioattr finfo;
4126 * If file is NULL, it means to free up the fd cache.
4129 if (file == NULL && cache != NULL) {
4130 for (cp = cache; cp < &cache[cache_size]; cp++) {
4131 if (cp->c_fd != -1) {
4135 if (cp->c_memaddr != NULL) {
4136 munmap(cp->c_memaddr, cp->c_memlen);
4151 * Look for a fd in the cache. If one is found, return it directly.
4152 * Otherwise, when this loop exits, oldest_slot will point to the
4153 * oldest fd slot in the cache, and free_slot will point to an
4154 * unoccupied slot if there are any.
4157 for (cp = cache; cp != NULL && cp < &cache[cache_size]; cp++) {
4158 if (cp->c_fd != -1 &&
4159 cp->c_oflags == oflags &&
4160 strcmp(cp->c_file, file) == 0) {
4169 if (cp->c_fd == -1) {
4170 if (free_slot == NULL) {
4174 if (oldest_slot == NULL ||
4175 cp->c_rtc < oldest_slot->c_rtc) {
4182 * No matching file/oflags pair was found in the cache. Attempt to
4186 if ((fd = open(file, oflags, 0666)) < 0) {
4187 if (errno != EMFILE) {
4188 doio_fprintf(stderr,
4189 "Could not open file %s with flags %#o (%s): %s (%d)\n",
4190 file, oflags, format_oflags(oflags),
4197 * If we get here, we have as many open fd's as we can have.
4198 * Close the oldest one in the cache (pointed to by
4199 * oldest_slot), and attempt to re-open.
4202 close(oldest_slot->c_fd);
4203 oldest_slot->c_fd = -1;
4204 free_slot = oldest_slot;
4206 if ((fd = open(file, oflags, 0666)) < 0) {
4207 doio_fprintf(stderr,
4208 "Could not open file %s with flags %#o (%s): %s (%d)\n",
4209 file, oflags, format_oflags(oflags),
4216 /*printf("alloc_fd: new file %s flags %#o fd %d\n", file, oflags, fd);*/
4219 * If we get here, fd is our open descriptor. If free_slot is NULL,
4220 * we need to grow the cache, otherwise free_slot is the slot that
4221 * should hold the fd info.
4224 if (free_slot == NULL) {
4225 cache = (struct fd_cache *)realloc(cache, sizeof(struct fd_cache) * (FD_ALLOC_INCR + cache_size));
4226 if (cache == NULL) {
4227 doio_fprintf(stderr, "Could not malloc() space for fd chace");
4232 cache_size += FD_ALLOC_INCR;
4234 for (cp = &cache[cache_size-FD_ALLOC_INCR];
4235 cp < &cache[cache_size]; cp++) {
4239 free_slot = &cache[cache_size - FD_ALLOC_INCR];
4243 * finally, fill in the cache slot info
4246 free_slot->c_fd = fd;
4247 free_slot->c_oflags = oflags;
4248 strcpy(free_slot->c_file, file);
4250 free_slot->c_rtc = _rtc();
4252 free_slot->c_rtc = Reqno;
4256 if (oflags & O_DIRECT) {
4257 if (xfsctl(file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
4259 finfo.d_miniosz = 1;
4260 finfo.d_maxiosz = 1;
4264 finfo.d_miniosz = 1;
4265 finfo.d_maxiosz = 1;
4268 free_slot->c_memalign = finfo.d_mem;
4269 free_slot->c_miniosz = finfo.d_miniosz;
4270 free_slot->c_maxiosz = finfo.d_maxiosz;
4273 free_slot->c_memaddr = NULL;
4274 free_slot->c_memlen = 0;
4282 * Signal Handling Section
4289 * "caller-id" for signals
4292 signal_info(int sig, siginfo_t *info, void *v)
4297 switch(info->si_code) {
4299 doio_fprintf(stderr,
4300 "signal_info: si_signo %d si_errno %d si_code SI_USER pid %d uid %d\n",
4301 info->si_signo, info->si_errno,
4302 info->si_pid, info->si_uid);
4307 doio_fprintf(stderr, "signal_info si_signo %d si_code = SI_QUEUE\n",
4314 if( (info->si_signo == SIGSEGV) ||
4315 (info->si_signo == SIGBUS) ){
4316 doio_fprintf(stderr, "signal_info si_signo %d si_errno %d si_code = %d si_addr=%p active_mmap_rw=%d havesigint=%d\n",
4317 info->si_signo, info->si_errno,
4318 info->si_code, info->si_addr,
4326 doio_fprintf(stderr, "signal_info: si_signo %d si_errno %d unknown code %d\n",
4327 info->si_signo, info->si_errno,
4331 doio_fprintf(stderr, "signal_info: sig %d\n", sig);
4338 cleanup_handler(int sig, siginfo_t *info, void *v)
4340 havesigint=1; /* in case there's a followup signal */
4341 /*signal_info(sig, info, v);*/ /* be quiet on "normal" kill */
4348 die_handler(int sig, siginfo_t *info, void *v)
4350 doio_fprintf(stderr, "terminating on signal %d\n", sig);
4351 signal_info(sig, info, v);
4357 sigbus_handler(int sig, siginfo_t *info, void *v)
4359 /* While we are doing a memcpy to/from an mmapped region we can
4360 get a SIGBUS for a variety of reasons--and not all of them
4361 should be considered failures.
4363 Under normal conditions if we get a SIGINT it means we've been
4364 told to shutdown. However, if we're currently doing the above-
4365 mentioned memcopy then the kernel will follow that SIGINT with
4366 a SIGBUS. We can guess that we're in this situation by seeing
4367 that the si_errno field in the siginfo structure has EINTR as
4368 an errno. (We might make the guess stronger by looking at the
4369 si_addr field to see that it's not faulting off the end of the
4370 mmapped region, but it seems that in such a case havesigint
4371 would not have been set so maybe that doesn't make the guess
4376 if( active_mmap_rw && havesigint && (info->si_errno == EINTR) ){
4377 cleanup_handler( sig, info, v );
4380 die_handler( sig, info, v );
4388 havesigint=1; /* in case there's a followup signal */
4397 doio_fprintf(stderr, "terminating on signal %d\n", sig);
4407 /* See sigbus_handler() in the 'ifdef sgi' case for details. Here,
4408 we don't have the siginfo stuff so the guess is weaker but we'll
4412 if( active_mmap_rw && havesigint )
4430 * SIGINT handler for the parent (original doio) process. It simply sends
4431 * a SIGINT to all of the doio children. Since they're all in the same
4432 * pgrp, this can be done with a single kill().
4440 for (i = 0; i < Nchildren; i++) {
4441 if (Children[i] != -1) {
4442 kill(Children[i], SIGINT);
4448 * Signal handler used to inform a process when async io completes. Referenced
4449 * in do_read() and do_write(). Note that the signal handler is not
4458 struct aio_info *aiop;
4460 for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
4461 aiop = &Aio_Info[i];
4463 if (aiop->strategy == A_SIGNAL && aiop->sig == sig) {
4466 if (aio_done(aiop)) {
4474 * dump info on all open aio slots
4482 for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
4483 if (Aio_Info[i].busy) {
4486 "Aio_Info[%03d] id=%d fd=%d signal=%d signaled=%d\n",
4490 Aio_Info[i].signalled);
4491 fprintf(stderr, "\tstrategy=%s\n",
4492 format_strat(Aio_Info[i].strategy));
4495 fprintf(stderr, "%d active async i/os\n", count);
4501 * Signal handler called as a callback, not as a signal.
4502 * 'val' is the value from sigev_value and is assumed to be the
4509 struct aio_info *aiop;
4511 /*printf("cb_handler requesting slot %d\n", val.sival_int);*/
4512 aiop = aio_slot( val.sival_int );
4513 /*printf("cb_handler, aiop=%p\n", aiop);*/
4515 /*printf("%d in cb_handler\n", getpid() );*/
4516 if (aiop->strategy == A_CALLBACK) {
4519 if (aio_done(aiop)) {
4532 struct aio_info *aiop;
4536 for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
4538 if (! Aio_Info[i].busy) {
4539 aiop = &Aio_Info[i];
4545 if (Aio_Info[i].busy && Aio_Info[i].id == aio_id) {
4546 aiop = &Aio_Info[i];
4553 doio_fprintf(stderr,"aio_slot(%d) not found. Request %d\n",
4564 aio_register(fd, strategy, sig)
4569 struct aio_info *aiop;
4571 struct sigaction sa;
4573 aiop = aio_slot(-1);
4576 aiop->strategy = strategy;
4579 bzero((char *)&aiop->iosw, sizeof(aiop->iosw));
4582 if (strategy == A_SIGNAL) {
4584 aiop->signalled = 0;
4586 sa.sa_handler = aio_handler;
4588 sigemptyset(&sa.sa_mask);
4590 sigaction(sig, &sa, &aiop->osa);
4593 aiop->signalled = 0;
4600 aio_unregister(aio_id)
4603 struct aio_info *aiop;
4605 aiop = aio_slot(aio_id);
4607 if (aiop->strategy == A_SIGNAL) {
4608 sigaction(aiop->sig, &aiop->osa, NULL);
4620 #ifdef RECALL_SIZEOF
4621 long mask[RECALL_SIZEOF];
4624 struct aio_info *aiop;
4626 struct iosw *ioswlist[1];
4629 const aiocb_t *aioary[1];
4634 aiop = aio_slot(aio_id);
4635 /*printf("%d aiop B =%p\n", getpid(), aiop);*/
4637 switch (aiop->strategy) {
4639 while (! aio_done(aiop))
4644 sigemptyset(&sigset);
4645 sighold( aiop->sig );
4647 while ( !aiop->signalled || !aiop->done ) {
4648 sigsuspend(&sigset);
4649 sighold( aiop->sig );
4655 ioswlist[0] = &aiop->iosw;
4656 if (recall(aiop->fd, 1, ioswlist) < 0) {
4657 doio_fprintf(stderr, "recall() failed: %s (%d)\n",
4663 #ifdef RECALL_SIZEOF
4667 RECALL_SET(mask, aiop->fd);
4668 if (recalla(mask) < 0) {
4669 doio_fprintf(stderr, "recalla() failed: %s (%d)\n",
4674 RECALL_CLR(mask, aiop->fd);
4679 ioswlist[0] = &aiop->iosw;
4680 if (recalls(1, ioswlist) < 0) {
4681 doio_fprintf(stderr, "recalls failed: %s (%d)\n",
4690 aioary[0] = &aiop->aiocb;
4693 r = aio_suspend(aioary, 1, NULL);
4695 doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
4700 } while(aiop->done == 0);
4704 * after having this set for a while, I've decided that
4708 doio_fprintf(stderr, "aio_wait: callback wait took %d tries\n", cnt);
4712 * Note: cb_handler already calls aio_done
4718 aioary[0] = &aiop->aiocb;
4719 r = aio_suspend(aioary, 1, NULL);
4721 doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
4731 /*printf("aio_wait: errno %d return %d\n", aiop->aio_errno, aiop->aio_ret);*/
4738 * Format specified time into HH:MM:SS format. t is the time to format
4739 * in seconds (as returned from time(2)).
4746 static char ascii_time[9];
4749 ltime = localtime(&t);
4750 strftime(ascii_time, sizeof(ascii_time), "%H:%M:%S", ltime);
4756 * Simple routine to check if an async io request has completed.
4760 aio_done(struct aio_info *ainfo)
4763 return ainfo->iosw.sw_flag;
4767 if( (ainfo->aio_errno = aio_error(&ainfo->aiocb)) == -1 ){
4768 doio_fprintf(stderr, "aio_done: aio_error failed: %s (%d)\n",
4772 /*printf("%d aio_done aio_errno=%d\n", getpid(), ainfo->aio_errno);*/
4773 if( ainfo->aio_errno != EINPROGRESS ){
4774 if( (ainfo->aio_ret = aio_return(&ainfo->aiocb)) == -1 ){
4775 doio_fprintf(stderr, "aio_done: aio_return failed: %s (%d)\n",
4781 return (ainfo->aio_errno != EINPROGRESS);
4783 return -1; /* invalid */
4788 * Routine to handle upanic() - it first attempts to set the panic flag. If
4789 * the flag cannot be set, an error message is issued. A call to upanic
4790 * with PA_PANIC is then done unconditionally, in case the panic flag was set
4791 * from outside the program (as with the panic(8) program).
4793 * Note - we only execute the upanic code if -U was used, and the passed in
4794 * mask is set in the Upanic_Conditions bitmask.
4801 if (U_opt == 0 || (mask & Upanic_Conditions) == 0) {
4806 if (upanic(PA_SET) < 0) {
4807 doio_fprintf(stderr, "WARNING - Could not set the panic flag - upanic(PA_SET) failed: %s (%d)\n",
4814 syssgi(1005); /* syssgi test panic - DEBUG kernels only */
4816 doio_fprintf(stderr, "WARNING - upanic() failed\n");
4820 * Parse cmdline options/arguments and set appropriate global variables.
4821 * If the cmdline is valid, return 0 to caller. Otherwise exit with a status
4826 parse_cmdline(argc, argv, opts)
4832 char cc, *cp, *tok = NULL;
4835 extern char *optarg;
4837 char *memargs[NMEMALLOC];
4839 void parse_memalloc(char *arg);
4840 void parse_delay(char *arg);
4841 void dump_memalloc();
4843 if (*argv[0] == '-') {
4848 if ((Prog = strrchr(argv[0], '/')) == NULL) {
4855 while ((c = getopt(argc, argv, opts)) != EOF) {
4863 for(s=checkmap; s->string != NULL; s++)
4864 if(!strcmp(s->string, optarg))
4866 if (s->string == NULL) {
4868 "%s%s: Illegal -C arg (%s). Must be one of: ",
4869 Prog, TagName, tok);
4871 for (s = checkmap; s->string != NULL; s++)
4872 fprintf(stderr, "%s ", s->string);
4873 fprintf(stderr, "\n");
4879 Data_Fill = doio_pat_fill;
4880 Data_Check = doio_pat_check;
4884 "%s%s: Unrecognised -C arg '%s' %d",
4885 Prog, TagName, s->string, s->value);
4890 case 'd': /* delay between i/o ops */
4891 parse_delay(optarg);
4895 if (Npes > 1 && Nprocs > 1) {
4896 fprintf(stderr, "%s%s: Warning - Program is a multi-pe application - exec option is ignored.\n", Prog, TagName);
4911 Message_Interval = strtol(optarg, &cp, 10);
4912 if (*cp != '\0' || Message_Interval < 0) {
4913 fprintf(stderr, "%s%s: Illegal -m arg (%s): Must be an integer >= 0\n", Prog, TagName, optarg);
4919 case 'M': /* memory allocation types */
4921 nmemargs = string_to_tokens(optarg, memargs, 32, ",");
4922 for(ma=0; ma < nmemargs; ma++) {
4923 parse_memalloc(memargs[ma]);
4925 /*dump_memalloc();*/
4927 fprintf(stderr, "%s%s: Error: -M isn't supported on this platform\n", Prog, TagName);
4934 sprintf( TagName, "(%.39s)", optarg );
4938 Nprocs = strtol(optarg, &cp, 10);
4939 if (*cp != '\0' || Nprocs < 1) {
4941 "%s%s: Illegal -n arg (%s): Must be integer > 0\n",
4942 Prog, TagName, optarg);
4946 if (Npes > 1 && Nprocs > 1) {
4947 fprintf(stderr, "%s%s: Program has been built as a multi-pe app. -n1 is the only nprocs value allowed\n", Prog, TagName);
4954 Release_Interval = strtol(optarg, &cp, 10);
4955 if (*cp != '\0' || Release_Interval < 0) {
4957 "%s%s: Illegal -r arg (%s): Must be integer >= 0\n",
4958 Prog, TagName, optarg);
4975 if (strcasecmp(optarg, "sync") == 0) {
4976 Validation_Flags = O_SYNC;
4977 } else if (strcasecmp(optarg, "buffered") == 0) {
4978 Validation_Flags = 0;
4980 } else if (strcasecmp(optarg, "parallel") == 0) {
4981 Validation_Flags = O_PARALLEL;
4982 } else if (strcasecmp(optarg, "ldraw") == 0) {
4983 Validation_Flags = O_LDRAW;
4984 } else if (strcasecmp(optarg, "raw") == 0) {
4985 Validation_Flags = O_RAW;
4987 } else if (strcasecmp(optarg, "direct") == 0) {
4988 Validation_Flags = O_DIRECT;
4990 if (sscanf(optarg, "%i%c", &Validation_Flags, &cc) != 1) {
4991 fprintf(stderr, "%s: Invalid -V argument (%s) - must be a decimal, hex, or octal\n", Prog, optarg);
4992 fprintf(stderr, " number, or one of the following strings: 'sync',\n");
4993 fprintf(stderr, " 'buffered', 'parallel', 'ldraw', or 'raw'\n");
5000 tok = strtok(optarg, ",");
5001 while (tok != NULL) {
5002 for (s = Upanic_Args; s->string != NULL; s++)
5003 if (strcmp(s->string, tok) == 0)
5006 if (s->string == NULL) {
5008 "%s%s: Illegal -U arg (%s). Must be one of: ",
5009 Prog, TagName, tok);
5011 for (s = Upanic_Args; s->string != NULL; s++)
5012 fprintf(stderr, "%s ", s->string);
5014 fprintf(stderr, "\n");
5019 Upanic_Conditions |= s->value;
5020 tok = strtok(NULL, ",");
5038 Data_Fill = doio_pat_fill;
5039 Data_Check = doio_pat_check;
5043 Upanic_Conditions = 0;
5049 Release_Interval = DEF_RELEASE_INTERVAL;
5052 Memalloc[Nmemalloc].memtype = MEM_DATA;
5053 Memalloc[Nmemalloc].flags = 0;
5054 Memalloc[Nmemalloc].name = NULL;
5055 Memalloc[Nmemalloc].space = NULL;
5060 * Initialize input stream
5063 if (argc == optind) {
5066 Infile = argv[optind++];
5069 if (argc != optind) {
5080 * Parse memory allocation types
5084 * T3E-shmem:blksize[:nblks]
5085 * SysV-shmem:shmid:blksize:nblks
5086 * if shmid is "private", use IPC_PRIVATE
5087 * and nblks is not required
5089 * mmap:flags:filename:blksize[:nblks]
5091 * p - private (MAP_PRIVATE)
5092 * a - private, MAP_AUTORESRV
5093 * l - local (MAP_LOCAL)
5094 * s - shared (nblks required)
5097 * f - fixed address (MAP_FIXED)
5098 * A - use an address without MAP_FIXED
5099 * a - autogrow (map once at startup)
5101 * mmap:flags:devzero
5102 * mmap /dev/zero (shared not allowd)
5103 * maps the first 4096 bytes of /dev/zero
5105 * - put a directory at the beginning of the shared
5106 * regions saying what pid has what region.
5110 * nblks worth of directories - 1 int pids
5114 parse_memalloc(char *arg)
5116 char *allocargs[NMEMALLOC];
5120 if(Nmemalloc >= NMEMALLOC) {
5121 doio_fprintf(stderr, "Error - too many memory types (%d).\n",
5126 M = &Memalloc[Nmemalloc];
5128 nalloc = string_to_tokens(arg, allocargs, 32, ":");
5129 if(!strcmp(allocargs[0], "data")) {
5130 M->memtype = MEM_DATA;
5136 if(strchr(allocargs[1], 'p'))
5137 M->flags |= MEMF_MPIN;
5139 } else if(!strcmp(allocargs[0], "mmap")) {
5140 /* mmap:flags:filename[:size] */
5141 M->memtype = MEM_MMAP;
5145 if(strchr(allocargs[1], 'p'))
5146 M->flags |= MEMF_PRIVATE;
5147 if(strchr(allocargs[1], 'a'))
5148 M->flags |= MEMF_AUTORESRV;
5149 if(strchr(allocargs[1], 'l'))
5150 M->flags |= MEMF_LOCAL;
5151 if(strchr(allocargs[1], 's'))
5152 M->flags |= MEMF_SHARED;
5154 if(strchr(allocargs[1], 'f'))
5155 M->flags |= MEMF_FIXADDR;
5156 if(strchr(allocargs[1], 'A'))
5157 M->flags |= MEMF_ADDR;
5158 if(strchr(allocargs[1], 'G'))
5159 M->flags |= MEMF_AUTOGROW;
5161 if(strchr(allocargs[1], 'U'))
5162 M->flags |= MEMF_FILE;
5164 M->flags |= MEMF_PRIVATE;
5168 if(!strcmp(allocargs[2], "devzero")) {
5169 M->name = "/dev/zero";
5171 ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
5172 M->flags |= MEMF_PRIVATE;
5174 M->name = allocargs[2];
5177 M->name = "/dev/zero";
5179 ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
5180 M->flags |= MEMF_PRIVATE;
5184 } else if(!strcmp(allocargs[0], "shmem")) {
5185 /* shmem:shmid:size */
5186 M->memtype = MEM_SHMEM;
5190 M->name = allocargs[1];
5195 sscanf(allocargs[2], "%i", &M->nblks);
5200 if(strchr(allocargs[3], 'p'))
5201 M->flags |= MEMF_MPIN;
5206 doio_fprintf(stderr, "Error - unknown memory type '%s'.\n",
5218 if(Nmemalloc == 0) {
5219 printf("No memory allocation strategies devined\n");
5223 for(ma=0; ma < Nmemalloc; ma++) {
5224 switch(Memalloc[ma].memtype) {
5225 case MEM_DATA: mt = "data"; break;
5226 case MEM_SHMEM: mt = "shmem"; break;
5227 case MEM_MMAP: mt = "mmap"; break;
5228 default: mt = "unknown"; break;
5230 printf("mstrat[%d] = %d %s\n", ma, Memalloc[ma].memtype, mt);
5231 printf("\tflags=%#o name='%s' nblks=%d\n",
5234 Memalloc[ma].nblks);
5241 * -d <op>:<time> - doio inter-operation delay
5242 * currently this permits ONE type of delay between operations.
5246 parse_delay(char *arg)
5248 char *delayargs[NMEMALLOC];
5252 ndelay = string_to_tokens(arg, delayargs, 32, ":");
5254 doio_fprintf(stderr,
5255 "Illegal delay arg (%s). Must be operation:time\n", arg);
5258 for(s=delaymap; s->string != NULL; s++)
5259 if(!strcmp(s->string, delayargs[0]))
5261 if (s->string == NULL) {
5263 "Illegal Delay arg (%s). Must be one of: ", arg);
5265 for (s = delaymap; s->string != NULL; s++)
5266 fprintf(stderr, "%s ", s->string);
5267 fprintf(stderr, "\n");
5273 sscanf(delayargs[1], "%i", &delaytime);
5277 "Warning: extra delay arguments ignored.\n");
5283 * Usage clause - obvious
5291 * Only do this if we are on vpe 0, to avoid seeing it from every
5292 * process in the application.
5295 if (Npes > 1 && Vpe != 0) {
5299 fprintf(stream, "usage%s: %s [-aekv] [-m message_interval] [-n nprocs] [-r release_interval] [-w write_log] [-V validation_ftype] [-U upanic_cond] [infile]\n", TagName, Prog);
5308 * Only the app running on vpe 0 gets to issue help - this prevents
5309 * everybody in the application from doing this.
5312 if (Npes > 1 && Vpe != 0) {
5317 fprintf(stream, "\n");
5318 fprintf(stream, "\t-a abort - kill all doio processes on data compare\n");
5319 fprintf(stream, "\t errors. Normally only the erroring process exits\n");
5320 fprintf(stream, "\t-C data-pattern-type \n");
5321 fprintf(stream, "\t Available data patterns are:\n");
5322 fprintf(stream, "\t default - repeating pattern\n");
5323 fprintf(stream, "\t-d Operation:Time Inter-operation delay.\n");
5324 fprintf(stream, "\t Operations are:\n");
5325 fprintf(stream, "\t select:time (1 second=1000000)\n");
5326 fprintf(stream, "\t sleep:time (1 second=1)\n");
5328 fprintf(stream, "\t sginap:time (1 second=CLK_TCK=100)\n");
5330 fprintf(stream, "\t alarm:time (1 second=1)\n");
5331 fprintf(stream, "\t-e Re-exec children before entering the main\n");
5332 fprintf(stream, "\t loop. This is useful for spreading\n");
5333 fprintf(stream, "\t procs around on multi-pe systems.\n");
5334 fprintf(stream, "\t-k Lock file regions during writes using fcntl()\n");
5335 fprintf(stream, "\t-v Verify writes - this is done by doing a buffered\n");
5336 fprintf(stream, "\t read() of the data if file io was done, or\n");
5337 fprintf(stream, "\t an ssread()of the data if sds io was done\n");
5339 fprintf(stream, "\t-M Data buffer allocation method\n");
5340 fprintf(stream, "\t alloc-type[,type]\n");
5342 fprintf(stream, "\t data:flags\n");
5343 fprintf(stream, "\t p - mpin buffer\n");
5344 fprintf(stream, "\t shmem:shmid:size:flags\n");
5345 fprintf(stream, "\t p - mpin buffer\n");
5347 fprintf(stream, "\t data\n");
5348 fprintf(stream, "\t shmem:shmid:size\n");
5350 fprintf(stream, "\t mmap:flags:filename\n");
5351 fprintf(stream, "\t p - private\n");
5353 fprintf(stream, "\t s - shared\n");
5354 fprintf(stream, "\t l - local\n");
5355 fprintf(stream, "\t a - autoresrv\n");
5356 fprintf(stream, "\t G - autogrow\n");
5358 fprintf(stream, "\t s - shared (shared file must exist\n"),
5359 fprintf(stream, "\t and have needed length)\n");
5361 fprintf(stream, "\t f - fixed address (not used)\n");
5362 fprintf(stream, "\t a - specify address (not used)\n");
5363 fprintf(stream, "\t U - Unlink file when done\n");
5364 fprintf(stream, "\t The default flag is private\n");
5365 fprintf(stream, "\n");
5367 fprintf(stream, "\t-m message_interval Generate a message every 'message_interval'\n");
5368 fprintf(stream, "\t requests. An interval of 0 suppresses\n");
5369 fprintf(stream, "\t messages. The default is 0.\n");
5370 fprintf(stream, "\t-N tagname Tag name, for Monster.\n");
5371 fprintf(stream, "\t-n nprocs # of processes to start up\n");
5372 fprintf(stream, "\t-r release_interval Release all memory and close\n");
5373 fprintf(stream, "\t files every release_interval operations.\n");
5374 fprintf(stream, "\t By default procs never release memory\n");
5375 fprintf(stream, "\t or close fds unless they have to.\n");
5376 fprintf(stream, "\t-V validation_ftype The type of file descriptor to use for doing data\n");
5377 fprintf(stream, "\t validation. validation_ftype may be an octal,\n");
5378 fprintf(stream, "\t hex, or decimal number representing the open()\n");
5379 fprintf(stream, "\t flags, or may be one of the following strings:\n");
5380 fprintf(stream, "\t 'buffered' - validate using bufferd read\n");
5381 fprintf(stream, "\t 'sync' - validate using O_SYNC read\n");
5382 fprintf(stream, "\t 'direct - validate using O_DIRECT read'\n");
5384 fprintf(stream, "\t 'ldraw' - validate using O_LDRAW read\n");
5385 fprintf(stream, "\t 'parallel' - validate using O_PARALLEL read\n");
5386 fprintf(stream, "\t 'raw' - validate using O_RAW read\n");
5388 fprintf(stream, "\t By default, 'parallel'\n");
5389 fprintf(stream, "\t is used if the write was done with O_PARALLEL\n");
5390 fprintf(stream, "\t or 'buffered' for all other writes.\n");
5391 fprintf(stream, "\t-w write_log File to log file writes to. The doio_check\n");
5392 fprintf(stream, "\t program can reconstruct datafiles using the\n");
5393 fprintf(stream, "\t write_log, and detect if a file is corrupt\n");
5394 fprintf(stream, "\t after all procs have exited.\n");
5395 fprintf(stream, "\t-U upanic_cond Comma separated list of conditions that will\n");
5396 fprintf(stream, "\t cause a call to upanic(PA_PANIC).\n");
5397 fprintf(stream, "\t 'corruption' -> upanic on bad data comparisons\n");
5398 fprintf(stream, "\t 'iosw' ---> upanic on unexpected async iosw\n");
5399 fprintf(stream, "\t 'rval' ---> upanic on unexpected syscall rvals\n");
5400 fprintf(stream, "\t 'all' ---> all of the above\n");
5401 fprintf(stream, "\n");
5402 fprintf(stream, "\tinfile Input stream - default is stdin - must be a list\n");
5403 fprintf(stream, "\t of io_req structures (see doio.h). Currently\n");
5404 fprintf(stream, "\t only the iogen program generates the proper\n");
5405 fprintf(stream, "\t format\n");