xfstests: fix compile warning in doio.c
[xfstests-dev.git] / ltp / doio.c
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 /*
19  * doio -       a general purpose io initiator with system call and
20  *              write logging.  See doio.h for the structure which defines
21  *              what doio requests should look like.
22  *
23  * programming
24  * notes:
25  * -----------
26  *      messages should generally be printed using doio_fprintf().
27  *
28  */
29
30 #include "global.h"
31
32 #ifdef sgi
33 #include <aio.h>        /* for aio_read,write */
34 #include <inttypes.h>   /* for uint64_t type */
35 #include <siginfo.h>    /* signal handlers & SA_SIGINFO */
36 #endif
37
38 #include <sys/uio.h>    /* for struct iovec (readv)*/
39 #include <sys/mman.h>   /* for mmap(2) */
40 #include <sys/ipc.h>    /* for i/o buffer in shared memory */
41 #include <sys/shm.h>    /* for i/o buffer in shared memory */
42 #include <sys/wait.h>
43 #include <sys/time.h>   /* for delays */
44 #include <ctype.h>
45
46 #ifndef NO_XFS
47 struct io_req;
48 int do_xfsctl(struct io_req *);
49 #endif
50
51 #include "doio.h"
52 #include "pattern.h"
53 #include "write_log.h"
54 #include "random_range.h"
55 #include "string_to_tokens.h"
56
57 #ifndef O_SSD
58 #define O_SSD 0         /* so code compiles on a CRAY2 */
59 #endif
60
61 #define UINT64_T unsigned long long
62
63 #ifndef O_PARALLEL
64 #define O_PARALLEL 0    /* so O_PARALLEL may be used in expressions */
65 #endif
66
67 #define PPID_CHECK_INTERVAL 5           /* check ppid every <-- iterations */
68 #define MAX_AIO         256             /* maximum number of async I/O ops */
69 #ifdef _CRAYMPP
70 #define MPP_BUMP        16              /* page un-alignment for MPP */
71 #else
72 #define MPP_BUMP        0
73 #endif
74
75
76 #define SYSERR strerror(errno)
77
78 /*
79  * getopt() string of supported cmdline arguments.
80  */
81
82 #define OPTS    "aC:d:ehm:n:kr:w:vU:V:M:N:"
83
84 #define DEF_RELEASE_INTERVAL    0
85
86 /*
87  * Flags set in parse_cmdline() to indicate which options were selected
88  * on the cmdline.
89  */
90
91 int     a_opt = 0;          /* abort on data compare errors     */
92 int     e_opt = 0;          /* exec() after fork()'ing          */
93 int     C_opt = 0;          /* Data Check Type                  */
94 int     d_opt = 0;          /* delay between operations         */
95 int     k_opt = 0;          /* lock file regions during writes  */
96 int     m_opt = 0;          /* generate periodic messages       */
97 int     n_opt = 0;          /* nprocs                           */
98 int     r_opt = 0;          /* resource release interval        */
99 int     w_opt = 0;          /* file write log file              */
100 int     v_opt = 0;          /* verify writes if set             */
101 int     U_opt = 0;          /* upanic() on varios conditions    */
102 int     V_opt = 0;          /* over-ride default validation fd type */
103 int     M_opt = 0;          /* data buffer allocation types     */
104 char    TagName[40];        /* name of this doio (see Monster)  */
105
106
107 /*
108  * Misc globals initialized in parse_cmdline()
109  */
110
111 char    *Prog = NULL;       /* set up in parse_cmdline()                */
112 int     Upanic_Conditions;  /* set by args to -U                        */
113 int     Release_Interval;   /* arg to -r                                */
114 int     Nprocs;             /* arg to -n                                */
115 char    *Write_Log;         /* arg to -w                                */
116 char    *Infile;            /* input file (defaults to stdin)           */
117 int     *Children;          /* pids of child procs                      */
118 int     Nchildren = 0;
119 int     Nsiblings = 0;      /* tfork'ed siblings                        */
120 int     Execd = 0;
121 int     Message_Interval = 0;
122 int     Npes = 0;           /* non-zero if built as an mpp multi-pe app */
123 int     Vpe = -1;           /* Virtual pe number if Npes >= 0           */
124 int     Reqno = 1;          /* request # - used in some error messages  */
125 int     Reqskipcnt = 0;     /* count of I/O requests that are skipped   */
126 int     Validation_Flags;
127 char    *(*Data_Check)();   /* function to call for data checking       */
128 int     (*Data_Fill)();     /* function to call for data filling        */
129 int     Nmemalloc = 0;      /* number of memory allocation strategies   */
130 int     delayop = 0;        /* delay between operations - type of delay */
131 int     delaytime = 0;      /* delay between operations - how long      */
132
133 struct wlog_file        Wlog;
134
135 int     active_mmap_rw = 0; /* Indicates that mmapped I/O is occurring. */
136                             /* Used by sigbus_action() in the child doio. */
137 int     havesigint = 0;
138
139 #define SKIP_REQ        -2      /* skip I/O request */
140
141 #define NMEMALLOC       32
142 #define MEM_DATA        1       /* data space                           */
143 #define MEM_SHMEM       2       /* System V shared memory               */
144 #define MEM_T3ESHMEM    3       /* T3E Shared Memory                    */
145 #define MEM_MMAP        4       /* mmap(2)                              */
146
147 #define MEMF_PRIVATE    0001
148 #define MEMF_AUTORESRV  0002
149 #define MEMF_LOCAL      0004
150 #define MEMF_SHARED     0010
151
152 #define MEMF_FIXADDR    0100
153 #define MEMF_ADDR       0200
154 #define MEMF_AUTOGROW   0400
155 #define MEMF_FILE       01000   /* regular file -- unlink on close      */
156 #define MEMF_MPIN       010000  /* use mpin(2) to lock pages in memory */
157
158 struct memalloc {
159         int     memtype;
160         int     flags;
161         int     nblks;
162         char    *name;
163         void    *space;         /* memory address of allocated space */
164         int     fd;             /* FD open for mmaping */
165         int     size;
166 }       Memalloc[NMEMALLOC];
167
168 /*
169  * Global file descriptors
170  */
171
172 int     Wfd_Append;         /* for appending to the write-log       */
173 int     Wfd_Random;         /* for overlaying write-log entries     */
174
175 /*
176  * Structure for maintaining open file test descriptors.  Used by
177  * alloc_fd().
178  */
179
180 struct fd_cache {
181         char    c_file[MAX_FNAME_LENGTH+1];
182         int     c_oflags;
183         int     c_fd;
184         long    c_rtc;
185 #ifndef NO_XFS
186         int     c_memalign;     /* from xfsctl(XFS_IOC_DIOINFO) */
187         int     c_miniosz;
188         int     c_maxiosz;
189 #endif
190 #ifndef CRAY
191         void    *c_memaddr;     /* mmapped address */
192         int     c_memlen;       /* length of above region */
193 #endif
194 };
195
196 #define FD_ALLOC_INCR   32      /* allocate this many fd_map structs    */
197                                 /* at a time */
198
199 /*
200  * Globals for tracking Sds and Core usage
201  */
202
203 char    *Memptr;                /* ptr to core buffer space             */
204 int     Memsize;                /* # bytes pointed to by Memptr         */
205                                 /* maintained by alloc_mem()            */
206
207 int     Sdsptr;                 /* sds offset (always 0)                */
208 int     Sdssize;                /* # bytes of allocated sds space       */
209                                 /* Maintained by alloc_sds()            */
210 char    Host[16];
211 char    Pattern[128];
212 int     Pattern_Length;
213
214 /*
215  * Signal handlers, and related globals
216  */
217
218 void    sigint_handler();       /* Catch SIGINT in parent doio, propagate
219                                  * to children, does not die. */
220
221 void    die_handler();          /* Bad sig in child doios, exit 1. */
222 void    cleanup_handler();      /* Normal kill, exit 0. */
223
224 #ifndef CRAY
225 void    sigbus_handler();       /* Handle sigbus--check active_mmap_rw to
226                                    decide if this should be a normal exit. */
227 #endif
228
229 void    cb_handler();           /* Posix aio callback handler. */
230 void    noop_handler();         /* Delayop alarm, does nothing. */
231 char    *hms();
232 char    *format_rw();
233 char    *format_sds();
234 char    *format_listio();
235 char    *check_file();
236 int     doio_fprintf(FILE *stream, char *format, ...);
237 void    doio_upanic();
238 void    doio();
239 void    help();
240 void    doio_delay();
241 int     alloc_fd( char *, int );
242 int     alloc_mem( int );
243 int     do_read( struct io_req * );
244 int     do_write( struct io_req * );
245 int     do_rw( struct io_req * );
246 int     do_sync( struct io_req * );
247 int     usage( FILE * );
248 int     aio_unregister( int );
249 int     parse_cmdline( int, char **, char * );
250 int     lock_file_region( char *, int, int, int, int );
251 struct  fd_cache *alloc_fdcache(char *, int);
252 int     aio_register( int, int, int );
253 #ifndef linux
254 int aio_wait(int);
255 #endif
256
257 /*
258  * Upanic conditions, and a map from symbolics to values
259  */
260
261 #define U_CORRUPTION    0001        /* upanic on data corruption    */
262 #define U_IOSW          0002        /* upanic on bad iosw           */
263 #define U_RVAL          0004        /* upanic on bad rval           */
264
265 #define U_ALL           (U_CORRUPTION | U_IOSW | U_RVAL)
266
267 /*
268  * Name-To-Value map
269  * Used to map cmdline arguments to values
270  */
271 struct smap {
272         char    *string;
273         int     value;
274 };
275
276 struct smap Upanic_Args[] = {
277         { "corruption", U_CORRUPTION    },
278         { "iosw",       U_IOSW          },
279         { "rval",       U_RVAL          },
280         { "all",        U_ALL           },
281         { NULL,         0               }
282 };
283
284 struct aio_info {
285         int                     busy;
286         int                     id;
287         int                     fd;
288         int                     strategy;
289         volatile int            done;
290 #ifdef CRAY
291         struct iosw             iosw;
292 #endif
293 #ifdef sgi
294         aiocb_t                 aiocb;
295         int                     aio_ret;        /* from aio_return */
296         int                     aio_errno;      /* from aio_error */
297 #endif
298         int                     sig;
299         int                     signalled;
300         struct sigaction        osa;
301 };
302
303 struct aio_info Aio_Info[MAX_AIO];
304
305 struct aio_info *aio_slot();
306 int     aio_done( struct aio_info * );
307
308 /* -C data-fill/check type */
309 #define C_DEFAULT       1
310 struct smap checkmap[] = {
311         { "default",    C_DEFAULT },
312         { NULL,         0 },
313 };
314
315 /* -d option delay types */
316 #define DELAY_SELECT    1
317 #define DELAY_SLEEP     2
318 #define DELAY_SGINAP    3
319 #define DELAY_ALARM     4
320 #define DELAY_ITIMER    5       /* POSIX timer                          */
321
322 struct smap delaymap[] = {
323         { "select",     DELAY_SELECT },
324         { "sleep",      DELAY_SLEEP },
325 #ifdef sgi
326         { "sginap",     DELAY_SGINAP },
327 #endif
328         { "alarm",      DELAY_ALARM },
329         { NULL, 0 },
330 };
331
332 /******
333 *
334 * strerror() does similar actions.
335
336 char *
337 syserrno(int err)
338 {
339     static char sys_errno[10];
340     sprintf(sys_errno, "%d", errno);
341     return(sys_errno);
342 }
343
344 ******/
345
346 int
347 main(argc, argv)
348 int     argc;
349 char    **argv;
350 {
351         int                     i, pid, stat, ex_stat;
352         struct sigaction        sa;
353         sigset_t                block_mask, old_mask;
354         umask(0);               /* force new file modes to known values */
355 #if _CRAYMPP
356         Npes = sysconf(_SC_CRAY_NPES);  /* must do this before parse_cmdline */
357         Vpe = sysconf(_SC_CRAY_VPE);
358 #endif
359
360         TagName[0] = '\0';
361         parse_cmdline(argc, argv, OPTS);
362
363         random_range_seed(getpid());       /* initialize random number generator */
364
365         /*      
366          * If this is a re-exec of doio, jump directly into the doio function.
367          */
368
369         if (Execd) {
370                 doio();
371                 exit(E_SETUP);
372         }
373
374         /*
375          * Stop on all but a few signals...
376          */
377         sigemptyset(&sa.sa_mask);
378         sa.sa_handler = sigint_handler;
379         sa.sa_flags = SA_RESETHAND;     /* sigint is ignored after the */
380                                         /* first time */
381         for (i = 1; i <= NSIG; i++) {
382                 switch(i) {
383 #ifdef SIGRECOVERY
384                 case SIGRECOVERY:
385                         break;
386 #endif
387 #ifdef SIGCKPT
388                 case SIGCKPT:
389 #endif
390 #ifdef SIGRESTART
391                 case SIGRESTART:
392 #endif
393                 case SIGTSTP:
394                 case SIGSTOP:
395                 case SIGCONT:
396                 case SIGCLD:
397                 case SIGBUS:
398                 case SIGSEGV:
399                 case SIGQUIT:
400                         break;
401                 default:
402                         sigaction(i, &sa, NULL);
403                 }
404         }
405
406         /*
407          * If we're logging write operations, make a dummy call to wlog_open
408          * to initialize the write history file.  This call must be done in
409          * the parent, to ensure that the history file exists and/or has
410          * been truncated before any children attempt to open it, as the doio
411          * children are not allowed to truncate the file.
412          */
413
414         if (w_opt) {
415                 strcpy(Wlog.w_file, Write_Log);
416
417                 if (wlog_open(&Wlog, 1, 0666) < 0) {
418                         doio_fprintf(stderr,
419                                      "Could not create/truncate write log %s\n",
420                                      Write_Log);
421                         exit(2);
422                 }
423
424                 wlog_close(&Wlog);
425         }
426
427         /*
428          * Malloc space for the children pid array.  Initialize all entries
429          * to -1.
430          */
431
432         Children = (int *)malloc(sizeof(int) * Nprocs);
433         for (i = 0; i < Nprocs; i++) {
434                 Children[i] = -1;
435         }
436
437         sigemptyset(&block_mask);
438         sigaddset(&block_mask, SIGCHLD);
439         sigprocmask(SIG_BLOCK, &block_mask, &old_mask);
440
441         /*
442          * Fork Nprocs.  This [parent] process is a watchdog, to notify the
443          * invoker of procs which exit abnormally, and to make sure that all
444          * child procs get cleaned up.  If the -e option was used, we will also
445          * re-exec.  This is mostly for unicos/mk on mpp's, to ensure that not
446          * all of the doio's don't end up in the same pe.
447          *
448          * Note - if Nprocs is 1, or this doio is a multi-pe app (Npes > 1),
449          * jump directly to doio().  multi-pe apps can't fork(), and there is
450          * no reason to fork() for 1 proc.
451          */
452
453         if (Nprocs == 1 || Npes > 1) {
454                 doio();
455                 exit(0);
456         } else {
457                 for (i = 0; i < Nprocs; i++) {
458                         if ((pid = fork()) == -1) {
459                                 doio_fprintf(stderr,
460                                              "(parent) Could not fork %d children:  %s (%d)\n",
461                                              i+1, SYSERR, errno);
462                                 exit(E_SETUP);
463                         }
464                         
465                         Children[Nchildren] = pid;
466                         Nchildren++;
467                         
468                         if (pid == 0) {
469                                 if (e_opt) {
470                                         char *exec_path;
471
472                                         exec_path = argv[0];
473                                         argv[0] = (char *)malloc(strlen(exec_path + 1));
474                                         sprintf(argv[0], "-%s", exec_path);
475
476                                         execvp(exec_path, argv);
477                                         doio_fprintf(stderr,
478                                                      "(parent) Could not execvp %s:  %s (%d)\n",
479                                                      exec_path, SYSERR, errno);
480                                         exit(E_SETUP);
481                                 } else {
482                                         doio();
483                                         exit(E_SETUP);
484                                 }
485                         }
486                 }
487
488                 /*
489                  * Parent spins on wait(), until all children exit.
490                  */
491                 
492                 ex_stat = E_NORMAL;
493                 
494                 while (Nprocs) {
495                         if ((pid = wait(&stat)) == -1) {
496                                 if (errno == EINTR)
497                                         continue;
498                         }
499                         
500                         for (i = 0; i < Nchildren; i++)
501                                 if (Children[i] == pid)
502                                         Children[i] = -1;
503                         
504                         Nprocs--;
505                         
506                         if (WIFEXITED(stat)) {
507                                 switch (WEXITSTATUS(stat)) {
508                                 case E_NORMAL:
509                                         /* noop */
510                                         break;
511
512                                 case E_INTERNAL:
513                                         doio_fprintf(stderr,
514                                                      "(parent) pid %d exited because of an internal error\n",
515                                                      pid);
516                                         ex_stat |= E_INTERNAL;
517                                         break;
518
519                                 case E_SETUP:
520                                         doio_fprintf(stderr,
521                                                      "(parent) pid %d exited because of a setup error\n",
522                                                      pid);
523                                         ex_stat |= E_SETUP;
524                                         break;
525
526                                 case E_COMPARE:
527                                         doio_fprintf(stderr,
528                                                      "(parent) pid %d exited because of data compare errors\n",
529                                                      pid);
530
531                                         ex_stat |= E_COMPARE;
532
533                                         if (a_opt)
534                                                 kill(0, SIGINT);
535
536                                         break;
537
538                                 case E_USAGE:
539                                         doio_fprintf(stderr,
540                                                      "(parent) pid %d exited because of a usage error\n",
541                                                      pid);
542
543                                         ex_stat |= E_USAGE;
544                                         break;
545
546                                 default:
547                                         doio_fprintf(stderr,
548                                                      "(parent) pid %d exited with unknown status %d\n",
549                                                      pid, WEXITSTATUS(stat));
550                                         ex_stat |= E_INTERNAL;
551                                         break;
552                                 }
553                         } else if (WIFSIGNALED(stat) && WTERMSIG(stat) != SIGINT) {
554                                 doio_fprintf(stderr,
555                                              "(parent) pid %d terminated by signal %d\n",
556                                              pid, WTERMSIG(stat));
557                                 
558                                 ex_stat |= E_SIGNAL;
559                         }
560                         
561                         fflush(NULL);
562                 }
563         }
564
565         exit(ex_stat);
566
567 }  /* main */
568
569 /*
570  * main doio function.  Each doio child starts here, and never returns.
571  */
572
573 void
574 doio()
575 {
576         int                     rval, i, infd, nbytes;
577         char                    *cp;
578         struct io_req           ioreq;
579         struct sigaction        sa, def_action, ignore_action, exit_action;
580 #ifndef CRAY
581         struct sigaction        sigbus_action;
582 #endif
583
584         Memsize = Sdssize = 0;
585
586         /*
587          * Initialize the Pattern - write-type syscalls will replace Pattern[1]
588          * with the pattern passed in the request.  Make sure that
589          * strlen(Pattern) is not mod 16 so that out of order words will be
590          * detected.
591          */
592
593         gethostname(Host, sizeof(Host));
594         if ((cp = strchr(Host, '.')) != NULL)
595                 *cp = '\0';
596
597         Pattern_Length = sprintf(Pattern, "-:%d:%s:%s*", (int)getpid(), Host, Prog);
598
599         if (!(Pattern_Length % 16)) {
600                 Pattern_Length = sprintf(Pattern, "-:%d:%s:%s**",
601                                          (int)getpid(), Host, Prog);
602         }
603
604         /*
605          * Open a couple of descriptors for the write-log file.  One descriptor
606          * is for appending, one for random access.  Write logging is done for
607          * file corruption detection.  The program doio_check is capable of
608          * doing corruption detection based on a doio write-log.
609          */
610
611         if (w_opt) {
612
613                 strcpy(Wlog.w_file, Write_Log);
614         
615                 if (wlog_open(&Wlog, 0, 0666) == -1) {
616                         doio_fprintf(stderr,
617                                      "Could not open write log file (%s): wlog_open() failed\n",
618                                      Write_Log);
619                         exit(E_SETUP);
620                 }
621         }
622
623         /*
624          * Open the input stream - either a file or stdin
625          */
626
627         if (Infile == NULL) {
628                 infd = 0;
629         } else {
630                 if ((infd = open(Infile, O_RDWR)) == -1) {
631                         doio_fprintf(stderr,
632                                      "Could not open input file (%s):  %s (%d)\n",
633                                      Infile, SYSERR, errno);
634                         exit(E_SETUP);
635                 }
636         }
637
638         /*
639          * Define a set of signals that should never be masked.  Receipt of
640          * these signals generally indicates a programming error, and we want
641          * a corefile at the point of error.  We put SIGQUIT in this list so
642          * that ^\ will force a user core dump.
643          *
644          * Note:  the handler for these should be SIG_DFL, all of them 
645          * produce a corefile as the default action.
646          */
647
648         ignore_action.sa_handler = SIG_IGN;
649         ignore_action.sa_flags = 0;
650         sigemptyset(&ignore_action.sa_mask);
651
652         def_action.sa_handler = SIG_DFL;
653         def_action.sa_flags = 0;
654         sigemptyset(&def_action.sa_mask);
655
656 #ifdef sgi
657         exit_action.sa_sigaction = cleanup_handler;
658         exit_action.sa_flags = SA_SIGINFO;
659         sigemptyset(&exit_action.sa_mask);
660
661         sa.sa_sigaction = die_handler;
662         sa.sa_flags = SA_SIGINFO;
663         sigemptyset(&sa.sa_mask);
664
665         sigbus_action.sa_sigaction = sigbus_handler;
666         sigbus_action.sa_flags = SA_SIGINFO;
667         sigemptyset(&sigbus_action.sa_mask);
668 #else
669         exit_action.sa_handler = cleanup_handler;
670         exit_action.sa_flags = 0;
671         sigemptyset(&exit_action.sa_mask);
672
673         sa.sa_handler = die_handler;
674         sa.sa_flags = 0;
675         sigemptyset(&sa.sa_mask);
676
677 #ifndef CRAY
678         sigbus_action.sa_handler = sigbus_handler;
679         sigbus_action.sa_flags = 0;
680         sigemptyset(&sigbus_action.sa_mask);
681 #endif
682 #endif
683
684         for (i = 1; i <= NSIG; i++) {
685                 switch(i) {
686                         /* Signals to terminate program on */
687                 case SIGINT:
688                         sigaction(i, &exit_action, NULL);
689                         break;
690
691 #ifndef CRAY
692                         /* This depends on active_mmap_rw */
693                 case SIGBUS:
694                         sigaction(i, &sigbus_action, NULL);
695                         break;
696 #endif
697
698                     /* Signals to Ignore... */
699                 case SIGSTOP:
700                 case SIGCONT:
701 #ifdef SIGRECOVERY
702                 case SIGRECOVERY:
703 #endif
704                         sigaction(i, &ignore_action, NULL);
705                         break;
706
707                     /* Signals to trap & report & die */
708                 /*case SIGTRAP:*/
709                 /*case SIGABRT:*/
710 #ifdef SIGERR   /* cray only signals */
711                 case SIGERR:
712                 case SIGBUFIO:
713                 case SIGINFO:
714 #endif
715                 /*case SIGFPE:*/
716                 case SIGURG:
717                 case SIGHUP:
718                 case SIGTERM:
719                 case SIGPIPE:
720                 case SIGIO:
721                 case SIGUSR1:
722                 case SIGUSR2:
723                         sigaction(i, &sa, NULL);
724                         break;
725
726
727                     /* Default Action for all other signals */
728                 default:
729                         sigaction(i, &def_action, NULL);
730                         break;
731                 }
732         }
733
734         /*
735          * Main loop - each doio proc does this until the read returns eof (0).
736          * Call the appropriate io function based on the request type.
737          */
738
739         while ((nbytes = read(infd, (char *)&ioreq, sizeof(ioreq)))) {
740
741                 /*
742                  * Periodically check our ppid.  If it is 1, the child exits to
743                  * help clean up in the case that the main doio process was
744                  * killed.
745                  */
746
747                 if (Reqno && ((Reqno % PPID_CHECK_INTERVAL) == 0)) {
748                         if (getppid() == 1) {
749                                 doio_fprintf(stderr,
750                                              "Parent doio process has exited\n");
751                                 alloc_mem(-1);
752                                 exit(E_SETUP);
753                         }
754                 }
755
756                 if (nbytes == -1) {
757                         doio_fprintf(stderr,
758                                      "read of %d bytes from input failed:  %s (%d)\n",
759                                      sizeof(ioreq), SYSERR, errno);
760                         alloc_mem(-1);
761                         exit(E_SETUP);
762                 }
763
764                 if (nbytes != sizeof(ioreq)) {
765                         doio_fprintf(stderr,
766                                      "read wrong # bytes from input stream, expected %d, got %d\n",
767                                      sizeof(ioreq), nbytes);
768                         alloc_mem(-1);
769                         exit(E_SETUP);
770                 }
771
772                 if (ioreq.r_magic != DOIO_MAGIC) {
773                         doio_fprintf(stderr,
774                                      "got a bad magic # from input stream.  Expected 0%o, got 0%o\n",
775                                      DOIO_MAGIC, ioreq.r_magic);
776                         alloc_mem(-1);
777                         exit(E_SETUP);
778                 }
779
780                 /*
781                  * If we're on a Release_Interval multiple, relase all ssd and
782                  * core space, and close all fd's in Fd_Map[].
783                  */
784
785                 if (Reqno && Release_Interval && ! (Reqno%Release_Interval)) {
786                         if (Memsize) {
787 #ifdef NOTDEF
788                                 sbrk(-1 * Memsize);
789 #else
790                                 alloc_mem(-1);
791 #endif
792                         }
793
794 #ifdef _CRAY1
795                         if (Sdssize) {
796                                 ssbreak(-1 * btoc(Sdssize));
797                                 Sdsptr = 0;
798                                 Sdssize = 0;
799                         }
800 #endif /* _CRAY1 */
801
802                         alloc_fd(NULL, 0);
803                 }
804
805                 switch (ioreq.r_type) {
806                 case READ:
807                 case READA:
808                         rval = do_read(&ioreq);
809                         break;
810
811                 case WRITE:
812                 case WRITEA:
813                         rval = do_write(&ioreq);
814                         break;
815
816                 case READV:
817                 case AREAD:
818                 case PREAD:
819                 case LREAD:
820                 case LREADA:
821                 case LSREAD:
822                 case LSREADA:
823                 case WRITEV:
824                 case AWRITE:
825                 case PWRITE:
826                 case MMAPR:
827                 case MMAPW:
828                 case LWRITE:
829                 case LWRITEA:
830                 case LSWRITE:
831                 case LSWRITEA:
832                 case LEREAD:
833                 case LEREADA:
834                 case LEWRITE:
835                 case LEWRITEA:
836                         rval = do_rw(&ioreq);
837                         break;
838
839 #ifdef CRAY
840                 case SSREAD:
841                 case SSWRITE:
842                         rval = do_ssdio(&ioreq);
843                         break;
844
845                 case LISTIO:
846                         rval = do_listio(&ioreq);
847                         break;
848 #endif
849
850 #ifndef NO_XFS
851                 case RESVSP:
852                 case UNRESVSP:
853                         rval = do_xfsctl(&ioreq);
854                         break;
855 #endif
856
857 #ifndef CRAY
858                 case FSYNC2:
859                 case FDATASYNC:
860                         rval = do_sync(&ioreq);
861                         break;
862 #endif
863                 default:
864                         doio_fprintf(stderr,
865                                      "Don't know how to handle io request type %d\n",
866                                      ioreq.r_type);
867                         alloc_mem(-1);
868                         exit(E_SETUP);
869                 }
870
871                 if (rval == SKIP_REQ){
872                         Reqskipcnt++;
873                 }
874                 else if (rval != 0) {
875                         alloc_mem(-1);
876                         doio_fprintf(stderr,
877                                      "doio(): operation %d returned != 0\n",
878                                      ioreq.r_type);
879                         exit(E_SETUP);
880                 }
881
882                 if (Message_Interval && Reqno % Message_Interval == 0) {
883                         doio_fprintf(stderr, "Info:  %d requests done (%d skipped) by this process\n", Reqno, Reqskipcnt);
884                 }
885
886                 Reqno++;
887
888                 if(delayop != 0)
889                         doio_delay();
890         }
891
892         /*
893          * Child exits normally
894          */
895         alloc_mem(-1);
896         exit(E_NORMAL);
897
898 }  /* doio */
899
900 void
901 doio_delay()
902 {
903         struct timeval tv_delay;
904         struct sigaction sa_al, sa_old;
905         sigset_t al_mask;
906
907         switch(delayop) {
908         case DELAY_SELECT:
909                 tv_delay.tv_sec = delaytime / 1000000;
910                 tv_delay.tv_usec = delaytime % 1000000;
911                 /*doio_fprintf(stdout, "delay_select: %d %d\n", 
912                             tv_delay.tv_sec, tv_delay.tv_usec);*/
913                 select(0, NULL, NULL, NULL, &tv_delay);
914                 break;
915
916         case DELAY_SLEEP:
917                 sleep(delaytime);
918                 break;
919
920 #ifdef sgi
921         case DELAY_SGINAP:
922                 sginap(delaytime);
923                 break;
924 #endif
925
926         case DELAY_ALARM:
927                 sa_al.sa_flags = 0;
928                 sa_al.sa_handler = noop_handler;
929                 sigemptyset(&sa_al.sa_mask);
930                 sigaction(SIGALRM, &sa_al, &sa_old);
931                 sigemptyset(&al_mask);
932                 alarm(delaytime);
933                 sigsuspend(&al_mask);
934                 sigaction(SIGALRM, &sa_old, 0);
935                 break;
936         }
937 }
938
939
940 /*
941  * Format IO requests, returning a pointer to the formatted text.
942  *
943  * format_strat - formats the async i/o completion strategy
944  * format_rw    - formats a read[a]/write[a] request
945  * format_sds   - formats a ssread/sswrite request
946  * format_listio- formats a listio request
947  *
948  * ioreq is the doio io request structure.
949  */
950
951 struct smap sysnames[] = {
952         { "READ",       READ            },
953         { "WRITE",      WRITE           },
954         { "READA",      READA           },
955         { "WRITEA",     WRITEA          },
956         { "SSREAD",     SSREAD          },
957         { "SSWRITE",    SSWRITE         },
958         { "LISTIO",     LISTIO          },
959         { "LREAD",      LREAD           },
960         { "LREADA",     LREADA          },
961         { "LWRITE",     LWRITE          },
962         { "LWRITEA",    LWRITEA         },
963         { "LSREAD",     LSREAD          },
964         { "LSREADA",    LSREADA         },
965         { "LSWRITE",    LSWRITE         },
966         { "LSWRITEA",   LSWRITEA        },
967
968         /* Irix System Calls */
969         { "PREAD",      PREAD           },
970         { "PWRITE",     PWRITE          },
971         { "AREAD",      AREAD           },
972         { "AWRITE",     AWRITE          },
973         { "LLREAD",     LLREAD          },
974         { "LLAREAD",    LLAREAD         },
975         { "LLWRITE",    LLWRITE         },
976         { "LLAWRITE",   LLAWRITE        },
977         { "RESVSP",     RESVSP          },
978         { "UNRESVSP",   UNRESVSP        },
979
980         /* Irix and Linux System Calls */
981         { "READV",      READV           },
982         { "WRITEV",     WRITEV          },
983         { "MMAPR",      MMAPR           },
984         { "MMAPW",      MMAPW           },
985         { "FSYNC2",     FSYNC2          },
986         { "FDATASYNC",  FDATASYNC       },
987
988         { "unknown",    -1              },
989 };      
990
991 struct smap aionames[] = {
992         { "poll",       A_POLL          },
993         { "signal",     A_SIGNAL        },
994         { "recall",     A_RECALL        },
995         { "recalla",    A_RECALLA       },
996         { "recalls",    A_RECALLS       },
997         { "suspend",    A_SUSPEND       },
998         { "callback",   A_CALLBACK      },
999         { "synch",      0               },
1000         { "unknown",    -1              },
1001 };
1002
1003 char *
1004 format_oflags(int oflags)
1005 {
1006         char flags[255];
1007
1008
1009         flags[0]='\0';
1010         switch(oflags & 03) {
1011         case O_RDONLY:          strcat(flags,"O_RDONLY,");      break;
1012         case O_WRONLY:          strcat(flags,"O_WRONLY,");      break;
1013         case O_RDWR:            strcat(flags,"O_RDWR,");        break;
1014         default:                strcat(flags,"O_weird");        break;
1015         }
1016
1017         if(oflags & O_EXCL)
1018                 strcat(flags,"O_EXCL,");
1019
1020         if(oflags & O_SYNC)
1021                 strcat(flags,"O_SYNC,");
1022 #ifdef CRAY
1023         if(oflags & O_RAW)
1024                 strcat(flags,"O_RAW,");
1025         if(oflags & O_WELLFORMED)
1026                 strcat(flags,"O_WELLFORMED,");
1027 #ifdef O_SSD
1028         if(oflags & O_SSD)
1029                 strcat(flags,"O_SSD,");
1030 #endif
1031         if(oflags & O_LDRAW)
1032                 strcat(flags,"O_LDRAW,");
1033         if(oflags & O_PARALLEL)
1034                 strcat(flags,"O_PARALLEL,");
1035         if(oflags & O_BIG)
1036                 strcat(flags,"O_BIG,");
1037         if(oflags & O_PLACE)
1038                 strcat(flags,"O_PLACE,");
1039         if(oflags & O_ASYNC)
1040                 strcat(flags,"O_ASYNC,");
1041 #endif
1042
1043         if(oflags & O_DIRECT)
1044                 strcat(flags,"O_DIRECT,");
1045 #ifdef sgi
1046         if(oflags & O_DSYNC)
1047                 strcat(flags,"O_DSYNC,");
1048         if(oflags & O_RSYNC)
1049                 strcat(flags,"O_RSYNC,");
1050 #endif
1051
1052         return(strdup(flags));
1053 }
1054
1055 char *
1056 format_strat(int strategy)
1057 {
1058         char msg[64];
1059         char *aio_strat;
1060
1061         switch (strategy) {
1062         case A_POLL:            aio_strat = "POLL";     break;
1063         case A_SIGNAL:          aio_strat = "SIGNAL";   break;
1064         case A_RECALL:          aio_strat = "RECALL";   break;
1065         case A_RECALLA:         aio_strat = "RECALLA";  break;
1066         case A_RECALLS:         aio_strat = "RECALLS";  break;
1067         case A_SUSPEND:         aio_strat = "SUSPEND";  break;
1068         case A_CALLBACK:        aio_strat = "CALLBACK"; break;
1069         case 0:                 aio_strat = "<zero>";   break;
1070         default:
1071                 sprintf(msg, "<error:%#o>", strategy);
1072                 aio_strat = strdup(msg);
1073                 break;
1074         }
1075
1076         return(aio_strat);
1077 }
1078
1079 char *
1080 format_rw(
1081         struct  io_req  *ioreq,
1082         int             fd,
1083         void            *buffer,
1084         int             signo,
1085         char            *pattern,
1086 #ifdef CRAY
1087         struct  iosw    *iosw
1088 #else
1089         void            *iosw
1090 #endif
1091         )
1092 {
1093         static char             *errbuf=NULL;
1094         char                    *aio_strat, *cp;
1095         struct read_req         *readp = &ioreq->r_data.read;
1096         struct write_req        *writep = &ioreq->r_data.write;
1097         struct read_req         *readap = &ioreq->r_data.read;
1098         struct write_req        *writeap = &ioreq->r_data.write;
1099
1100         if(errbuf == NULL)
1101                 errbuf = (char *)malloc(32768);
1102
1103         cp = errbuf;
1104         cp += sprintf(cp, "Request number %d\n", Reqno);
1105
1106         switch (ioreq->r_type) {
1107         case READ:
1108                 cp += sprintf(cp, "syscall:  read(%d, %#lo, %d)\n",
1109                               fd, (unsigned long) buffer, readp->r_nbytes);
1110                 cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
1111                               fd, readp->r_file, readp->r_oflags);
1112                 cp += sprintf(cp, "          read done at file offset %d\n",
1113                               readp->r_offset);
1114                 break;
1115
1116         case WRITE:
1117                 cp += sprintf(cp, "syscall:  write(%d, %#lo, %d)\n",
1118                               fd, (unsigned long) buffer, writep->r_nbytes);
1119                 cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
1120                               fd, writep->r_file, writep->r_oflags);
1121                 cp += sprintf(cp, "          write done at file offset %d - pattern is %s\n",
1122                               writep->r_offset, pattern);
1123                 break;
1124
1125         case READA:
1126                 aio_strat = format_strat(readap->r_aio_strat);
1127
1128                 cp += sprintf(cp, "syscall:  reada(%d, %#lo, %d, %#lo, %d)\n",
1129                               fd, (unsigned long) buffer, readap->r_nbytes,
1130                               (unsigned long) iosw, signo);
1131                 cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
1132                               fd, readap->r_file, readp->r_oflags);
1133                 cp += sprintf(cp, "          reada done at file offset %d\n",
1134                               readap->r_offset);
1135                 cp += sprintf(cp, "          async io completion strategy is %s\n",
1136                               aio_strat);
1137                 break;
1138
1139         case WRITEA:
1140                 aio_strat = format_strat(writeap->r_aio_strat);
1141
1142                 cp += sprintf(cp, "syscall:  writea(%d, %#lo, %d, %#lo, %d)\n",
1143                               fd, (unsigned long) buffer, writeap->r_nbytes,
1144                               (unsigned long) iosw, signo);
1145                 cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
1146                               fd, writeap->r_file, writeap->r_oflags);
1147                 cp += sprintf(cp, "          writea done at file offset %d - pattern is %s\n",
1148                               writeap->r_offset, pattern);
1149                 cp += sprintf(cp, "          async io completion strategy is %s\n",
1150                               aio_strat);
1151                 break;
1152
1153         }
1154
1155         return errbuf;
1156 }
1157
1158 #ifdef CRAY
1159 char *
1160 format_sds(
1161         struct  io_req  *ioreq,
1162         void            *buffer,
1163         int             sds,
1164         char            *pattern
1165         )
1166 {
1167         int                     i;
1168         static char             *errbuf=NULL;
1169         char                    *cp;
1170
1171         struct ssread_req       *ssreadp = &ioreq->r_data.ssread;
1172         struct sswrite_req      *sswritep = &ioreq->r_data.sswrite;
1173
1174         if(errbuf == NULL)
1175                 errbuf = (char *)malloc(32768);
1176
1177         cp = errbuf;
1178         cp += sprintf(cp, "Request number %d\n", Reqno);
1179
1180
1181         switch (ioreq->r_type) {
1182         case SSREAD:
1183                 cp += sprintf(cp, "syscall:  ssread(%#o, %#o, %d)\n",
1184                               buffer, sds, ssreadp->r_nbytes);
1185                 break;
1186
1187         case SSWRITE:
1188                 cp += sprintf(cp, "syscall:  sswrite(%#o, %#o, %d) - pattern was %s\n",
1189                               buffer, sds, sswritep->r_nbytes, pattern);
1190                 break;
1191         }
1192         return errbuf;
1193 }
1194 #endif /* CRAY */
1195
1196 /*
1197  * Perform the various sorts of disk reads
1198  */
1199
1200 int
1201 do_read(req)
1202 struct io_req   *req;
1203 {
1204         int                     fd, offset, nbytes, oflags, rval;
1205         char                    *addr, *file;
1206 #ifdef CRAY
1207         struct aio_info         *aiop;
1208         int                     aio_id, aio_strat, signo;
1209 #endif
1210 #ifndef NO_XFS
1211         struct fd_cache         *fdc;
1212 #endif
1213
1214         /*
1215          * Initialize common fields - assumes r_oflags, r_file, r_offset, and
1216          * r_nbytes are at the same offset in the read_req and reada_req
1217          * structures.
1218          */
1219
1220         file = req->r_data.read.r_file;
1221         oflags = req->r_data.read.r_oflags;
1222         offset = req->r_data.read.r_offset;
1223         nbytes = req->r_data.read.r_nbytes;
1224
1225         /*printf("read: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
1226
1227         /*
1228          * Grab an open file descriptor
1229          * Note: must be done before memory allocation so that the direct i/o
1230          *      information is available in mem. allocate
1231          */
1232
1233         if ((fd = alloc_fd(file, oflags)) == -1)
1234                 return -1;
1235
1236         /*
1237          * Allocate core or sds - based on the O_SSD flag
1238          */
1239
1240 #ifndef wtob
1241 #define wtob(x) (x * sizeof(UINT64_T))
1242 #endif
1243
1244 #ifdef CRAY
1245         if (oflags & O_SSD) {
1246                 if (alloc_sds(nbytes) == -1)
1247                         return -1;
1248
1249                 addr = (char *)Sdsptr;
1250         } else {
1251                 if ((rval = alloc_mem(nbytes + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
1252                         return rval;
1253                 }
1254
1255                 addr = Memptr;
1256
1257                 /*
1258                  * if io is not raw, bump the offset by a random amount
1259                  * to generate non-word-aligned io.
1260                  */
1261                 if (! (req->r_data.read.r_uflags & F_WORD_ALIGNED)) {
1262                         addr += random_range(0, wtob(1) - 1, 1, NULL);
1263                 }
1264         }
1265 #else
1266 #ifndef NO_XFS
1267         /* get memory alignment for using DIRECT I/O */
1268         fdc = alloc_fdcache(file, oflags);
1269
1270         if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
1271                 return rval;
1272         }
1273
1274         addr = Memptr;
1275
1276
1277         if( (req->r_data.read.r_uflags & F_WORD_ALIGNED) ) {
1278                 /*
1279                  * Force memory alignment for Direct I/O
1280                  */
1281                 if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
1282                         addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
1283                 }
1284         } else {
1285                 addr += random_range(0, wtob(1) - 1, 1, NULL);
1286         }
1287 #else
1288         if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
1289                 return rval;
1290         }
1291
1292         addr = Memptr;
1293 #endif  /* !CRAY && sgi */
1294 #endif  /* CRAY */
1295
1296
1297         switch (req->r_type) {
1298         case READ:
1299                 /* move to the desired file position. */
1300                 if (lseek(fd, offset, SEEK_SET) == -1) {
1301                         doio_fprintf(stderr,
1302                                      "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
1303                                      fd, offset, SYSERR, errno);
1304                         return -1;
1305                 }
1306
1307                 if ((rval = read(fd, addr, nbytes)) == -1) {
1308                         doio_fprintf(stderr,
1309                                      "read() request failed:  %s (%d)\n%s\n",
1310                                      SYSERR, errno,
1311                                      format_rw(req, fd, addr, -1, NULL, NULL));
1312                         doio_upanic(U_RVAL);
1313                         return -1;
1314                 } else if (rval != nbytes) {
1315                         doio_fprintf(stderr,
1316                                      "read() request returned wrong # of bytes - expected %d, got %d\n%s\n",
1317                                      nbytes, rval, 
1318                                      format_rw(req, fd, addr, -1, NULL, NULL));
1319                         doio_upanic(U_RVAL);
1320                         return -1;
1321                 }
1322                 break;
1323
1324 #ifdef CRAY
1325         case READA:
1326                 /*
1327                  * Async read
1328                  */
1329
1330                 /* move to the desired file position. */
1331                 if (lseek(fd, offset, SEEK_SET) == -1) {
1332                         doio_fprintf(stderr,
1333                                      "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
1334                                      fd, offset, SYSERR, errno);
1335                         return -1;
1336                 }
1337
1338                 aio_strat = req->r_data.read.r_aio_strat;
1339                 signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
1340
1341                 aio_id = aio_register(fd, aio_strat, signo);
1342                 aiop = aio_slot(aio_id);
1343
1344                 if (reada(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
1345                         doio_fprintf(stderr, "reada() failed: %s (%d)\n%s\n",
1346                                      SYSERR, errno,
1347                                      format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
1348                         aio_unregister(aio_id);
1349                         doio_upanic(U_RVAL);
1350                         rval = -1;
1351                 } else {
1352                         /*
1353                          * Wait for io to complete
1354                          */
1355
1356                         aio_wait(aio_id);
1357
1358                         /*
1359                          * make sure the io completed without error
1360                          */
1361
1362                         if (aiop->iosw.sw_count != nbytes) {
1363                                 doio_fprintf(stderr,
1364                                              "Bad iosw from reada()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
1365                                              1, 0, nbytes,
1366                                              aiop->iosw.sw_flag,
1367                                              aiop->iosw.sw_error,
1368                                              aiop->iosw.sw_count,
1369                                      format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
1370                                 aio_unregister(aio_id);
1371                                 doio_upanic(U_IOSW);
1372                                 rval = -1;
1373                         } else {
1374                                 aio_unregister(aio_id);
1375                                 rval = 0;
1376                         }
1377                 }
1378
1379                 if (rval == -1)
1380                         return rval;
1381                 break;
1382 #endif  /* CRAY */
1383         }
1384
1385         return 0;               /* if we get here, everything went ok */
1386 }
1387
1388 /*
1389  * Perform the verious types of disk writes.
1390  */
1391
1392 int
1393 do_write(req)
1394 struct io_req   *req;
1395 {
1396         static int              pid = -1;
1397         int                     fd, nbytes, oflags;
1398         /* REFERENCED */
1399         int                     signo;
1400         int                     logged_write, rval, got_lock;
1401         long                    offset, woffset = 0;
1402         char                    *addr, pattern, *file, *msg;
1403         struct wlog_rec         wrec;
1404 #ifdef CRAY
1405         int                     aio_strat, aio_id;
1406         struct aio_info         *aiop;
1407 #endif
1408 #ifndef NO_XFS
1409         struct fd_cache         *fdc;
1410 #endif
1411
1412         /*
1413          * Misc variable setup
1414          */
1415
1416         signo   = 0;
1417         nbytes  = req->r_data.write.r_nbytes;
1418         offset  = req->r_data.write.r_offset;
1419         pattern = req->r_data.write.r_pattern;
1420         file    = req->r_data.write.r_file;
1421         oflags  = req->r_data.write.r_oflags;
1422
1423         /*printf("pwrite: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
1424
1425         /*
1426          * Allocate core memory and possibly sds space.  Initialize the data
1427          * to be written.
1428          */
1429
1430         Pattern[0] = pattern;
1431
1432
1433         /*
1434          * Get a descriptor to do the io on
1435          */
1436
1437         if ((fd = alloc_fd(file, oflags)) == -1)
1438                 return -1;
1439
1440         /*printf("write: %d, %s, %#o, %d %d\n",
1441                fd, file, oflags, offset, nbytes);*/
1442
1443         /*
1444          * Allocate SDS space for backdoor write if desired
1445          */
1446
1447 #ifdef CRAY
1448         if (oflags & O_SSD) {
1449 #ifndef _CRAYMPP
1450                 if ((rval = alloc_mem(nbytes + wtob(1))) < 0) {
1451                         return rval;
1452                 }
1453
1454                 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1455                 /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
1456
1457                 if (alloc_sds(nbytes) == -1)
1458                         return -1;
1459
1460                 if (sswrite((long)Memptr, Sdsptr, btoc(nbytes)) == -1) {
1461                         doio_fprintf(stderr, "sswrite(%d, %d, %d) failed:  %s (%d)\n",
1462                                      (long)Memptr, Sdsptr, btoc(nbytes), 
1463                                      SYSERR, errno);
1464                         fflush(stderr);
1465                         return -1;
1466                 }
1467
1468                 addr = (char *)Sdsptr;
1469 #else
1470                 doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
1471                 fflush(stderr);
1472                 return -1;
1473 #endif /* !CRAYMPP */
1474         } else {
1475                 if ((rval = alloc_mem(nbytes + wtob(1)) < 0)) {
1476                         return rval;
1477                 }
1478
1479                 addr = Memptr;
1480
1481                 /*
1482                  * if io is not raw, bump the offset by a random amount
1483                  * to generate non-word-aligned io.
1484                  */
1485
1486                 if (! (req->r_data.write.r_uflags & F_WORD_ALIGNED)) {
1487                         addr += random_range(0, wtob(1) - 1, 1, NULL);
1488                 }
1489
1490                 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1491                 if( addr != Memptr )
1492                         memmove( addr, Memptr, nbytes);
1493         }
1494 #else /* CRAY */
1495 #ifndef NO_XFS
1496         /* get memory alignment for using DIRECT I/O */
1497         fdc = alloc_fdcache(file, oflags);
1498
1499         if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
1500                 return rval;
1501         }
1502
1503         addr = Memptr;
1504
1505         if( (req->r_data.write.r_uflags & F_WORD_ALIGNED) ) {
1506                 /*
1507                  * Force memory alignment for Direct I/O
1508                  */
1509                 if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
1510                         addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
1511                 }
1512         } else {
1513                 addr += random_range(0, wtob(1) - 1, 1, NULL);
1514         }
1515
1516         (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1517         if( addr != Memptr )
1518                 memmove( addr, Memptr, nbytes);
1519
1520 #else /* sgi */
1521         if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
1522                 return rval;
1523         }
1524
1525         addr = Memptr;
1526
1527         (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
1528         if( addr != Memptr )
1529                 memmove( addr, Memptr, nbytes);
1530 #endif /* sgi */
1531 #endif /* CRAY */
1532
1533         rval = -1;
1534         got_lock = 0;
1535         logged_write = 0;
1536
1537         if (k_opt) {
1538                 if (lock_file_region(file, fd, F_WRLCK, offset, nbytes) < 0) {
1539                         alloc_mem(-1);
1540                         exit(E_INTERNAL);
1541                 }
1542
1543                 got_lock = 1;
1544         }
1545
1546         /*
1547          * Write a preliminary write-log entry.  This is done so that
1548          * doio_check can do corruption detection across an interrupt/crash.
1549          * Note that w_done is set to 0.  If doio_check sees this, it
1550          * re-creates the file extents as if the write completed, but does not
1551          * do any checking - see comments in doio_check for more details.
1552          */
1553
1554         if (w_opt) {
1555                 if (pid == -1) {
1556                         pid = getpid();
1557                 }
1558                 wrec.w_async = (req->r_type == WRITEA) ? 1 : 0;
1559                 wrec.w_oflags = oflags;
1560                 wrec.w_pid = pid;
1561                 wrec.w_offset = offset;
1562                 wrec.w_nbytes = nbytes;
1563
1564                 wrec.w_pathlen = strlen(file);
1565                 memcpy(wrec.w_path, file, wrec.w_pathlen);
1566                 wrec.w_hostlen = strlen(Host);
1567                 memcpy(wrec.w_host, Host, wrec.w_hostlen);
1568                 wrec.w_patternlen = Pattern_Length;
1569                 memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
1570
1571                 wrec.w_done = 0;
1572
1573                 if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
1574                         doio_fprintf(stderr,
1575                                      "Could not append to write-log:  %s (%d)\n",
1576                                      SYSERR, errno);
1577                 } else {
1578                         logged_write = 1;
1579                 }
1580         }
1581
1582         switch (req->r_type ) {
1583         case WRITE:
1584                 /*
1585                  * sync write
1586                  */
1587
1588                 if (lseek(fd, offset, SEEK_SET) == -1) {
1589                         doio_fprintf(stderr,
1590                                      "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
1591                                      fd, offset, SYSERR, errno);
1592                         return -1;
1593                 }
1594
1595                 rval = write(fd, addr, nbytes);
1596
1597                 if (rval == -1) {
1598                         doio_fprintf(stderr,
1599                                      "write() failed:  %s (%d)\n%s\n",
1600                                      SYSERR, errno,
1601                                      format_rw(req, fd, addr, -1, Pattern, NULL));
1602 #ifndef NO_XFS
1603                         doio_fprintf(stderr,
1604                                      "write() failed:  %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%miniou(%d)=%d, oflags=%#o memalign=%d, addr%%memalign=%d\n",
1605                                      strerror(errno),
1606                                      fd, addr, nbytes,
1607                                      offset,
1608                                      fdc->c_miniosz, nbytes%fdc->c_miniosz,
1609                                      oflags, fdc->c_memalign, (long)addr%fdc->c_memalign);
1610 #else
1611                         doio_fprintf(stderr,
1612                                      "write() failed:  %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%1B=%d, oflags=%#o\n",
1613                                      strerror(errno),
1614                                      fd, addr, nbytes,
1615                                      offset, nbytes%4096, oflags);
1616 #endif
1617                         doio_upanic(U_RVAL);
1618                 } else if (rval != nbytes) {
1619                         doio_fprintf(stderr,
1620                                      "write() returned wrong # bytes - expected %d, got %d\n%s\n",
1621                                      nbytes, rval,
1622                                      format_rw(req, fd, addr, -1, Pattern, NULL));
1623                         doio_upanic(U_RVAL);
1624                         rval = -1;
1625                 }
1626
1627                 break;
1628
1629 #ifdef CRAY
1630         case WRITEA:
1631                 /*
1632                  * async write
1633                  */
1634                 if (lseek(fd, offset, SEEK_SET) == -1) {
1635                         doio_fprintf(stderr,
1636                                      "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
1637                                      fd, offset, SYSERR, errno);
1638                         return -1;
1639                 }
1640
1641                 aio_strat = req->r_data.write.r_aio_strat;
1642                 signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
1643
1644                 aio_id = aio_register(fd, aio_strat, signo);
1645                 aiop = aio_slot(aio_id);
1646
1647                 /*
1648                  * init iosw and do the async write
1649                  */
1650
1651                 if (writea(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
1652                         doio_fprintf(stderr,
1653                                      "writea() failed: %s (%d)\n%s\n",
1654                                      SYSERR, errno,
1655                                      format_rw(req, fd, addr, -1, Pattern, NULL));
1656                         doio_upanic(U_RVAL);
1657                         aio_unregister(aio_id);
1658                         rval = -1;
1659                 } else {
1660
1661                         /*
1662                          * Wait for io to complete
1663                          */
1664
1665                         aio_wait(aio_id);
1666
1667                         /*
1668                          * check that iosw is ok
1669                          */
1670
1671                         if (aiop->iosw.sw_count != nbytes) {
1672                                 doio_fprintf(stderr,
1673                                              "Bad iosw from writea()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
1674                                              1, 0, nbytes,
1675                                              aiop->iosw.sw_flag,
1676                                              aiop->iosw.sw_error,
1677                                              aiop->iosw.sw_count,
1678                                              format_rw(req, fd, addr, -1, Pattern, &aiop->iosw));
1679                                 aio_unregister(aio_id);
1680                                 doio_upanic(U_IOSW);
1681                                 rval = -1;
1682                         } else {
1683                                 aio_unregister(aio_id);
1684                                 rval = 0;
1685                         }
1686                 }
1687                 break;
1688
1689 #endif /* CRAY */
1690         }
1691
1692         /*
1693          * Verify that the data was written correctly - check_file() returns
1694          * a non-null pointer which contains an error message if there are
1695          * problems.
1696          */
1697
1698         if (v_opt) {
1699                 msg = check_file(file, offset, nbytes, Pattern, Pattern_Length,
1700                                  0, oflags & O_PARALLEL);
1701                 if (msg != NULL) {
1702                         doio_fprintf(stderr, "%s%s\n",
1703                                      msg,
1704 #ifdef CRAY
1705                                      format_rw(req, fd, addr, -1, Pattern, &aiop->iosw)
1706 #else
1707                                      format_rw(req, fd, addr, -1, Pattern, NULL)
1708 #endif
1709                                 );
1710                         doio_upanic(U_CORRUPTION);
1711                         exit(E_COMPARE);
1712
1713                 }
1714         }
1715
1716         /*
1717          * General cleanup ...
1718          *
1719          * Write extent information to the write-log, so that doio_check can do
1720          * corruption detection.  Note that w_done is set to 1, indicating that
1721          * the write has been verified as complete.  We don't need to write the
1722          * filename on the second logging.
1723          */
1724
1725         if (w_opt && logged_write) {
1726                 wrec.w_done = 1;
1727                 wlog_record_write(&Wlog, &wrec, woffset);
1728         }
1729
1730         /*
1731          * Unlock file region if necessary
1732          */
1733
1734         if (got_lock) {
1735                 if (lock_file_region(file, fd, F_UNLCK, offset, nbytes) < 0) {
1736                         alloc_mem(-1);
1737                         exit(E_INTERNAL);
1738                 }
1739         }
1740
1741         return( (rval == -1) ? -1 : 0);
1742 }
1743
1744
1745 /*
1746  * Simple routine to lock/unlock a file using fcntl()
1747  */
1748
1749 int
1750 lock_file_region(fname, fd, type, start, nbytes)
1751 char    *fname;
1752 int     fd;
1753 int     type;
1754 int     start;
1755 int     nbytes;
1756 {
1757         struct flock    flk;
1758
1759         flk.l_type = type;
1760         flk.l_whence = 0;
1761         flk.l_start = start;
1762         flk.l_len = nbytes;
1763
1764         if (fcntl(fd, F_SETLKW, &flk) < 0) {
1765                 doio_fprintf(stderr,
1766                              "fcntl(%d, %d, %#o) failed for file %s, lock type %d, offset %d, length %d:  %s (%d), open flags: %#o\n",
1767                              fd, F_SETLKW, &flk, fname, type,
1768                              start, nbytes, SYSERR, errno,
1769                              fcntl(fd, F_GETFL, 0));
1770                 return -1;
1771         }
1772
1773         return 0;
1774 }
1775
1776 /*
1777  * Perform a listio request.
1778  */
1779
1780 #ifdef CRAY
1781 char *
1782 format_listio(
1783         struct  io_req  *ioreq,
1784         int             lcmd,
1785         struct listreq  *list,
1786         int             nent,
1787         int             fd,
1788         char            *pattern
1789         )
1790 {
1791         static  char            *errbuf=NULL;
1792         struct  listio_req      *liop = &ioreq->r_data.listio;
1793         struct  listreq         *listreq;
1794         char                    *cp, *cmd, *opcode, *aio_strat;
1795         int                     i;
1796
1797         switch (lcmd) {
1798         case LC_START:  cmd = "LC_START";       break;
1799         case LC_WAIT:   cmd = "LC_WAIT";        break;
1800         default:        cmd = "???";            break;
1801         }
1802
1803         if(errbuf == NULL)
1804                 errbuf = (char *)malloc(32768);
1805
1806         cp = errbuf;
1807         cp += sprintf(cp, "Request number %d\n", Reqno);
1808
1809         cp += sprintf(cp, "syscall:  listio(%s, %#o, %d)\n\n",
1810                       cmd, list, nent);
1811
1812         aio_strat = format_strat(liop->r_aio_strat);
1813
1814         for (i = 0; i < nent; i++) {
1815                 cp += sprintf(cp, "struct lioreq for request element %d\n", i);
1816                 cp += sprintf(cp, "----------------------------------------\n");
1817
1818                 listreq = list + i;
1819
1820                 switch (listreq->li_opcode) {
1821                 case LO_READ:   opcode = "LO_READ";     break;
1822                 case LO_WRITE:  opcode = "LO_WRITE";    break;
1823                 default:        opcode = "???";         break;
1824                 }
1825                         
1826                 cp += sprintf(cp, "          li_opcode =    %s\n", opcode);
1827                 cp += sprintf(cp, "          li_drvr =      %#o\n", listreq->li_drvr);
1828                 cp += sprintf(cp, "          li_flags =     %#o\n", listreq->li_flags);
1829                 cp += sprintf(cp, "          li_offset =    %d\n", listreq->li_offset);
1830                 cp += sprintf(cp, "          li_fildes =    %d\n", listreq->li_fildes);
1831                 cp += sprintf(cp, "          li_buf =       %#o\n", listreq->li_buf);
1832                 cp += sprintf(cp, "          li_nbyte =     %d\n", listreq->li_nbyte);
1833                 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);
1834                 cp += sprintf(cp, "          li_signo =     %d\n", listreq->li_signo);
1835                 cp += sprintf(cp, "          li_nstride =   %d\n", listreq->li_nstride);
1836                 cp += sprintf(cp, "          li_filstride = %d\n", listreq->li_filstride);
1837                 cp += sprintf(cp, "          li_memstride = %d\n", listreq->li_memstride);
1838                 cp += sprintf(cp, "          io completion strategy is %s\n", aio_strat);
1839         }
1840         return errbuf;
1841 }
1842 #endif /* CRAY */
1843
1844 int
1845 do_listio(req)
1846 struct io_req   *req;
1847 {
1848 #ifdef CRAY
1849         struct listio_req       *lio;
1850         int                     fd, oflags, signo, nb, i;
1851         int                     logged_write, rval, got_lock;
1852         int                     aio_strat, aio_id;
1853         int                     min_byte, max_byte;
1854         int                     mem_needed;
1855         int                     foffset, fstride, mstride, nstrides;
1856         char                    *moffset;
1857         long                    offset, woffset;
1858         char                    *addr, *msg;
1859         sigset_t                block_mask, omask;
1860         struct wlog_rec         wrec;
1861         struct aio_info         *aiop;
1862         struct listreq          lio_req;
1863
1864         lio = &req->r_data.listio;
1865
1866         /*
1867          * If bytes per stride is less than the stride size, drop the request
1868          * since it will cause overlapping strides, and we cannot predict
1869          * the order they will complete in.
1870          */
1871
1872         if (lio->r_filestride && abs(lio->r_filestride) < lio->r_nbytes) {
1873                 doio_fprintf(stderr, "do_listio():  Bogus listio request - abs(filestride) [%d] < nbytes [%d]\n",
1874                              abs(lio->r_filestride), lio->r_nbytes);
1875                 return -1;
1876         }
1877
1878         /*
1879          * Allocate core memory.  Initialize the data to be written.  Make
1880          * sure we get enough, based on the memstride.
1881          */
1882
1883         mem_needed = 
1884                 stride_bounds(0, lio->r_memstride, lio->r_nstrides,
1885                               lio->r_nbytes, NULL, NULL);
1886
1887         if ((rval = alloc_mem(mem_needed + wtob(1))) < 0) {
1888                 return rval;
1889         }
1890
1891         /*
1892          * Set the memory address pointer.  If the io is not raw, adjust
1893          * addr by a random amount, so that non-raw io is not necessarily
1894          * word aligned.
1895          */
1896
1897         addr = Memptr;
1898
1899         if (! (lio->r_uflags & F_WORD_ALIGNED)) {
1900                 addr += random_range(0, wtob(1) - 1, 1, NULL);
1901         }
1902
1903         if (lio->r_opcode == LO_WRITE) {
1904                 Pattern[0] = lio->r_pattern;
1905                 (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
1906                 if( addr != Memptr )
1907                         memmove( addr, Memptr, mem_needed);
1908         }
1909
1910         /*
1911          * Get a descriptor to do the io on.  No need to do an lseek, as this
1912          * is encoded in the listio request.
1913          */
1914
1915         if ((fd = alloc_fd(lio->r_file, lio->r_oflags)) == -1) {
1916                 return -1;
1917         }
1918
1919         rval = -1;
1920         got_lock = 0;
1921         logged_write = 0;
1922
1923         /*
1924          * If the opcode is LO_WRITE, lock all regions of the file that
1925          * are touched by this listio request.  Currently, we use
1926          * stride_bounds() to figure out the min and max bytes affected, and
1927          * lock the entire region, regardless of the file stride.
1928          */
1929
1930         if (lio->r_opcode == LO_WRITE && k_opt) {
1931                 stride_bounds(lio->r_offset,
1932                               lio->r_filestride, lio->r_nstrides,
1933                               lio->r_nbytes, &min_byte, &max_byte);
1934
1935                 if (lock_file_region(lio->r_file, fd, F_WRLCK,
1936                                      min_byte, (max_byte-min_byte+1)) < 0) {
1937                         doio_fprintf(stderr, "stride_bounds(%d, %d, %d, %d, ..., ...) set min_byte to %d, max_byte to %d\n",
1938                                      lio->r_offset, lio->r_filestride,
1939                                      lio->r_nstrides, lio->r_nbytes, min_byte,
1940                                      max_byte);
1941                         return -1;
1942                 } else {
1943                         got_lock = 1;
1944                 }
1945         }
1946
1947         /*
1948          * async write
1949          */
1950
1951         aio_strat = lio->r_aio_strat;
1952         signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
1953
1954         aio_id = aio_register(fd, aio_strat, signo);
1955         aiop = aio_slot(aio_id);
1956
1957         /*
1958          * Form the listio request, and make the call.
1959          */
1960
1961         lio_req.li_opcode = lio->r_opcode;
1962         lio_req.li_drvr = 0;
1963         lio_req.li_flags = LF_LSEEK;
1964         lio_req.li_offset = lio->r_offset;
1965         lio_req.li_fildes = fd;
1966
1967         if (lio->r_memstride >= 0 || lio->r_nstrides <= 1) {
1968                 lio_req.li_buf = addr;
1969         } else {
1970                 lio_req.li_buf = addr + mem_needed - lio->r_nbytes;
1971         }
1972
1973         lio_req.li_nbyte = lio->r_nbytes;
1974         lio_req.li_status = &aiop->iosw;
1975         lio_req.li_signo = signo;
1976         lio_req.li_nstride = lio->r_nstrides;
1977         lio_req.li_filstride = lio->r_filestride;
1978         lio_req.li_memstride = lio->r_memstride;
1979
1980         /*
1981          * If signo != 0, block signo while we're in the system call, so that
1982          * we don't get interrupted syscall failures.
1983          */
1984
1985         if (signo) {
1986                 sigemptyset(&block_mask);
1987                 sigaddset(&block_mask, signo);
1988                 sigprocmask(SIG_BLOCK, &block_mask, &omask);
1989         }
1990
1991         if (listio(lio->r_cmd, &lio_req, 1) < 0) {
1992                 doio_fprintf(stderr,
1993                              "listio() failed: %s (%d)\n%s\n",
1994                              SYSERR, errno,
1995                              format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
1996                 aio_unregister(aio_id);
1997                 doio_upanic(U_RVAL);
1998                 goto lio_done;
1999         }
2000
2001         if (signo) {
2002                 sigprocmask(SIG_SETMASK, &omask, NULL);
2003         }
2004
2005         /*
2006          * Wait for io to complete
2007          */
2008
2009         aio_wait(aio_id);
2010
2011         nstrides = lio->r_nstrides ? lio->r_nstrides : 1;
2012         if (aiop->iosw.sw_count != lio->r_nbytes * nstrides) {
2013                 doio_fprintf(stderr,
2014                              "Bad iosw from listio()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
2015                              1, 0, lio->r_nbytes * lio->r_nstrides,
2016                              aiop->iosw.sw_flag,
2017                              aiop->iosw.sw_error, aiop->iosw.sw_count,
2018                              format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
2019                 aio_unregister(aio_id);
2020                 doio_upanic(U_IOSW);
2021                 goto lio_done;
2022         } 
2023
2024         aio_unregister(aio_id);
2025
2026         /*
2027          * Verify that the data was written correctly - check_file() returns
2028          * a non-null pointer which contains an error message if there are
2029          * problems.
2030          *
2031          * For listio, we basically have to make 1 call to check_file for each
2032          * stride.
2033          */
2034
2035         if (v_opt && lio_req.li_opcode == LO_WRITE) {
2036                 fstride = lio->r_filestride ? lio->r_filestride : lio->r_nbytes;
2037                 mstride = lio->r_memstride ? lio->r_memstride : lio->r_nbytes;
2038                 foffset = lio->r_offset;
2039
2040                 if (mstride> 0 || lio->r_nstrides <= 1) {
2041                         moffset = addr;
2042                 } else {
2043                         moffset = addr + mem_needed - lio->r_nbytes;
2044                 }
2045
2046                 for (i = 0; i < lio_req.li_nstride; i++) {
2047                         msg = check_file(lio->r_file,
2048                                          foffset, lio->r_nbytes,
2049                                          Pattern, Pattern_Length,
2050                                          moffset - addr,
2051                                          lio->r_oflags & O_PARALLEL);
2052
2053                         if (msg != NULL) {
2054                                 doio_fprintf(stderr, "%s\n%s\n",
2055                                              msg,
2056                              format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
2057                                 doio_upanic(U_CORRUPTION);
2058                                 exit(E_COMPARE);
2059                         }
2060
2061                         moffset += mstride;
2062                         foffset += fstride;
2063                 }
2064
2065         }
2066
2067         rval = 0;
2068
2069  lio_done:
2070
2071         /*
2072          * General cleanup ...
2073          *
2074          */
2075
2076         /*
2077          * Release file locks if necessary
2078          */
2079
2080         if (got_lock) {
2081                 if (lock_file_region(lio->r_file, fd, F_UNLCK,
2082                                      min_byte, (max_byte-min_byte+1)) < 0) {
2083                         return -1;
2084                 }
2085         }
2086
2087         return rval;
2088 #else
2089         return -1;
2090 #endif
2091 }
2092
2093 /*
2094  * perform ssread/sswrite operations
2095  */
2096
2097 #ifdef _CRAY1
2098
2099 int
2100 do_ssdio(req)
2101 struct io_req   *req;
2102 {
2103         int         nbytes, nb;
2104         char    errbuf[BSIZE];
2105
2106         nbytes = req->r_data.ssread.r_nbytes;
2107
2108         /*
2109          * Grab core and sds space
2110          */
2111
2112         if ((nb = alloc_mem(nbytes)) < 0)
2113                 return nb;
2114
2115         if (alloc_sds(nbytes) == -1)
2116                 return -1;
2117
2118         if (req->r_type == SSWRITE) {
2119
2120                 /*
2121                  * Init data and ship it to the ssd
2122                  */
2123
2124                 Pattern[0] = req->r_data.sswrite.r_pattern;
2125                 /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
2126                 (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
2127
2128                 if (sswrite((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
2129                         doio_fprintf(stderr, "sswrite() failed:  %s (%d)\n%s\n",
2130                                      SYSERR, errno,
2131                                      format_sds(req, Memptr, Sdsptr, Pattern));
2132                         doio_upanic(U_RVAL);
2133                         return -1;
2134                 }
2135         } else {
2136                 /*
2137                  * read from sds
2138                  */
2139
2140                 if (ssread((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
2141                         doio_fprintf(stderr, "ssread() failed: %s (%d)\n%s\n",
2142                                      SYSERR, errno,
2143                                      format_sds(req, Memptr, Sdsptr, Pattern));
2144
2145                         doio_upanic(U_RVAL);
2146                         return -1;
2147                 }
2148         }
2149
2150         /*
2151          * Verify data if SSWRITE and v_opt
2152          */
2153
2154         if (v_opt && req->r_type == SSWRITE) {
2155                 ssread((long)Memptr, (long)Sdsptr, btoc(nbytes));
2156
2157                 if (pattern_check(Memptr, nbytes, Pattern, Pattern_Length, 0) == -1) {
2158                         doio_fprintf(stderr,
2159                                      "sds DATA COMPARE ERROR - ABORTING\n%s\n",
2160                                      format_sds(req, Memptr, Sdsptr, Pattern));
2161
2162                         doio_upanic(U_CORRUPTION);
2163                         exit(E_COMPARE);
2164                 }
2165         }
2166 }
2167
2168 #else
2169
2170 #ifdef CRAY
2171
2172 int
2173 do_ssdio(req)
2174 struct io_req   *req;
2175 {
2176         doio_fprintf(stderr,
2177                      "Internal Error - do_ssdio() called on a non-cray1 system\n");
2178         alloc_mem(-1);
2179         exit(E_INTERNAL);
2180 }
2181
2182 #endif
2183
2184 #endif /* _CRAY1 */
2185
2186 \f
2187 /* ---------------------------------------------------------------------------
2188  * 
2189  * A new paradigm of doing the r/w system call where there is a "stub"
2190  * function that builds the info for the system call, then does the system
2191  * call; this is called by code that is common to all system calls and does
2192  * the syscall return checking, async I/O wait, iosw check, etc.
2193  *
2194  * Flags:
2195  *      WRITE, ASYNC, SSD/SDS, 
2196  *      FILE_LOCK, WRITE_LOG, VERIFY_DATA,
2197  */
2198
2199 struct  status {
2200         int     rval;           /* syscall return */
2201         int     err;            /* errno */
2202         int     *aioid;         /* list of async I/O structures */
2203 };
2204
2205 struct syscall_info {
2206         char            *sy_name;
2207         int             sy_type;
2208         struct status   *(*sy_syscall)();
2209         int             (*sy_buffer)();
2210         char            *(*sy_format)();
2211         int             sy_flags;
2212         int             sy_bits;
2213 };
2214
2215 #define SY_WRITE                00001
2216 #define SY_ASYNC                00010
2217 #define SY_IOSW                 00020
2218 #define SY_SDS                  00100
2219
2220 char *
2221 fmt_ioreq(struct io_req *ioreq, struct syscall_info *sy, int fd)
2222 {
2223         static char             *errbuf=NULL;
2224         char                    *cp;
2225         struct rw_req           *io;
2226         struct smap             *aname;
2227 #ifdef CRAY
2228         struct stat             sbuf;
2229 #endif
2230
2231         if(errbuf == NULL)
2232                 errbuf = (char *)malloc(32768);
2233
2234         io = &ioreq->r_data.io;
2235
2236         /*
2237          * Look up async I/O completion strategy
2238          */
2239         for(aname=aionames;
2240             aname->value != -1 && aname->value != io->r_aio_strat;
2241             aname++)
2242                 ;
2243
2244         cp = errbuf;
2245         cp += sprintf(cp, "Request number %d\n", Reqno);
2246
2247         cp += sprintf(cp, "          fd %d is file %s - open flags are %#o %s\n",
2248                       fd, io->r_file, io->r_oflags, format_oflags(io->r_oflags));
2249
2250         if(sy->sy_flags & SY_WRITE) {
2251                 cp += sprintf(cp, "          write done at file offset %d - pattern is %c (%#o)\n",
2252                               io->r_offset,
2253                               (io->r_pattern == '\0') ? '?' : io->r_pattern, 
2254                               io->r_pattern);
2255         } else {
2256                 cp += sprintf(cp, "          read done at file offset %d\n",
2257                       io->r_offset);
2258         }
2259
2260         if(sy->sy_flags & SY_ASYNC) {
2261                 cp += sprintf(cp, "          async io completion strategy is %s\n",
2262                               aname->string);
2263         }
2264
2265         cp += sprintf(cp, "          number of requests is %d, strides per request is %d\n",
2266                       io->r_nent, io->r_nstrides);
2267
2268         cp += sprintf(cp, "          i/o byte count = %d\n",
2269                       io->r_nbytes);
2270
2271         cp += sprintf(cp, "          memory alignment is %s\n",
2272                       (io->r_uflags & F_WORD_ALIGNED) ? "aligned" : "unaligned");
2273
2274 #ifdef CRAY
2275         if(io->r_oflags & O_RAW) {
2276                 cp += sprintf(cp, "          RAW I/O: offset %% 4096 = %d length %% 4096 = %d\n",
2277                               io->r_offset % 4096, io->r_nbytes % 4096);
2278                 fstat(fd, &sbuf);
2279                 cp += sprintf(cp, "          optimal file xfer size: small: %d large: %d\n",
2280                               sbuf.st_blksize, sbuf.st_oblksize);
2281                 cp += sprintf(cp, "          cblks %d cbits %#o\n",
2282                               sbuf.st_cblks, sbuf.st_cbits);
2283         }
2284 #endif
2285 #ifndef NO_XFS
2286         if(io->r_oflags & O_DIRECT) {
2287                 struct dioattr  finfo;
2288                 
2289                 if(xfsctl(io->r_file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
2290                         cp += sprintf(cp, "          Error %s (%d) getting direct I/O info\n",
2291                                       strerror(errno), errno);
2292                         finfo.d_mem = 1;
2293                         finfo.d_miniosz = 1;
2294                         finfo.d_maxiosz = 1;
2295                 }
2296
2297                 cp += sprintf(cp, "          DIRECT I/O: offset %% %d = %d length %% %d = %d\n",
2298                               finfo.d_miniosz,
2299                               io->r_offset % finfo.d_miniosz,
2300                               io->r_nbytes,
2301                               io->r_nbytes % finfo.d_miniosz);
2302                 cp += sprintf(cp, "          mem alignment 0x%x xfer size: small: %d large: %d\n",
2303                               finfo.d_mem, finfo.d_miniosz, finfo.d_maxiosz);
2304         }
2305 #endif
2306
2307         return(errbuf);
2308 }
2309
2310 /*
2311  * Issue listio requests
2312  */
2313 #ifdef CRAY
2314 struct status *
2315 sy_listio(req, sysc, fd, addr)
2316 struct io_req   *req;
2317 struct syscall_info *sysc;
2318 int fd;
2319 char *addr;
2320 {
2321         int             offset, nbytes, nstrides, nents, aio_strat;
2322         int             aio_id, signo, o, i, lc;
2323         char            *a;
2324         struct listreq  *lio_req, *l;
2325         struct aio_info *aiop;
2326         struct status   *status;
2327
2328         /*
2329          * Initialize common fields - assumes r_oflags, r_file, r_offset, and
2330          * r_nbytes are at the same offset in the read_req and reada_req
2331          * structures.
2332          */
2333         offset    = req->r_data.io.r_offset;
2334         nbytes    = req->r_data.io.r_nbytes;
2335         nstrides  = req->r_data.io.r_nstrides;
2336         nents     = req->r_data.io.r_nent;
2337         aio_strat = req->r_data.io.r_aio_strat;
2338
2339         lc = (sysc->sy_flags & SY_ASYNC) ? LC_START : LC_WAIT;
2340
2341         status = (struct status *)malloc(sizeof(struct status));
2342         if( status == NULL ){
2343                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2344                         __FILE__, __LINE__);
2345                 return NULL;
2346         }
2347         status->aioid = (int *)malloc( (nents+1) * sizeof(int) );
2348         if( status->aioid == NULL ){
2349                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2350                         __FILE__, __LINE__);
2351                 return NULL;
2352         }
2353
2354         signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
2355
2356         lio_req = (struct listreq *)malloc(nents * sizeof(struct listreq));
2357         if( lio_req == NULL ){
2358                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2359                         __FILE__, __LINE__);
2360                 return NULL;
2361         }
2362         for(l=lio_req,a=addr,o=offset,i=0;
2363             i < nents;
2364             l++, a+=nbytes, o+=nbytes, i++) {
2365
2366                 aio_id = aio_register(fd, aio_strat, signo);
2367                 aiop = aio_slot(aio_id);
2368                 status->aioid[i] = aio_id;
2369
2370                 l->li_opcode    = (sysc->sy_flags & SY_WRITE) ? LO_WRITE : LO_READ;
2371                 l->li_offset    = o;
2372                 l->li_fildes    = fd;
2373                 l->li_buf       = a;
2374                 l->li_nbyte     = nbytes;
2375                 l->li_status    = &aiop->iosw;
2376                 l->li_signo     = signo;
2377                 l->li_nstride   = nstrides;
2378                 l->li_filstride = 0;
2379                 l->li_memstride = 0;
2380                 l->li_drvr      = 0;
2381                 l->li_flags     = LF_LSEEK;
2382         }
2383
2384         status->aioid[nents] = -1;              /* end sentinel */
2385
2386         if( (status->rval = listio(lc, lio_req, nents)) == -1) {
2387                 status->err = errno;
2388         }
2389
2390         free(lio_req);
2391         return(status);
2392 }
2393
2394 /*
2395  * Calculate the size of a request in bytes and min/max boundaries
2396  *
2397  * This assumes filestride & memstride = 0.
2398  */
2399 int
2400 listio_mem(struct io_req *req, int offset, int fmstride,
2401            int *min, int *max)
2402 {
2403         int     i, size;
2404
2405         size = stride_bounds(offset, fmstride,
2406                              req->r_data.io.r_nstrides*req->r_data.io.r_nent,
2407                              req->r_data.io.r_nbytes, min, max);
2408         return(size);
2409 }
2410
2411 char *
2412 fmt_listio(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2413 {
2414         static char     *errbuf = NULL;
2415         char            *cp;
2416         char            *c, *opcode;
2417         int             i;
2418
2419         if(errbuf == NULL){
2420                 errbuf = (char *)malloc(32768);
2421                 if( errbuf == NULL ){
2422                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2423                         __FILE__, __LINE__);
2424                         return NULL;
2425                 }
2426         }
2427
2428         c = (sy->sy_flags & SY_ASYNC) ? "lc_wait" : "lc_start";
2429
2430         cp = errbuf;
2431         cp += sprintf(cp, "syscall:  listio(%s, (?), %d)\n",
2432                       c, req->r_data.io.r_nent);
2433
2434         cp += sprintf(cp, "          data buffer at %#o\n", addr);
2435
2436         return(errbuf);
2437 }
2438 #endif /* CRAY */
2439
2440 struct status *
2441 sy_pread(req, sysc, fd, addr)
2442 struct io_req   *req;
2443 struct syscall_info *sysc;
2444 int fd;
2445 char *addr;
2446 {
2447         int rc;
2448         struct status   *status;
2449
2450         rc = pread(fd, addr, req->r_data.io.r_nbytes,
2451                    req->r_data.io.r_offset);
2452
2453         status = (struct status *)malloc(sizeof(struct status));
2454         if( status == NULL ){
2455                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2456                         __FILE__, __LINE__);
2457                 return NULL;
2458         }
2459         status->aioid = NULL;
2460         status->rval = rc;
2461         status->err = errno;
2462
2463         return(status);
2464 }
2465
2466 struct status *
2467 sy_pwrite(req, sysc, fd, addr)
2468 struct io_req   *req;
2469 struct syscall_info *sysc;
2470 int fd;
2471 char *addr;
2472 {
2473         int rc;
2474         struct status   *status;
2475
2476         rc = pwrite(fd, addr, req->r_data.io.r_nbytes,
2477                     req->r_data.io.r_offset);
2478
2479         status = (struct status *)malloc(sizeof(struct status));
2480         if( status == NULL ){
2481                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2482                         __FILE__, __LINE__);
2483                 return NULL;
2484         }
2485         status->aioid = NULL;
2486         status->rval = rc;
2487         status->err = errno;
2488
2489         return(status);
2490 }
2491
2492 char *
2493 fmt_pread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2494 {
2495         static char     *errbuf = NULL;
2496         char            *cp;
2497
2498         if(errbuf == NULL){
2499                 errbuf = (char *)malloc(32768);
2500                 if( errbuf == NULL ){
2501                         doio_fprintf(stderr, "malloc failed, %s/%d\n",
2502                                 __FILE__, __LINE__);
2503                         return NULL;
2504                 }
2505         }
2506
2507         cp = errbuf;
2508         cp += sprintf(cp, "syscall:  %s(%d, 0x%p, %d)\n",
2509                       sy->sy_name, fd, addr, req->r_data.io.r_nbytes);
2510         return(errbuf);
2511 }
2512
2513 #ifndef CRAY
2514 struct status *
2515 sy_readv(req, sysc, fd, addr)
2516 struct io_req   *req;
2517 struct syscall_info *sysc;
2518 int fd;
2519 char *addr;
2520 {
2521         struct status *sy_rwv();
2522         return sy_rwv(req, sysc, fd, addr, 0);
2523 }
2524
2525 struct status *
2526 sy_writev(req, sysc, fd, addr)
2527 struct io_req   *req;
2528 struct syscall_info *sysc;
2529 int fd;
2530 char *addr;
2531 {
2532         struct status *sy_rwv();
2533         return sy_rwv(req, sysc, fd, addr, 1);
2534 }
2535
2536 struct status *
2537 sy_rwv(req, sysc, fd, addr, rw)
2538 struct io_req   *req;
2539 struct syscall_info *sysc;
2540 int fd;
2541 char *addr;
2542 int rw;
2543 {
2544         int rc;
2545         struct status   *status;
2546         struct iovec    iov[2];
2547
2548         status = (struct status *)malloc(sizeof(struct status));
2549         if( status == NULL ){
2550                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2551                         __FILE__, __LINE__);
2552                 return NULL;
2553         }
2554         status->aioid = NULL;
2555
2556         /* move to the desired file position. */
2557         if ((rc=lseek(fd, req->r_data.io.r_offset, SEEK_SET)) == -1) {
2558                 status->rval = rc;
2559                 status->err = errno;
2560                 return(status);
2561         }
2562
2563         iov[0].iov_base = addr;
2564         iov[0].iov_len = req->r_data.io.r_nbytes;
2565
2566         if(rw)
2567                 rc = writev(fd, iov, 1);
2568         else
2569                 rc = readv(fd, iov, 1);
2570         status->aioid = NULL;
2571         status->rval = rc;
2572         status->err = errno;
2573         return(status);
2574 }
2575
2576 char *
2577 fmt_readv(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2578 {
2579         static char     errbuf[32768];
2580         char            *cp;
2581
2582         cp = errbuf;
2583         cp += sprintf(cp, "syscall:  %s(%d, (iov on stack), 1)\n",
2584                       sy->sy_name, fd);
2585         return(errbuf);
2586 }
2587 #endif /* !CRAY */
2588
2589 #ifdef sgi
2590 struct status *
2591 sy_aread(req, sysc, fd, addr)
2592 struct io_req *req;
2593 struct syscall_info *sysc;
2594 int fd;
2595 char *addr;
2596 {
2597         struct status *sy_arw();
2598         return sy_arw(req, sysc, fd, addr, 0);
2599 }
2600
2601 struct status *
2602 sy_awrite(req, sysc, fd, addr)
2603 struct io_req *req;
2604 struct syscall_info *sysc;
2605 int fd;
2606 char *addr;
2607 {
2608         struct status *sy_arw();
2609         return sy_arw(req, sysc, fd, addr, 1);
2610 }
2611
2612 /*
2613   #define sy_aread(A, B, C, D)  sy_arw(A, B, C, D, 0)
2614   #define sy_awrite(A, B, C, D) sy_arw(A, B, C, D, 1)
2615  */
2616
2617 struct status *
2618 sy_arw(req, sysc, fd, addr, rw)
2619 struct io_req *req;
2620 struct syscall_info *sysc;
2621 int fd;
2622 char *addr;
2623 int rw;
2624 {
2625         /* POSIX 1003.1b-1993 Async read */
2626         struct status           *status;
2627         int                     rc;
2628         int                     aio_id, aio_strat, signo;
2629         struct aio_info         *aiop;
2630
2631         status = (struct status *)malloc(sizeof(struct status));
2632         if( status == NULL ){
2633                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2634                         __FILE__, __LINE__);
2635                 return NULL;
2636         }
2637         aio_strat = req->r_data.io.r_aio_strat;
2638         signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
2639
2640         aio_id = aio_register(fd, aio_strat, signo);
2641         aiop = aio_slot(aio_id);
2642
2643         memset( (void *)&aiop->aiocb, 0, sizeof(aiocb_t));
2644
2645         aiop->aiocb.aio_fildes = fd;
2646         aiop->aiocb.aio_nbytes = req->r_data.io.r_nbytes;
2647         aiop->aiocb.aio_offset = req->r_data.io.r_offset;
2648         aiop->aiocb.aio_buf = addr;
2649         aiop->aiocb.aio_reqprio = 0;    /* must be 0 */
2650         aiop->aiocb.aio_lio_opcode = 0;
2651
2652         if(aio_strat == A_SIGNAL) {     /* siginfo(2) stuff */
2653                 aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
2654                 aiop->aiocb.aio_sigevent.sigev_signo = signo;
2655         } else if(aio_strat == A_CALLBACK) {
2656                 aiop->aiocb.aio_sigevent.sigev_signo = 0;
2657                 aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
2658                 aiop->aiocb.aio_sigevent.sigev_func = cb_handler;
2659                 aiop->aiocb.aio_sigevent.sigev_value.sival_int = aio_id;
2660         } else {
2661                 aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_NONE;
2662                 aiop->aiocb.aio_sigevent.sigev_signo = 0;
2663         }
2664
2665         if(rw)
2666                 rc = aio_write(&aiop->aiocb);
2667         else
2668                 rc = aio_read(&aiop->aiocb);
2669
2670         status->aioid = (int *)malloc( 2 * sizeof(int) );
2671         if( status->aioid == NULL ){
2672                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2673                         __FILE__, __LINE__);
2674                 return NULL;
2675         }
2676         status->aioid[0] = aio_id;
2677         status->aioid[1] = -1;
2678         status->rval = rc;
2679         status->err = errno;
2680         return(status);
2681 }
2682
2683 char *
2684 fmt_aread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2685 {
2686         static char     errbuf[32768];
2687         char            *cp;
2688
2689         cp = errbuf;
2690         cp += sprintf(cp, "syscall:  %s(&aiop->aiocb)\n",
2691                       sy->sy_name);
2692         return(errbuf);
2693 }
2694 #endif /* sgi */
2695
2696 #ifndef CRAY
2697
2698 struct status *
2699 sy_mmread(req, sysc, fd, addr)
2700 struct io_req *req;
2701 struct syscall_info *sysc;
2702 int fd;
2703 char *addr;
2704 {
2705         struct status *sy_mmrw();
2706         return sy_mmrw(req, sysc, fd, addr, 0);
2707 }
2708
2709 struct status *
2710 sy_mmwrite(req, sysc, fd, addr)
2711 struct io_req *req;
2712 struct syscall_info *sysc;
2713 int fd;
2714 char *addr;
2715 {
2716         struct status *sy_mmrw();
2717         return sy_mmrw(req, sysc, fd, addr, 1);
2718 }
2719
2720 struct status *
2721 sy_mmrw(req, sysc, fd, addr, rw)
2722 struct io_req *req;
2723 struct syscall_info *sysc;
2724 int fd;
2725 char *addr;
2726 int rw;
2727 {
2728         /*
2729          * mmap read/write
2730          * This version is oriented towards mmaping the file to memory
2731          * ONCE and keeping it mapped.
2732          */
2733         struct status           *status;
2734         void                    *mrc, *memaddr;
2735         struct fd_cache         *fdc;
2736         struct stat             sbuf;
2737
2738         status = (struct status *)malloc(sizeof(struct status));
2739         if( status == NULL ){
2740                 doio_fprintf(stderr, "malloc failed, %s/%d\n",
2741                         __FILE__, __LINE__);
2742                 return NULL;
2743         }
2744         status->aioid = NULL;
2745         status->rval = -1;
2746
2747         fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
2748
2749         if( fdc->c_memaddr == NULL ) {
2750                 if( fstat(fd, &sbuf) < 0 ){
2751                         doio_fprintf(stderr, "fstat failed, errno=%d\n",
2752                                      errno);
2753                         status->err = errno;
2754                         return(status);
2755                 }
2756
2757                 fdc->c_memlen = (int)sbuf.st_size;
2758                 mrc = mmap(NULL, (int)sbuf.st_size,
2759                      rw ? PROT_WRITE|PROT_READ : PROT_READ,
2760                      MAP_SHARED, fd, 0);
2761
2762                 if( mrc == MAP_FAILED ) {
2763                         doio_fprintf(stderr, "mmap() failed - 0x%lx %d\n",
2764                                 mrc, errno);
2765                         status->err = errno;
2766                         return(status);
2767                 }
2768
2769                 fdc->c_memaddr = mrc;
2770         }
2771
2772         memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
2773
2774         active_mmap_rw = 1;
2775         if(rw)
2776                 memcpy(memaddr, addr, req->r_data.io.r_nbytes);
2777         else
2778                 memcpy(addr, memaddr, req->r_data.io.r_nbytes);
2779         active_mmap_rw = 0;
2780
2781         status->rval = req->r_data.io.r_nbytes;
2782         status->err = 0;
2783         return(status);
2784 }
2785
2786 char *
2787 fmt_mmrw(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
2788 {
2789         static char     errbuf[32768];
2790         char            *cp;
2791         struct fd_cache *fdc;
2792         void            *memaddr;
2793
2794         fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
2795
2796         cp = errbuf;
2797         cp += sprintf(cp, "syscall:  %s(NULL, %d, %s, MAP_SHARED, %d, 0)\n",
2798                       sy->sy_name,
2799                       fdc->c_memlen,
2800                       (sy->sy_flags & SY_WRITE) ? "PROT_WRITE" : "PROT_READ",
2801                       fd);
2802
2803         cp += sprintf(cp, "\tfile is mmaped to: 0x%lx\n",
2804                       (unsigned long) fdc->c_memaddr);
2805
2806         memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
2807
2808         cp += sprintf(cp, "\tfile-mem=0x%lx, length=%d, buffer=0x%lx\n",
2809                       (unsigned long) memaddr, req->r_data.io.r_nbytes,
2810                       (unsigned long) addr);
2811                       
2812         return(errbuf);
2813 }
2814 #endif /* !CRAY */
2815
2816 struct syscall_info syscalls[] = {
2817 #ifdef CRAY
2818         { "listio-read-sync",           LREAD,
2819           sy_listio,    NULL,           fmt_listio,
2820           SY_IOSW
2821         },
2822         { "listio-read-strides-sync",   LSREAD,
2823           sy_listio,    listio_mem,     fmt_listio,
2824           SY_IOSW
2825         },
2826         { "listio-read-reqs-sync",      LEREAD,
2827           sy_listio,    listio_mem,     fmt_listio,
2828           SY_IOSW
2829         },
2830         { "listio-read-async",          LREADA,
2831           sy_listio,    NULL,           fmt_listio,
2832           SY_IOSW | SY_ASYNC
2833         },
2834         { "listio-read-strides-async",  LSREADA,
2835           sy_listio,    listio_mem,     fmt_listio,
2836           SY_IOSW | SY_ASYNC
2837         },
2838         { "listio-read-reqs-async",     LEREADA,
2839           sy_listio,    listio_mem,     fmt_listio,
2840           SY_IOSW | SY_ASYNC
2841         },
2842         { "listio-write-sync",          LWRITE,
2843           sy_listio,    listio_mem,     fmt_listio,
2844           SY_IOSW | SY_WRITE
2845         },
2846         { "listio-write-strides-sync",  LSWRITE,
2847           sy_listio,    listio_mem,     fmt_listio,
2848           SY_IOSW | SY_WRITE
2849         },
2850         { "listio-write-reqs-sync",     LEWRITE,
2851           sy_listio,    listio_mem,     fmt_listio,
2852           SY_IOSW | SY_WRITE
2853         },
2854         { "listio-write-async",         LWRITEA,
2855           sy_listio,    listio_mem,     fmt_listio,
2856           SY_IOSW | SY_WRITE | SY_ASYNC
2857         },
2858         { "listio-write-strides-async", LSWRITEA,
2859           sy_listio,    listio_mem,     fmt_listio,
2860           SY_IOSW | SY_WRITE | SY_ASYNC
2861         },
2862         { "listio-write-reqs-async",    LEWRITEA,
2863           sy_listio,    listio_mem,     fmt_listio,
2864           SY_IOSW | SY_WRITE | SY_ASYNC
2865         },
2866 #endif
2867
2868 #ifdef sgi
2869         { "aread",                      AREAD,
2870           sy_aread,     NULL,           fmt_aread,
2871           SY_IOSW | SY_ASYNC
2872         },
2873         { "awrite",                     AWRITE,
2874           sy_awrite,    NULL,           fmt_aread,
2875           SY_IOSW | SY_WRITE | SY_ASYNC
2876         },
2877 #endif
2878         { "pread",                      PREAD,
2879           sy_pread,     NULL,           fmt_pread,
2880           0
2881         },
2882         { "pwrite",                     PWRITE,
2883           sy_pwrite,    NULL,           fmt_pread,
2884           SY_WRITE
2885         },
2886
2887 #ifndef CRAY
2888         { "readv",                      READV,
2889           sy_readv,     NULL,           fmt_readv,
2890           0
2891         },
2892         { "writev",                     WRITEV,
2893           sy_writev,    NULL,           fmt_readv,
2894           SY_WRITE
2895         },
2896         { "mmap-read",                  MMAPR,
2897           sy_mmread,    NULL,           fmt_mmrw,
2898           0
2899         },
2900         { "mmap-write",                 MMAPW,
2901           sy_mmwrite,   NULL,           fmt_mmrw,
2902           SY_WRITE
2903         },
2904 #endif
2905
2906         { NULL,                         0,
2907           0,            0,              0,
2908           0
2909         },
2910 };
2911
2912 int
2913 do_rw(req)
2914         struct io_req   *req;
2915 {
2916         static int              pid = -1;
2917         int                     fd, offset, nbytes, nstrides, nents, oflags;
2918         int                     rval, mem_needed, i;
2919         int                     logged_write, got_lock, woffset = 0, pattern;
2920         int                     min_byte, max_byte;
2921         char                    *addr, *file, *msg;
2922         struct status           *s;
2923         struct wlog_rec         wrec;
2924         struct syscall_info     *sy;
2925 #ifdef sgi
2926         struct aio_info         *aiop;
2927 #endif
2928 #ifdef CRAY
2929         /* REFERENCED */
2930         struct iosw             *iosw;
2931 #endif
2932 #ifndef NO_XFS
2933         struct fd_cache         *fdc;
2934 #endif
2935
2936         /*
2937          * Initialize common fields - assumes r_oflags, r_file, r_offset, and
2938          * r_nbytes are at the same offset in the read_req and reada_req
2939          * structures.
2940          */
2941         file    = req->r_data.io.r_file;
2942         oflags  = req->r_data.io.r_oflags;
2943         offset  = req->r_data.io.r_offset;
2944         nbytes  = req->r_data.io.r_nbytes;
2945         nstrides= req->r_data.io.r_nstrides;
2946         nents   = req->r_data.io.r_nent;
2947         pattern = req->r_data.io.r_pattern;
2948
2949         if( nents >= MAX_AIO ) {
2950                 doio_fprintf(stderr, "do_rw: too many list requests, %d.  Maximum is %d\n",
2951                              nents, MAX_AIO);
2952                 return(-1);
2953         }
2954
2955         /*
2956          * look up system call info
2957          */
2958         for(sy=syscalls; sy->sy_name != NULL && sy->sy_type != req->r_type; sy++)
2959                 ;
2960
2961         if(sy->sy_name == NULL) {
2962                 doio_fprintf(stderr, "do_rw: unknown r_type %d.\n",
2963                              req->r_type);
2964                 return(-1);
2965         }
2966
2967         /*
2968          * Get an open file descriptor
2969          * Note: must be done before memory allocation so that the direct i/o
2970          *      information is available in mem. allocate
2971          */
2972
2973         if ((fd = alloc_fd(file, oflags)) == -1)
2974                 return -1;
2975
2976         /*
2977          * Allocate core memory and possibly sds space.  Initialize the
2978          * data to be written.  Make sure we get enough, based on the
2979          * memstride.
2980          *
2981          * need:
2982          *      1 extra word for possible partial-word address "bump"
2983          *      1 extra word for dynamic pattern overrun
2984          *      MPP_BUMP extra words for T3E non-hw-aligned memory address.
2985          */
2986
2987         if( sy->sy_buffer != NULL ) {
2988                 mem_needed = (*sy->sy_buffer)(req, 0, 0, NULL, NULL);
2989         } else {
2990                 mem_needed = nbytes;
2991         }
2992
2993 #ifdef CRAY
2994         if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
2995                 return rval;
2996         }
2997 #else
2998 #ifndef NO_XFS
2999         /* get memory alignment for using DIRECT I/O */
3000         fdc = alloc_fdcache(file, oflags);
3001
3002         if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + fdc->c_memalign)) < 0) {
3003                 return rval;
3004         }
3005 #else
3006         if ((rval = alloc_mem(mem_needed + wtob(1) * 2)) < 0) {
3007                 return rval;
3008         }
3009 #endif
3010 #endif /* CRAY */
3011
3012         Pattern[0] = pattern;
3013
3014         /*
3015          * Allocate SDS space for backdoor write if desired
3016          */
3017
3018         if (oflags & O_SSD) {
3019 #ifdef CRAY
3020 #ifndef _CRAYMPP
3021                 if (alloc_sds(nbytes) == -1)
3022                         return -1;
3023
3024                 if( sy->sy_flags & SY_WRITE ) {
3025                         /*pattern_fill(Memptr, mem_needed, Pattern, Pattern_Length, 0);*/
3026                         (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
3027
3028                         if (sswrite((long)Memptr, Sdsptr, btoc(mem_needed)) == -1) {
3029                                 doio_fprintf(stderr, "sswrite(%d, %d, %d) failed:  %s (%d)\n",
3030                                              (long)Memptr, Sdsptr, 
3031                                              btoc(mem_needed), SYSERR, errno);
3032                                 fflush(stderr);
3033                                 return -1;
3034                         }
3035                 }
3036
3037                 addr = (char *)Sdsptr;
3038 #else
3039                 doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
3040                 fflush(stderr);
3041                 return -1;
3042 #endif /* _CRAYMPP */
3043 #else   /* CRAY */
3044                 doio_fprintf(stderr, "Invalid O_SSD flag was generated for non-Cray system\n");
3045                 fflush(stderr);
3046                 return -1;
3047 #endif  /* CRAY */
3048         } else {
3049                 addr = Memptr;
3050
3051                 /*
3052                  * if io is not raw, bump the offset by a random amount
3053                  * to generate non-word-aligned io.
3054                  *
3055                  * On MPP systems, raw I/O must start on an 0x80 byte boundary.
3056                  * For non-aligned I/O, bump the address from 1 to 8 words.
3057                  */
3058
3059                 if (! (req->r_data.io.r_uflags & F_WORD_ALIGNED)) {
3060 #ifdef _CRAYMPP
3061                         addr += random_range(0, MPP_BUMP, 1, NULL) * sizeof(int);
3062 #endif
3063                         addr += random_range(0, wtob(1) - 1, 1, NULL);
3064                 }
3065
3066 #ifndef NO_XFS
3067                 /*
3068                  * Force memory alignment for Direct I/O
3069                  */
3070                 if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
3071                         addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
3072                 }
3073 #endif
3074
3075                 /*
3076                  * FILL must be done on a word-aligned buffer.
3077                  * Call the fill function with Memptr which is aligned,
3078                  * then memmove it to the right place.
3079                  */
3080                 if (sy->sy_flags & SY_WRITE) {
3081                         (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
3082                         if( addr != Memptr )
3083                             memmove( addr, Memptr, mem_needed);
3084                 }
3085         }
3086
3087         rval = 0;
3088         got_lock = 0;
3089         logged_write = 0;
3090
3091         /*
3092          * Lock data if this is a write and locking option is set
3093          */
3094         if (sy->sy_flags & SY_WRITE && k_opt) {
3095                 if( sy->sy_buffer != NULL ) {
3096                         (*sy->sy_buffer)(req, offset, 0, &min_byte, &max_byte);
3097                 } else {
3098                         min_byte = offset;
3099                         max_byte = offset + (nbytes * nstrides * nents);
3100                 }
3101
3102                 if (lock_file_region(file, fd, F_WRLCK,
3103                                      min_byte, (max_byte-min_byte+1)) < 0) {
3104                     doio_fprintf(stderr, 
3105                                 "file lock failed:\n%s\n",
3106                                 fmt_ioreq(req, sy, fd));
3107                     doio_fprintf(stderr, 
3108                                 "          buffer(req, %d, 0, 0x%x, 0x%x)\n",
3109                                 offset, min_byte, max_byte);
3110                     alloc_mem(-1);
3111                     exit(E_INTERNAL);
3112                 }
3113
3114                 got_lock = 1;
3115         }
3116
3117         /*
3118          * Write a preliminary write-log entry.  This is done so that
3119          * doio_check can do corruption detection across an interrupt/crash.
3120          * Note that w_done is set to 0.  If doio_check sees this, it
3121          * re-creates the file extents as if the write completed, but does not
3122          * do any checking - see comments in doio_check for more details.
3123          */
3124
3125         if (sy->sy_flags & SY_WRITE && w_opt) {
3126                 if (pid == -1) {
3127                         pid = getpid();
3128                 }
3129
3130                 wrec.w_async = (sy->sy_flags & SY_ASYNC) ? 1 : 0;
3131                 wrec.w_oflags = oflags;
3132                 wrec.w_pid = pid;
3133                 wrec.w_offset = offset;
3134                 wrec.w_nbytes = nbytes; /* mem_needed -- total length */
3135
3136                 wrec.w_pathlen = strlen(file);
3137                 memcpy(wrec.w_path, file, wrec.w_pathlen);
3138                 wrec.w_hostlen = strlen(Host);
3139                 memcpy(wrec.w_host, Host, wrec.w_hostlen);
3140                 wrec.w_patternlen = Pattern_Length;
3141                 memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
3142
3143                 wrec.w_done = 0;
3144
3145                 if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
3146                         doio_fprintf(stderr,
3147                                      "Could not append to write-log:  %s (%d)\n",
3148                                      SYSERR, errno);
3149                 } else {
3150                         logged_write = 1;
3151                 }
3152         }
3153
3154         s = (*sy->sy_syscall)(req, sy, fd, addr);
3155
3156         if( s->rval == -1 ) {
3157                 doio_fprintf(stderr,
3158                              "%s() request failed:  %s (%d)\n%s\n%s\n",
3159                              sy->sy_name, SYSERR, errno,
3160                              fmt_ioreq(req, sy, fd),
3161                              (*sy->sy_format)(req, sy, fd, addr));
3162
3163                 doio_upanic(U_RVAL);
3164
3165                 for(i=0; i < nents; i++) {
3166                         if(s->aioid == NULL)
3167                                 break;
3168                         aio_unregister(s->aioid[i]);
3169                 }
3170                 rval = -1;
3171         } else {
3172                 /*
3173                  * If the syscall was async, wait for I/O to complete
3174                  */
3175 #ifndef linux
3176                 if(sy->sy_flags & SY_ASYNC) {
3177                         for(i=0; i < nents; i++) {
3178                                 aio_wait(s->aioid[i]);
3179                         }
3180                 }
3181 #endif
3182
3183                 /*
3184                  * Check the syscall how-much-data-written return.  Look
3185                  * for this in either the return value or the 'iosw'
3186                  * structure.
3187                  */
3188
3189                 if( sy->sy_flags & SY_IOSW ) {
3190 #ifdef CRAY
3191                         for( i=0; i < nents; i++ ) {
3192                                 if(s->aioid == NULL)
3193                                         break; /* >>> error condition? */
3194                                 aiop = aio_slot(s->aioid[i]);
3195                                 iosw = &aiop->iosw;
3196                                 if(iosw->sw_error != 0) {
3197                                         doio_fprintf(stderr,
3198                                                      "%s() iosw error set: %s\n%s\n%s\n",
3199                                                      sy->sy_name,
3200                                                      strerror(iosw->sw_error),
3201                                                      fmt_ioreq(req, sy, fd),
3202                                                      (*sy->sy_format)(req, sy, fd, addr));
3203                                         doio_upanic(U_IOSW);
3204                                         rval = -1;
3205                                 } else if(iosw->sw_count != nbytes*nstrides) {
3206                                         doio_fprintf(stderr,
3207                                                      "Bad iosw from %s() #%d\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n%s\n",
3208                                                      sy->sy_name, i,
3209                                                      1, 0, nbytes*nstrides,
3210                                                      iosw->sw_flag,
3211                                                      iosw->sw_error,
3212                                                      iosw->sw_count,
3213                                                      fmt_ioreq(req, sy, fd),
3214                                                      (*sy->sy_format)(req, sy, fd, addr));
3215                                         doio_upanic(U_IOSW);
3216                                         rval = -1;
3217                                 }
3218
3219                                 aio_unregister(s->aioid[i]);
3220                         }
3221 #endif /* CRAY */
3222 #ifdef sgi
3223                         for( i=0; s->aioid[i] != -1; i++ ) {
3224                                 if(s->aioid == NULL) {
3225                                         doio_fprintf(stderr,
3226                                                      "aioid == NULL!\n");
3227                                         break;
3228                                 }
3229                                 aiop = aio_slot(s->aioid[i]);
3230
3231                                 /*
3232                                  * make sure the io completed without error
3233                                  */
3234                                 if (aiop->aio_errno != 0) {
3235                                         doio_fprintf(stderr,
3236                                                      "%s() aio error set: %s (%d)\n%s\n%s\n",
3237                                                      sy->sy_name,
3238                                                      strerror(aiop->aio_errno),
3239                                                      aiop->aio_errno,
3240                                                      fmt_ioreq(req, sy, fd),
3241                                                      (*sy->sy_format)(req, sy, fd, addr));
3242                                         doio_upanic(U_IOSW);
3243                                         rval = -1;
3244                                 } else if (aiop->aio_ret != nbytes) {
3245                                         doio_fprintf(stderr,
3246                                                      "Bad aio return from %s() #%d\nExpected (%d,%d), got (%d,%d)\n%s\n%s\n",
3247                                                      sy->sy_name, i,
3248                                                      0, nbytes,
3249                                                      aiop->aio_errno,
3250                                                      aiop->aio_ret,
3251                                                      fmt_ioreq(req, sy, fd),
3252                                                      (*sy->sy_format)(req, sy, fd, addr));
3253                                         aio_unregister(s->aioid[i]);
3254                                         doio_upanic(U_IOSW);
3255                                         return -1;
3256                                 } else {
3257                                         aio_unregister(s->aioid[i]);
3258                                         rval = 0;
3259                                 }
3260                         }
3261 #endif /* sgi */
3262                 } else {
3263
3264                         if(s->rval != mem_needed) {
3265                                 doio_fprintf(stderr,
3266                                              "%s() request returned wrong # of bytes - expected %d, got %d\n%s\n%s\n",
3267                                              sy->sy_name, nbytes, s->rval,
3268                                              fmt_ioreq(req, sy, fd),
3269                                              (*sy->sy_format)(req, sy, fd, addr));
3270                                 rval = -1;
3271                                 doio_upanic(U_RVAL);
3272                         }
3273                 }
3274         }
3275
3276
3277         /*
3278          * Verify that the data was written correctly - check_file() returns
3279          * a non-null pointer which contains an error message if there are
3280          * problems.
3281          */
3282
3283         if ( rval == 0 && sy->sy_flags & SY_WRITE && v_opt) {
3284                 msg = check_file(file, offset, nbytes*nstrides*nents,
3285                                  Pattern, Pattern_Length, 0,
3286                                  oflags & O_PARALLEL);
3287                 if (msg != NULL) {
3288                         doio_fprintf(stderr, "%s\n%s\n%s\n",
3289                                      msg,
3290                                      fmt_ioreq(req, sy, fd),
3291                                      (*sy->sy_format)(req, sy, fd, addr));
3292                         doio_upanic(U_CORRUPTION);
3293                         exit(E_COMPARE);
3294                 }
3295         }
3296
3297         /*
3298          * General cleanup ...
3299          *
3300          * Write extent information to the write-log, so that doio_check can do
3301          * corruption detection.  Note that w_done is set to 1, indicating that
3302          * the write has been verified as complete.  We don't need to write the
3303          * filename on the second logging.
3304          */
3305
3306         if (w_opt && logged_write) {
3307                 wrec.w_done = 1;
3308                 wlog_record_write(&Wlog, &wrec, woffset);
3309         }
3310
3311         /*
3312          * Unlock file region if necessary
3313          */
3314
3315         if (got_lock) {
3316                 if (lock_file_region(file, fd, F_UNLCK,
3317                                      min_byte, (max_byte-min_byte+1)) < 0) {
3318                         alloc_mem(-1);
3319                         exit(E_INTERNAL);
3320                 }
3321         }
3322
3323         if(s->aioid != NULL)
3324                 free(s->aioid);
3325         free(s);
3326         return (rval == -1) ? -1 : 0;
3327 }
3328
3329
3330 /*
3331  * xfsctl-based requests
3332  *   - XFS_IOC_RESVSP
3333  *   - XFS_IOC_UNRESVSP
3334  */
3335 #ifndef NO_XFS
3336 int
3337 do_xfsctl(req)
3338         struct io_req   *req;
3339 {
3340         int                     fd, oflags, offset, nbytes;
3341         int                     rval, op = 0;
3342         int                     got_lock;
3343         int                     min_byte = 0, max_byte = 0;
3344         char                    *file, *msg = NULL;
3345         struct xfs_flock64      flk;
3346
3347         /*
3348          * Initialize common fields - assumes r_oflags, r_file, r_offset, and
3349          * r_nbytes are at the same offset in the read_req and reada_req
3350          * structures.
3351          */
3352         file    = req->r_data.io.r_file;
3353         oflags  = req->r_data.io.r_oflags;
3354         offset  = req->r_data.io.r_offset;
3355         nbytes  = req->r_data.io.r_nbytes;
3356
3357         flk.l_type=0;
3358         flk.l_whence=SEEK_SET;
3359         flk.l_start=offset;
3360         flk.l_len=nbytes;
3361
3362         /*
3363          * Get an open file descriptor
3364          */
3365
3366         if ((fd = alloc_fd(file, oflags)) == -1)
3367                 return -1;
3368
3369         rval = 0;
3370         got_lock = 0;
3371
3372         /*
3373          * Lock data if this is locking option is set
3374          */
3375         if (k_opt) {
3376                 min_byte = offset;
3377                 max_byte = offset + nbytes;
3378
3379                 if (lock_file_region(file, fd, F_WRLCK,
3380                                      min_byte, (nbytes+1)) < 0) {
3381                     doio_fprintf(stderr, 
3382                                 "file lock failed:\n");
3383                     doio_fprintf(stderr, 
3384                                 "          buffer(req, %d, 0, 0x%x, 0x%x)\n",
3385                                 offset, min_byte, max_byte);
3386                     alloc_mem(-1);
3387                     exit(E_INTERNAL);
3388                 }
3389
3390                 got_lock = 1;
3391         }
3392
3393         switch (req->r_type) {
3394         case RESVSP:    op=XFS_IOC_RESVSP;      msg="resvsp";   break;
3395         case UNRESVSP:  op=XFS_IOC_UNRESVSP;    msg="unresvsp"; break;
3396         }
3397
3398         rval = xfsctl(file, fd, op, &flk);
3399
3400         if( rval == -1 ) {
3401                 doio_fprintf(stderr,
3402 "xfsctl %s request failed: %s (%d)\n\txfsctl(%d, %s %d, {%d %lld ==> %lld}\n",
3403                              msg, SYSERR, errno,
3404                              fd, msg, op, flk.l_whence, 
3405                              (long long)flk.l_start, 
3406                              (long long)flk.l_len);
3407
3408                 doio_upanic(U_RVAL);
3409                 rval = -1;
3410         }
3411
3412         /*
3413          * Unlock file region if necessary
3414          */
3415
3416         if (got_lock) {
3417                 if (lock_file_region(file, fd, F_UNLCK,
3418                                      min_byte, (max_byte-min_byte+1)) < 0) {
3419                         alloc_mem(-1);
3420                         exit(E_INTERNAL);
3421                 }
3422         }
3423
3424         return (rval == -1) ? -1 : 0;
3425 }
3426 #endif
3427
3428 /*
3429  *  fsync(2) and fdatasync(2)
3430  */
3431 #ifndef CRAY
3432 int
3433 do_sync(req)
3434         struct io_req   *req;
3435 {
3436         int                     fd, oflags;
3437         int                     rval;
3438         char                    *file;
3439
3440         /*
3441          * Initialize common fields - assumes r_oflags, r_file, r_offset, and
3442          * r_nbytes are at the same offset in the read_req and reada_req
3443          * structures.
3444          */
3445         file    = req->r_data.io.r_file;
3446         oflags  = req->r_data.io.r_oflags;
3447
3448         /*
3449          * Get an open file descriptor
3450          */
3451
3452         if ((fd = alloc_fd(file, oflags)) == -1)
3453                 return -1;
3454
3455         rval = 0;
3456         switch(req->r_type) {
3457         case FSYNC2:
3458                 rval = fsync(fd);
3459                 break;
3460         case FDATASYNC:
3461                 rval = fdatasync(fd);
3462                 break;
3463         default:
3464                 rval = -1;
3465         }
3466         return (rval == -1) ? -1 : 0;
3467 }
3468 #endif
3469
3470
3471 int
3472 doio_pat_fill(char *addr, int mem_needed, char *Pattern, int Pattern_Length,
3473               int shift)
3474 {
3475         return pattern_fill(addr, mem_needed, Pattern, Pattern_Length, 0);
3476 }
3477
3478 char *
3479 doio_pat_check(buf, offset, length, pattern, pattern_length, patshift)
3480 char    *buf;
3481 int     offset;
3482 int     length;
3483 char    *pattern;
3484 int     pattern_length;
3485 int     patshift;
3486 {
3487         static char     errbuf[4096];
3488         int             nb, i, pattern_index;
3489         char            *cp, *bufend, *ep;
3490         char            actual[33], expected[33];
3491
3492         if (pattern_check(buf, length, pattern, pattern_length, patshift) != 0) {
3493                 ep = errbuf;
3494                 ep += sprintf(ep, "Corrupt regions follow - unprintable chars are represented as '.'\n");
3495                 ep += sprintf(ep, "-----------------------------------------------------------------\n");
3496
3497                 pattern_index = patshift % pattern_length;;
3498                 cp = buf;
3499                 bufend = buf + length;
3500
3501                 while (cp < bufend) {
3502                         if (*cp != pattern[pattern_index]) {
3503                                 nb = bufend - cp;
3504                                 if (nb > sizeof(expected)-1) {
3505                                         nb = sizeof(expected)-1;
3506                                 }
3507                             
3508                                 ep += sprintf(ep, "corrupt bytes starting at file offset %d\n", offset + (int)(cp-buf));
3509
3510                                 /*
3511                                  * Fill in the expected and actual patterns
3512                                  */
3513                                 bzero(expected, sizeof(expected));
3514                                 bzero(actual, sizeof(actual));
3515
3516                                 for (i = 0; i < nb; i++) {
3517                                         expected[i] = pattern[(pattern_index + i) % pattern_length];
3518                                         if (! isprint((int)expected[i])) {
3519                                                 expected[i] = '.';
3520                                         }
3521
3522                                         actual[i] = cp[i];
3523                                         if (! isprint((int)actual[i])) {
3524                                                 actual[i] = '.';
3525                                         }
3526                                 }
3527
3528                                 ep += sprintf(ep, "    1st %2d expected bytes:  %s\n", nb, expected);
3529                                 ep += sprintf(ep, "    1st %2d actual bytes:    %s\n", nb, actual);
3530                                 fflush(stderr);
3531                                 return errbuf;
3532                         } else {
3533                                 cp++;
3534                                 pattern_index++;
3535
3536                                 if (pattern_index == pattern_length) {
3537                                         pattern_index = 0;
3538                                 }
3539                         }
3540                 }
3541                 return errbuf;
3542         }
3543
3544         return(NULL);
3545 }
3546
3547
3548 /*
3549  * Check the contents of a file beginning at offset, for length bytes.  It
3550  * is assumed that there is a string of pattern bytes in this area of the
3551  * file.  Use normal buffered reads to do the verification.
3552  *
3553  * If there is a data mismatch, write a detailed message into a static buffer
3554  * suitable for the caller to print.  Otherwise print NULL.
3555  *
3556  * The fsa flag is set to non-zero if the buffer should be read back through
3557  * the FSA (unicos/mk).  This implies the file will be opened
3558  * O_PARALLEL|O_RAW|O_WELLFORMED to do the validation.  We must do this because
3559  * FSA will not allow the file to be opened for buffered io if it was
3560  * previously opened for O_PARALLEL io.
3561  */
3562
3563 char *
3564 check_file(file, offset, length, pattern, pattern_length, patshift, fsa)
3565 char    *file;
3566 int     offset;
3567 int     length;
3568 char    *pattern;
3569 int     pattern_length;
3570 int     patshift;
3571 int     fsa;
3572 {
3573         static char     errbuf[4096];
3574         int             fd, nb, flags;
3575         char            *buf, *em, *ep;
3576 #ifndef NO_XFS
3577         struct fd_cache *fdc;
3578 #endif
3579
3580         buf = Memptr;
3581
3582         if (V_opt) {
3583                 flags = Validation_Flags | O_RDONLY;
3584         } else {
3585                 flags = O_RDONLY;
3586                 if (fsa) {
3587 #ifdef CRAY
3588                         flags |= O_PARALLEL | O_RAW | O_WELLFORMED;
3589 #endif
3590                 }
3591         }
3592
3593         if ((fd = alloc_fd(file, flags)) == -1) {
3594                 sprintf(errbuf,
3595                         "Could not open file %s with flags %#o (%s) for data comparison:  %s (%d)\n",
3596                         file, flags, format_oflags(flags),
3597                         SYSERR, errno);
3598                 return errbuf;
3599         }
3600
3601         if (lseek(fd, offset, SEEK_SET) == -1) {
3602                 sprintf(errbuf, 
3603                         "Could not lseek to offset %d in %s for verification:  %s (%d)\n",
3604                         offset, file, SYSERR, errno);
3605                 return errbuf;
3606         }
3607
3608 #ifndef NO_XFS
3609         /* Guarantee a properly aligned address on Direct I/O */
3610         fdc = alloc_fdcache(file, flags);
3611         if( (flags & O_DIRECT) && ((long)buf % fdc->c_memalign != 0) ) {
3612                 buf += fdc->c_memalign - ((long)buf % fdc->c_memalign);
3613         }
3614 #endif
3615
3616         if ((nb = read(fd, buf, length)) == -1) {
3617 #ifndef NO_XFS
3618                 sprintf(errbuf,
3619                         "Could not read %d bytes from %s for verification:  %s (%d)\n\tread(%d, 0x%p, %d)\n\tbuf %% alignment(%d) = %ld\n",
3620                         length, file, SYSERR, errno,
3621                         fd, buf, length,
3622                         fdc->c_memalign, (long)buf % fdc->c_memalign);
3623 #else
3624                 sprintf(errbuf,
3625                         "Could not read %d bytes from %s for verification:  %s (%d)\n",
3626                         length, file, SYSERR, errno);
3627
3628 #endif
3629                 return errbuf;
3630         }
3631
3632         if (nb != length) {
3633                 sprintf(errbuf,
3634                         "Read wrong # bytes from %s.  Expected %d, got %d\n",
3635                         file, length, nb);
3636                 return errbuf;
3637         }
3638     
3639         if( (em = (*Data_Check)(buf, offset, length, pattern, pattern_length, patshift)) != NULL ) {
3640                 ep = errbuf;
3641                 ep += sprintf(ep, "*** DATA COMPARISON ERROR ***\n");
3642                 ep += sprintf(ep, "check_file(%s, %d, %d, %s, %d, %d) failed\n\n",
3643                               file, offset, length, pattern, pattern_length, patshift);
3644                 ep += sprintf(ep, "Comparison fd is %d, with open flags %#o\n",
3645                               fd, flags);
3646                 strcpy(ep, em);
3647                 return(errbuf);
3648         }
3649         return NULL;
3650 }
3651
3652 /*
3653  * Function to single-thread stdio output.
3654  */
3655
3656 int
3657 doio_fprintf(FILE *stream, char *format, ...)
3658 {
3659         static int      pid = -1;
3660         char            *date;
3661         int             rval;
3662         struct flock    flk;
3663         va_list         arglist;
3664
3665         date = hms(time(0));
3666
3667         if (pid == -1) {
3668                 pid = getpid();
3669         }
3670
3671         flk.l_whence = flk.l_start = flk.l_len = 0;
3672         flk.l_type = F_WRLCK;
3673         fcntl(fileno(stream), F_SETLKW, &flk);
3674
3675         va_start(arglist, format);
3676         rval = fprintf(stream, "\n%s%s (%5d) %s\n", Prog, TagName, pid, date);
3677         rval += fprintf(stream, "---------------------\n");
3678         vfprintf(stream, format, arglist);
3679         va_end(arglist);
3680
3681         fflush(stream);
3682
3683         flk.l_type = F_UNLCK;
3684         fcntl(fileno(stream), F_SETLKW, &flk);
3685  
3686         return rval;
3687 }
3688
3689 /*
3690  * Simple function for allocating core memory.  Uses Memsize and Memptr to
3691  * keep track of the current amount allocated.
3692  */
3693 #ifndef CRAY
3694 int
3695 alloc_mem(nbytes)
3696 int nbytes;
3697 {
3698         char            *cp;
3699         void            *addr;
3700         int             me = 0, flags, key, shmid;
3701         static int      mturn = 0;      /* which memory type to use */
3702         struct memalloc *M;
3703         char            filename[255];
3704 #ifdef linux
3705         struct shmid_ds shm_ds;
3706 #endif
3707
3708 #ifdef linux
3709         bzero( &shm_ds, sizeof(struct shmid_ds) );
3710 #endif
3711
3712         /* nbytes = -1 means "free all allocated memory" */
3713         if( nbytes == -1 ) {
3714
3715                 for(me=0; me < Nmemalloc; me++) {
3716                         if(Memalloc[me].space == NULL)
3717                                 continue;
3718
3719                         switch(Memalloc[me].memtype) {
3720                         case MEM_DATA:
3721 #ifdef sgi
3722                                 if(Memalloc[me].flags & MEMF_MPIN)
3723                                         munpin(Memalloc[me].space,
3724                                                Memalloc[me].size);
3725 #endif
3726                                 free(Memalloc[me].space);
3727                                 Memalloc[me].space = NULL;
3728                                 Memptr = NULL;
3729                                 Memsize = 0;
3730                                 break;
3731                         case MEM_SHMEM:
3732 #ifdef sgi
3733                                 if(Memalloc[me].flags & MEMF_MPIN)
3734                                         munpin(Memalloc[me].space,
3735                                                Memalloc[me].size);
3736 #endif
3737                                 shmdt(Memalloc[me].space);
3738                                 Memalloc[me].space = NULL;
3739 #ifdef sgi
3740                                 shmctl(Memalloc[me].fd, IPC_RMID);
3741 #else
3742                                 shmctl(Memalloc[me].fd, IPC_RMID, &shm_ds);
3743 #endif
3744                                 break;
3745                         case MEM_MMAP:
3746 #ifdef sgi
3747                                 if(Memalloc[me].flags & MEMF_MPIN)
3748                                         munpin(Memalloc[me].space,
3749                                                Memalloc[me].size);
3750 #endif
3751                                 munmap(Memalloc[me].space, 
3752                                        Memalloc[me].size);
3753                                 close(Memalloc[me].fd);
3754                                 if(Memalloc[me].flags & MEMF_FILE) {
3755                                         unlink(Memalloc[me].name);
3756                                 }
3757                                 Memalloc[me].space = NULL;
3758                                 break;
3759                         default:
3760                                 doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
3761                                              Memalloc[me].memtype, me);
3762                                 break;
3763                         }
3764                 }
3765                 return 0;
3766         }
3767
3768         /*
3769          * Select a memory area (currently round-robbin)
3770          */
3771
3772         if(mturn >= Nmemalloc)
3773                 mturn=0;
3774
3775         M = &Memalloc[mturn];
3776
3777         switch(M->memtype) {
3778         case MEM_DATA:
3779                 if( nbytes > M->size ) {
3780                         if( M->space != NULL ){
3781 #ifdef sgi
3782                                 if( M->flags & MEMF_MPIN )
3783                                         munpin( M->space, M->size );
3784 #endif
3785                                 free(M->space);
3786                         }
3787                         M->space = NULL;
3788                         M->size = 0;
3789                 }
3790
3791                 if( M->space == NULL ) {
3792                         if( (cp = malloc( nbytes )) == NULL ) {
3793                                 doio_fprintf(stderr, "malloc(%d) failed:  %s (%d)\n",
3794                                              nbytes, SYSERR, errno);
3795                                 return -1;
3796                         }
3797 #ifdef sgi
3798                         if(M->flags & MEMF_MPIN) {
3799                                 if( mpin(cp, nbytes) == -1 ) {
3800                                         doio_fprintf(stderr, "mpin(0x%lx, %d) failed:  %s (%d)\n",
3801                                              cp, nbytes, SYSERR, errno);
3802                                 }
3803                         }
3804 #endif
3805                         M->space = (void *)cp;
3806                         M->size = nbytes;
3807                 }
3808                 break;
3809
3810         case MEM_MMAP:
3811                 if( nbytes > M->size ) {
3812                         if( M->space != NULL ) {
3813 #ifdef sgi
3814                                 if( M->flags & MEMF_MPIN )
3815                                         munpin(M->space, M->size);
3816 #endif
3817                                 munmap(M->space, M->size);
3818                                 close(M->fd);
3819                                 if( M->flags & MEMF_FILE )
3820                                         unlink( M->name );
3821                         }
3822                         M->space = NULL;
3823                         M->size = 0;
3824                 }
3825
3826                 if( M->space == NULL ) {
3827                         if(strchr(M->name, '%')) {
3828                                 sprintf(filename, M->name, getpid());
3829                                 M->name = strdup(filename);
3830                         }
3831
3832                         if( (M->fd = open(M->name, O_CREAT|O_RDWR, 0666)) == -1) {
3833                                 doio_fprintf(stderr, "alloc_mmap: error %d (%s) opening '%s'\n",
3834                                              errno, SYSERR, 
3835                                              M->name);
3836                                 return(-1);
3837                         }
3838
3839                         addr = NULL;
3840                         flags = 0;
3841                         M->size = nbytes * 4;
3842
3843                         /* bias addr if MEMF_ADDR | MEMF_FIXADDR */
3844                         /* >>> how to pick a memory address? */
3845
3846                         /* bias flags on MEMF_PRIVATE etc */
3847                         if(M->flags & MEMF_PRIVATE)
3848                                 flags |= MAP_PRIVATE;
3849 #ifdef sgi
3850                         if(M->flags & MEMF_LOCAL)
3851                                 flags |= MAP_LOCAL;
3852                         if(M->flags & MEMF_AUTORESRV)
3853                                 flags |= MAP_AUTORESRV;
3854                         if(M->flags & MEMF_AUTOGROW)
3855                                 flags |= MAP_AUTOGROW;
3856 #endif
3857                         if(M->flags & MEMF_SHARED)
3858                                 flags |= MAP_SHARED;
3859
3860 /*printf("alloc_mem, about to mmap, fd=%d, name=(%s)\n", M->fd, M->name);*/
3861                         if( (M->space = mmap(addr, M->size,
3862                                              PROT_READ|PROT_WRITE,
3863                                              flags, M->fd, 0))
3864                             == MAP_FAILED) {
3865                                 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",
3866                                              errno, SYSERR,
3867                                              addr, M->size,
3868                                              PROT_READ|PROT_WRITE,
3869                                              flags, M->flags, M->fd,
3870                                              M->name);
3871                                 doio_fprintf(stderr, "\t%s%s%s%s%s",
3872                                              (flags & MAP_PRIVATE) ? "private " : "",
3873 #ifdef sgi
3874                                              (flags & MAP_LOCAL) ? "local " : "",
3875                                              (flags & MAP_AUTORESRV) ? "autoresrv " : "",
3876                                              (flags & MAP_AUTOGROW) ? "autogrow " : "",
3877 #endif
3878                                              (flags & MAP_SHARED) ? "shared" : "");
3879                                 return(-1);
3880                         }
3881                 }
3882                 break;
3883                 
3884         case MEM_SHMEM:
3885                 if( nbytes > M->size ) {
3886                         if( M->space != NULL ) {
3887 #ifdef sgi
3888                                 if( M->flags & MEMF_MPIN )
3889                                         munpin(M->space, M->size);
3890 #endif
3891                                 shmdt( M->space );
3892 #ifdef sgi
3893                                 shmctl( M->fd, IPC_RMID );
3894 #else
3895                                 shmctl( M->fd, IPC_RMID, &shm_ds );
3896 #endif
3897                         }
3898                         M->space = NULL;
3899                         M->size = 0;
3900                 }
3901
3902                 if(M->space == NULL) {
3903                         if(!strcmp(M->name, "private")) {
3904                                 key = IPC_PRIVATE;
3905                         } else {
3906                                 sscanf(M->name, "%i", &key);
3907                         }
3908
3909                         M->size = M->nblks ? M->nblks * 512 : nbytes;
3910
3911                         if( nbytes > M->size ){
3912 #ifdef DEBUG
3913                                 doio_fprintf(stderr, "MEM_SHMEM: nblks(%d) too small:  nbytes=%d  Msize=%d, skipping this req.\n",
3914                                              M->nblks, nbytes, M->size );
3915 #endif
3916                                 return SKIP_REQ;
3917                         }
3918
3919                         shmid = shmget(key, M->size, IPC_CREAT|0666);
3920                         if( shmid == -1 ) {
3921                                 doio_fprintf(stderr, "shmget(0x%x, %d, CREAT) failed: %s (%d)\n",
3922                                              key, M->size, SYSERR, errno);
3923                                 return(-1);
3924                         }
3925                         M->fd = shmid;
3926                         M->space = shmat(shmid, NULL, SHM_RND);
3927                         if( M->space == (void *)-1 ) {
3928                                 doio_fprintf(stderr, "shmat(0x%x, NULL, SHM_RND) failed: %s (%d)\n", 
3929                                              shmid, SYSERR, errno);
3930                                 return(-1);
3931                         }
3932 #ifdef sgi
3933                         if(M->flags & MEMF_MPIN) {
3934                                 if( mpin(M->space, M->size) == -1 ) {
3935                                         doio_fprintf(stderr, "mpin(0x%lx, %d) failed:  %s (%d)\n",
3936                                                      M->space, M->size, SYSERR, errno);
3937                             }
3938                         }
3939 #endif
3940                 }
3941                 break;
3942
3943         default:
3944                 doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
3945                              Memalloc[me].memtype, mturn);
3946                 break;
3947         }
3948
3949         Memptr = M->space;
3950         Memsize = M->size;
3951
3952         mturn++;
3953         return 0;
3954 }
3955 #endif /* !CRAY */
3956
3957 #ifdef CRAY
3958 int
3959 alloc_mem(nbytes)
3960 int nbytes;
3961 {
3962         char    *cp;
3963         int     ip;
3964         static  char    *malloc_space;
3965
3966         /*
3967          * The "unicos" version of this did some stuff with sbrk;
3968          * this caused problems with async I/O on irix, and now appears
3969          * to be causing problems with FSA I/O on unicos/mk.
3970          */
3971 #ifdef NOTDEF
3972         if (nbytes > Memsize) {
3973                 if ((cp = (char *)sbrk(nbytes - Memsize)) == (char *)-1) {
3974                         doio_fprintf(stderr, "sbrk(%d) failed:  %s (%d)\n",
3975                                      nbytes - Memsize, SYSERR, errno);
3976                         return -1;
3977                 }
3978
3979                 if (Memsize == 0)
3980                         Memptr = cp;
3981                 Memsize += nbytes - Memsize;
3982         }
3983 #else
3984
3985         /* nbytes = -1 means "free all allocated memory" */
3986         if( nbytes == -1 ) {
3987                 free( malloc_space );
3988                 Memptr = NULL;
3989                 Memsize = 0;
3990                 return 0;
3991         }
3992
3993         if( nbytes > Memsize ) {
3994             if( Memsize != 0 )
3995                 free( malloc_space );
3996
3997             if( (cp = malloc_space = malloc( nbytes )) == NULL ) {
3998                 doio_fprintf(stderr, "malloc(%d) failed:  %s (%d)\n",
3999                              nbytes, SYSERR, errno);
4000                 return -1;
4001             }
4002
4003 #ifdef _CRAYT3E
4004             /* T3E requires memory to be aligned on 0x40 word boundaries */
4005             ip = (int)cp;
4006             if( ip & 0x3F != 0 ) {
4007                 doio_fprintf(stderr, "malloc(%d) = 0x%x(0x%x) not aligned by 0x%x\n",
4008                              nbytes, cp, ip, ip & 0x3f);
4009
4010                 free(cp);
4011                 if( (cp = malloc_space = malloc( nbytes + 0x40 )) == NULL ) {
4012                     doio_fprintf(stderr, "malloc(%d) failed:  %s (%d)\n",
4013                                  nbytes, SYSERR, errno);
4014                     return -1;
4015                 }
4016                 ip = (int)cp;
4017                 cp += (0x40 - (ip & 0x3F));
4018             }
4019 #endif /* _CRAYT3E */
4020             Memptr = cp;
4021             Memsize = nbytes;
4022         }
4023 #endif /* NOTDEF */
4024         return 0;
4025 }
4026 #endif /* CRAY */
4027
4028 /*
4029  * Simple function for allocating sds space.  Uses Sdssize and Sdsptr to
4030  * keep track of location and size of currently allocated chunk.
4031  */
4032
4033 #ifdef _CRAY1
4034
4035 int
4036 alloc_sds(nbytes)
4037 int nbytes;
4038 {
4039         int nblks;
4040
4041         if (nbytes > Sdssize) {
4042                 if ((nblks = ssbreak(btoc(nbytes - Sdssize))) == -1) {
4043                         doio_fprintf(stderr, "ssbreak(%d) failed:  %s (%d)\n",
4044                                      btoc(nbytes - Sdssize), SYSERR, errno);
4045                         return -1;
4046                 }
4047
4048                 Sdssize = ctob(nblks);
4049                 Sdsptr = 0;
4050         }
4051
4052         return 0;
4053 }
4054
4055 #else
4056
4057 #ifdef CRAY
4058
4059 int
4060 alloc_sds(nbytes)
4061 int     nbytes;
4062 {
4063         doio_fprintf(stderr,
4064                      "Internal Error - alloc_sds() called on a CRAY2 system\n");
4065         alloc_mem(-1);
4066         exit(E_INTERNAL);
4067 }
4068
4069 #endif
4070
4071 #endif /* _CRAY1 */
4072
4073 /*
4074  * Function to maintain a file descriptor cache, so that doio does not have
4075  * to do so many open() and close() calls.  Descriptors are stored in the
4076  * cache by file name, and open flags.  Each entry also has a _rtc value
4077  * associated with it which is used in aging.  If doio cannot open a file
4078  * because it already has too many open (ie. system limit hit) it will close
4079  * the one in the cache that has the oldest _rtc value.
4080  *
4081  * If alloc_fd() is called with a file of NULL, it will close all descriptors
4082  * in the cache, and free the memory in the cache.
4083  */
4084
4085 int
4086 alloc_fd(file, oflags)
4087 char    *file;
4088 int     oflags;
4089 {
4090         struct fd_cache *fdc;
4091         struct fd_cache *alloc_fdcache(char *file, int oflags);
4092
4093         fdc = alloc_fdcache(file, oflags);
4094         if(fdc != NULL)
4095                 return(fdc->c_fd);
4096         else
4097                 return(-1);
4098 }
4099
4100 struct fd_cache *
4101 alloc_fdcache(file, oflags)
4102 char    *file;
4103 int     oflags;
4104 {
4105         int                     fd;
4106         struct fd_cache         *free_slot, *oldest_slot, *cp;
4107         static int              cache_size = 0;
4108         static struct fd_cache  *cache = NULL;
4109 #ifndef NO_XFS
4110         struct dioattr  finfo;
4111 #endif
4112
4113         /*
4114          * If file is NULL, it means to free up the fd cache.
4115          */
4116
4117         if (file == NULL && cache != NULL) {
4118                 for (cp = cache; cp < &cache[cache_size]; cp++) {
4119                         if (cp->c_fd != -1) {
4120                                 close(cp->c_fd);
4121                         }
4122 #ifndef CRAY
4123                         if (cp->c_memaddr != NULL) {
4124                                 munmap(cp->c_memaddr, cp->c_memlen);
4125                         }
4126 #endif
4127                 }
4128
4129                 free(cache);
4130                 cache = NULL;
4131                 cache_size = 0;
4132                 return 0;
4133         }
4134
4135         free_slot = NULL;
4136         oldest_slot = NULL;
4137
4138         /*
4139          * Look for a fd in the cache.  If one is found, return it directly.
4140          * Otherwise, when this loop exits, oldest_slot will point to the
4141          * oldest fd slot in the cache, and free_slot will point to an
4142          * unoccupied slot if there are any.
4143          */
4144
4145         for (cp = cache; cp != NULL && cp < &cache[cache_size]; cp++) {
4146                 if (cp->c_fd != -1 &&
4147                     cp->c_oflags == oflags &&
4148                     strcmp(cp->c_file, file) == 0) {
4149 #ifdef CRAY
4150                         cp->c_rtc = _rtc();
4151 #else
4152                         cp->c_rtc = Reqno;
4153 #endif
4154                         return cp;
4155                 }
4156
4157                 if (cp->c_fd == -1) {
4158                         if (free_slot == NULL) {
4159                                 free_slot = cp;
4160                         }
4161                 } else {
4162                         if (oldest_slot == NULL || 
4163                             cp->c_rtc < oldest_slot->c_rtc) {
4164                                 oldest_slot = cp;
4165                         }
4166                 }
4167         }
4168
4169         /*
4170          * No matching file/oflags pair was found in the cache.  Attempt to
4171          * open a new fd.
4172          */
4173
4174         if ((fd = open(file, oflags, 0666)) < 0) {
4175                 if (errno != EMFILE) {
4176                         doio_fprintf(stderr,
4177                                      "Could not open file %s with flags %#o (%s): %s (%d)\n",
4178                                      file, oflags, format_oflags(oflags),
4179                                      SYSERR, errno);
4180                         alloc_mem(-1);
4181                         exit(E_SETUP);
4182                 }
4183
4184                 /*
4185                  * If we get here, we have as many open fd's as we can have.
4186                  * Close the oldest one in the cache (pointed to by
4187                  * oldest_slot), and attempt to re-open.
4188                  */
4189
4190                 close(oldest_slot->c_fd);
4191                 oldest_slot->c_fd = -1;
4192                 free_slot = oldest_slot;
4193
4194                 if ((fd = open(file, oflags, 0666)) < 0) {
4195                         doio_fprintf(stderr,
4196                                      "Could not open file %s with flags %#o (%s):  %s (%d)\n",
4197                                      file, oflags, format_oflags(oflags),
4198                                      SYSERR, errno);
4199                         alloc_mem(-1);
4200                         exit(E_SETUP);
4201                 }
4202         }
4203
4204 /*printf("alloc_fd: new file %s flags %#o fd %d\n", file, oflags, fd);*/
4205
4206         /*
4207          * If we get here, fd is our open descriptor.  If free_slot is NULL,
4208          * we need to grow the cache, otherwise free_slot is the slot that
4209          * should hold the fd info.
4210          */
4211
4212         if (free_slot == NULL) {
4213                 cache = (struct fd_cache *)realloc(cache, sizeof(struct fd_cache) * (FD_ALLOC_INCR + cache_size));
4214                 if (cache == NULL) {
4215                         doio_fprintf(stderr, "Could not malloc() space for fd chace");
4216                         alloc_mem(-1);
4217                         exit(E_SETUP);
4218                 }
4219
4220                 cache_size += FD_ALLOC_INCR;
4221
4222                 for (cp = &cache[cache_size-FD_ALLOC_INCR];
4223                      cp < &cache[cache_size]; cp++) {
4224                         cp->c_fd = -1;
4225                 }
4226
4227                 free_slot = &cache[cache_size - FD_ALLOC_INCR];
4228         }
4229
4230         /*
4231          * finally, fill in the cache slot info
4232          */
4233
4234         free_slot->c_fd = fd;
4235         free_slot->c_oflags = oflags;
4236         strcpy(free_slot->c_file, file);
4237 #ifdef CRAY
4238         free_slot->c_rtc = _rtc();
4239 #else
4240         free_slot->c_rtc = Reqno;
4241 #endif
4242
4243 #ifndef NO_XFS
4244         if (oflags & O_DIRECT) {
4245                 if (xfsctl(file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
4246                         finfo.d_mem = 1;
4247                         finfo.d_miniosz = 1;
4248                         finfo.d_maxiosz = 1;
4249                 }
4250         } else {
4251                 finfo.d_mem = 1;
4252                 finfo.d_miniosz = 1;
4253                 finfo.d_maxiosz = 1;
4254         }
4255
4256         free_slot->c_memalign = finfo.d_mem;
4257         free_slot->c_miniosz = finfo.d_miniosz;
4258         free_slot->c_maxiosz = finfo.d_maxiosz;
4259 #endif
4260 #ifndef CRAY
4261         free_slot->c_memaddr = NULL;
4262         free_slot->c_memlen = 0;
4263 #endif
4264
4265         return free_slot;
4266 }
4267
4268 /*
4269  *
4270  *                      Signal Handling Section
4271  *
4272  *
4273  */
4274
4275 #ifdef sgi
4276 /*
4277  * "caller-id" for signals
4278  */
4279 void
4280 signal_info(int sig, siginfo_t *info, void *v)
4281 {
4282         int haveit = 0;
4283
4284         if(info != NULL) {
4285                 switch(info->si_code) {
4286                 case SI_USER:
4287                         doio_fprintf(stderr,
4288                                      "signal_info: si_signo %d si_errno %d si_code SI_USER pid %d uid %d\n",
4289                                      info->si_signo, info->si_errno, 
4290                                      info->si_pid, info->si_uid);
4291                         haveit = 1;
4292                         break;
4293
4294                 case SI_QUEUE:
4295                         doio_fprintf(stderr, "signal_info  si_signo %d si_code = SI_QUEUE\n",
4296                                      info->si_signo);
4297                         haveit = 1;
4298                         break;
4299                 }
4300
4301                 if( ! haveit ){
4302                         if( (info->si_signo == SIGSEGV) ||
4303                            (info->si_signo == SIGBUS) ){
4304                                 doio_fprintf(stderr, "signal_info  si_signo %d si_errno %d si_code = %d  si_addr=%p  active_mmap_rw=%d havesigint=%d\n",
4305                                              info->si_signo, info->si_errno,
4306                                              info->si_code, info->si_addr,
4307                                              active_mmap_rw,
4308                                              havesigint);
4309                                 haveit = 1;
4310                            }
4311                 }
4312
4313                 if( !haveit ){
4314                         doio_fprintf(stderr, "signal_info: si_signo %d si_errno %d unknown code %d\n",
4315                                      info->si_signo, info->si_errno,
4316                                      info->si_code);
4317                 }
4318         } else {
4319                 doio_fprintf(stderr, "signal_info: sig %d\n", sig);
4320         }
4321 }
4322 #endif
4323
4324 #ifdef sgi
4325 void
4326 cleanup_handler(int sig, siginfo_t *info, void *v)
4327 {
4328         havesigint=1; /* in case there's a followup signal */
4329         /*signal_info(sig, info, v);*/  /* be quiet on "normal" kill */
4330         alloc_mem(-1);
4331         exit(0);
4332 }
4333
4334
4335 void
4336 die_handler(int sig, siginfo_t *info, void *v)
4337 {
4338         doio_fprintf(stderr, "terminating on signal %d\n", sig);
4339         signal_info(sig, info, v);
4340         alloc_mem(-1);
4341         exit(1);
4342 }
4343
4344 void
4345 sigbus_handler(int sig, siginfo_t *info, void *v)
4346 {
4347         /* While we are doing a memcpy to/from an mmapped region we can
4348            get a SIGBUS for a variety of reasons--and not all of them
4349            should be considered failures.
4350
4351            Under normal conditions if we get a SIGINT it means we've been
4352            told to shutdown.  However, if we're currently doing the above-
4353            mentioned memcopy then the kernel will follow that SIGINT with
4354            a SIGBUS.  We can guess that we're in this situation by seeing
4355            that the si_errno field in the siginfo structure has EINTR as
4356            an errno.  (We might make the guess stronger by looking at the
4357            si_addr field to see that it's not faulting off the end of the
4358            mmapped region, but it seems that in such a case havesigint
4359            would not have been set so maybe that doesn't make the guess
4360            stronger.)
4361          */
4362
4363         
4364         if( active_mmap_rw && havesigint && (info->si_errno == EINTR) ){
4365                 cleanup_handler( sig, info, v );
4366         }
4367         else{
4368                 die_handler( sig, info, v );
4369         }
4370 }
4371 #else
4372
4373 void
4374 cleanup_handler()
4375 {
4376         havesigint=1; /* in case there's a followup signal */
4377         alloc_mem(-1);
4378         exit(0);
4379 }
4380
4381 void
4382 die_handler(sig)
4383 int sig;
4384 {
4385         doio_fprintf(stderr, "terminating on signal %d\n", sig);
4386         alloc_mem(-1);
4387         exit(1);
4388 }
4389
4390 #ifndef CRAY
4391 void
4392 sigbus_handler(sig)
4393 int sig;
4394 {
4395         /* See sigbus_handler() in the 'ifdef sgi' case for details.  Here,
4396            we don't have the siginfo stuff so the guess is weaker but we'll
4397            do it anyway.
4398         */
4399
4400         if( active_mmap_rw && havesigint )
4401                 cleanup_handler();
4402         else
4403                 die_handler(sig);
4404 }
4405 #endif /* !CRAY */
4406 #endif /* sgi */
4407
4408
4409 void
4410 noop_handler(sig)
4411 int sig;
4412 {
4413         return;
4414 }
4415
4416
4417 /*
4418  * SIGINT handler for the parent (original doio) process.  It simply sends
4419  * a SIGINT to all of the doio children.  Since they're all in the same
4420  * pgrp, this can be done with a single kill().
4421  */
4422
4423 void
4424 sigint_handler()
4425 {
4426         int     i;
4427
4428         for (i = 0; i < Nchildren; i++) {
4429                 if (Children[i] != -1) {
4430                         kill(Children[i], SIGINT);
4431                 }
4432         }
4433 }
4434
4435 /*
4436  * Signal handler used to inform a process when async io completes.  Referenced
4437  * in do_read() and do_write().  Note that the signal handler is not
4438  * re-registered.
4439  */
4440
4441 void
4442 aio_handler(sig)
4443 int     sig;
4444 {
4445         int             i;
4446         struct aio_info *aiop;
4447
4448         for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
4449                 aiop = &Aio_Info[i];
4450
4451                 if (aiop->strategy == A_SIGNAL && aiop->sig == sig) {
4452                         aiop->signalled++;
4453
4454                         if (aio_done(aiop)) {
4455                                 aiop->done++;
4456                         }
4457                 }
4458         }
4459 }
4460
4461 /*
4462  * dump info on all open aio slots
4463  */
4464 void
4465 dump_aio()
4466 {
4467         int             i, count;
4468
4469         count=0;
4470         for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
4471                 if (Aio_Info[i].busy) {
4472                         count++;
4473                         fprintf(stderr,
4474                                 "Aio_Info[%03d] id=%d fd=%d signal=%d signaled=%d\n",
4475                                 i, Aio_Info[i].id,
4476                                 Aio_Info[i].fd,
4477                                 Aio_Info[i].sig,
4478                                 Aio_Info[i].signalled);
4479                         fprintf(stderr, "\tstrategy=%s\n",
4480                                 format_strat(Aio_Info[i].strategy));
4481                 }
4482         }
4483         fprintf(stderr, "%d active async i/os\n", count);
4484 }
4485
4486
4487 #ifdef sgi
4488 /*
4489  * Signal handler called as a callback, not as a signal.
4490  * 'val' is the value from sigev_value and is assumed to be the
4491  * Aio_Info[] index.
4492  */
4493 void
4494 cb_handler(val)
4495 sigval_t val;
4496 {
4497         struct aio_info *aiop;
4498
4499 /*printf("cb_handler requesting slot %d\n", val.sival_int);*/
4500         aiop = aio_slot( val.sival_int );
4501 /*printf("cb_handler, aiop=%p\n", aiop);*/
4502
4503 /*printf("%d in cb_handler\n", getpid() );*/
4504         if (aiop->strategy == A_CALLBACK) {
4505                 aiop->signalled++;
4506
4507                 if (aio_done(aiop)) {
4508                         aiop->done++;
4509                 }
4510         }
4511 }
4512 #endif
4513
4514 struct aio_info *
4515 aio_slot(aio_id)
4516 int     aio_id;
4517 {
4518         int             i;
4519         static int      id = 1;
4520         struct aio_info *aiop;
4521
4522         aiop = NULL;
4523
4524         for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
4525                 if (aio_id == -1) {
4526                         if (! Aio_Info[i].busy) {
4527                                 aiop = &Aio_Info[i];
4528                                 aiop->busy = 1;
4529                                 aiop->id = id++;
4530                                 break;
4531                         }
4532                 } else {
4533                         if (Aio_Info[i].busy && Aio_Info[i].id == aio_id) {
4534                                 aiop = &Aio_Info[i];
4535                                 break;
4536                         }
4537                 }
4538         }
4539
4540         if( aiop == NULL ){
4541                 doio_fprintf(stderr,"aio_slot(%d) not found.  Request %d\n", 
4542                              aio_id, Reqno);
4543                 dump_aio();
4544                 alloc_mem(-1);
4545                 exit(E_INTERNAL);
4546         }
4547
4548         return aiop;
4549 }
4550
4551 int
4552 aio_register(fd, strategy, sig)
4553 int             fd;
4554 int             strategy;
4555 int             sig;
4556 {
4557         struct aio_info         *aiop;
4558         void                    aio_handler();
4559         struct sigaction        sa;
4560
4561         aiop = aio_slot(-1);
4562
4563         aiop->fd = fd;
4564         aiop->strategy = strategy;
4565         aiop->done = 0;
4566 #ifdef CRAY
4567         bzero((char *)&aiop->iosw, sizeof(aiop->iosw));
4568 #endif
4569
4570         if (strategy == A_SIGNAL) {
4571                 aiop->sig = sig;
4572                 aiop->signalled = 0;
4573
4574                 sa.sa_handler = aio_handler;
4575                 sa.sa_flags = 0;
4576                 sigemptyset(&sa.sa_mask);
4577
4578                 sigaction(sig, &sa, &aiop->osa);
4579         } else {
4580                 aiop->sig = -1;
4581                 aiop->signalled = 0;
4582         }
4583
4584         return aiop->id;
4585 }
4586
4587 int
4588 aio_unregister(aio_id)
4589 int     aio_id;
4590 {
4591         struct aio_info *aiop;
4592
4593         aiop = aio_slot(aio_id);
4594
4595         if (aiop->strategy == A_SIGNAL) {
4596                 sigaction(aiop->sig, &aiop->osa, NULL);
4597         }
4598
4599         aiop->busy = 0;
4600         return 0;
4601 }
4602
4603 #ifndef linux
4604 int
4605 aio_wait(aio_id)
4606 int     aio_id;
4607 {
4608 #ifdef RECALL_SIZEOF
4609         long            mask[RECALL_SIZEOF];
4610 #endif
4611         sigset_t        sigset;
4612         struct aio_info *aiop;
4613 #ifdef CRAY
4614         struct iosw     *ioswlist[1];
4615 #endif
4616 #ifdef sgi
4617         const aiocb_t   *aioary[1];
4618 #endif
4619         int r, cnt;
4620
4621
4622         aiop = aio_slot(aio_id);
4623 /*printf("%d aiop B =%p\n", getpid(), aiop);*/
4624
4625         switch (aiop->strategy) {
4626         case A_POLL:
4627                 while (! aio_done(aiop))
4628                         ;
4629                 break;
4630
4631         case A_SIGNAL:
4632                 sigemptyset(&sigset);
4633                 sighold( aiop->sig );
4634
4635                 while ( !aiop->signalled || !aiop->done ) {
4636                         sigsuspend(&sigset);
4637                         sighold( aiop->sig );
4638                 }
4639                 break;
4640
4641 #ifdef CRAY
4642         case A_RECALL:
4643                 ioswlist[0] = &aiop->iosw;
4644                 if (recall(aiop->fd, 1, ioswlist) < 0) {
4645                         doio_fprintf(stderr, "recall() failed:  %s (%d)\n",
4646                                      SYSERR, errno);
4647                         exit(E_SETUP);
4648                 }
4649                 break;
4650
4651 #ifdef RECALL_SIZEOF
4652
4653         case A_RECALLA:
4654                 RECALL_INIT(mask);
4655                 RECALL_SET(mask, aiop->fd);
4656                 if (recalla(mask) < 0) {
4657                         doio_fprintf(stderr, "recalla() failed:  %s (%d)\n",
4658                                      SYSERR, errno);
4659                         exit(E_SETUP);
4660                 }
4661
4662                 RECALL_CLR(mask, aiop->fd);
4663                 break;
4664 #endif
4665
4666         case A_RECALLS:
4667                 ioswlist[0] = &aiop->iosw;
4668                 if (recalls(1, ioswlist) < 0) {
4669                         doio_fprintf(stderr, "recalls failed:  %s (%d)\n",
4670                                 SYSERR, errno);
4671                         exit(E_SETUP);
4672                 }
4673                 break;
4674 #endif  /* CRAY */
4675
4676 #ifdef sgi
4677         case A_CALLBACK:
4678                 aioary[0] = &aiop->aiocb;
4679                 cnt=0;
4680                 do {
4681                         r = aio_suspend(aioary, 1, NULL);
4682                         if( r == -1 ){
4683                                 doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
4684                                              SYSERR, errno );
4685                                 exit(E_SETUP);
4686                         }
4687                         cnt++;
4688                 } while(aiop->done == 0);
4689
4690 #if 0
4691                 /*
4692                  * after having this set for a while, I've decided that
4693                  * it's too noisy
4694                  */
4695                 if(cnt > 1)
4696                         doio_fprintf(stderr, "aio_wait: callback wait took %d tries\n", cnt);
4697 #endif
4698
4699                 /* 
4700                  * Note: cb_handler already calls aio_done
4701                  */
4702                 break;
4703
4704
4705         case A_SUSPEND:
4706                 aioary[0] = &aiop->aiocb;
4707                 r = aio_suspend(aioary, 1, NULL);
4708                 if( r == -1 ){
4709                         doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
4710                                      SYSERR, errno );
4711                         exit(E_SETUP);
4712                 }
4713
4714                 aio_done(aiop);
4715                 break;
4716 #endif
4717         }
4718
4719 /*printf("aio_wait: errno %d return %d\n", aiop->aio_errno, aiop->aio_ret);*/
4720
4721         return 0;
4722 }
4723 #endif /* !linux */
4724
4725 /*
4726  * Format specified time into HH:MM:SS format.  t is the time to format
4727  * in seconds (as returned from time(2)).
4728  */
4729
4730 char *
4731 hms(t)
4732 time_t  t;
4733 {
4734         static char     ascii_time[9];
4735         struct tm       *ltime;
4736
4737         ltime = localtime(&t);
4738         strftime(ascii_time, sizeof(ascii_time), "%H:%M:%S", ltime);
4739
4740         return ascii_time;
4741 }
4742
4743 /*
4744  * Simple routine to check if an async io request has completed.
4745  */
4746
4747 int
4748 aio_done(struct aio_info *ainfo)
4749 {
4750 #ifdef CRAY
4751         return ainfo->iosw.sw_flag;
4752 #endif
4753
4754 #ifdef sgi
4755         if( (ainfo->aio_errno = aio_error(&ainfo->aiocb)) == -1 ){
4756                 doio_fprintf(stderr, "aio_done: aio_error failed: %s (%d)\n",
4757                              SYSERR, errno );
4758                 exit(E_SETUP);
4759         }
4760         /*printf("%d aio_done aio_errno=%d\n", getpid(), ainfo->aio_errno);*/
4761         if( ainfo->aio_errno != EINPROGRESS ){
4762                 if( (ainfo->aio_ret = aio_return(&ainfo->aiocb)) == -1 ){
4763                         doio_fprintf(stderr, "aio_done: aio_return failed: %s (%d)\n",
4764                                      SYSERR, errno );
4765                         exit(E_SETUP);
4766                 }
4767         }
4768
4769         return (ainfo->aio_errno != EINPROGRESS);
4770 #else
4771         return -1;   /* invalid */
4772 #endif
4773 }
4774
4775 /*
4776  * Routine to handle upanic() - it first attempts to set the panic flag.  If
4777  * the flag cannot be set, an error message is issued.  A call to upanic
4778  * with PA_PANIC is then done unconditionally, in case the panic flag was set
4779  * from outside the program (as with the panic(8) program).
4780  *
4781  * Note - we only execute the upanic code if -U was used, and the passed in
4782  * mask is set in the Upanic_Conditions bitmask.
4783  */
4784
4785 void
4786 doio_upanic(mask)
4787 int     mask;
4788 {
4789         if (U_opt == 0 || (mask & Upanic_Conditions) == 0) {
4790                 return;
4791         }
4792
4793 #ifdef CRAY
4794         if (upanic(PA_SET) < 0) {
4795                 doio_fprintf(stderr, "WARNING - Could not set the panic flag - upanic(PA_SET) failed:  %s (%d)\n",
4796                              SYSERR, errno);
4797         }
4798
4799         upanic(PA_PANIC);
4800 #endif
4801 #ifdef sgi
4802         syssgi(1005);   /* syssgi test panic - DEBUG kernels only */
4803 #endif
4804         doio_fprintf(stderr, "WARNING - upanic() failed\n");
4805 }
4806
4807 /*
4808  * Parse cmdline options/arguments and set appropriate global variables.
4809  * If the cmdline is valid, return 0 to caller.  Otherwise exit with a status
4810  * of 1.
4811  */
4812
4813 int
4814 parse_cmdline(argc, argv, opts)
4815 int     argc;
4816 char    **argv;
4817 char    *opts;
4818 {
4819         int             c;
4820         char            cc, *cp, *tok = NULL;
4821         extern int      opterr;
4822         extern int      optind;
4823         extern char     *optarg;
4824         struct smap     *s;
4825         char            *memargs[NMEMALLOC];
4826         int             nmemargs, ma;
4827         void            parse_memalloc(char *arg);
4828         void            parse_delay(char *arg);
4829         void            dump_memalloc();
4830
4831         if (*argv[0] == '-') {
4832                 argv[0]++;
4833                 Execd = 1;
4834         }
4835         
4836         if ((Prog = strrchr(argv[0], '/')) == NULL) {
4837                 Prog = argv[0];
4838         } else {
4839                 Prog++;
4840         }
4841         
4842         opterr = 0;
4843         while ((c = getopt(argc, argv, opts)) != EOF) {
4844                 switch ((char)c) {
4845                 case 'a':
4846                         a_opt++;
4847                         break;
4848
4849                 case 'C':
4850                         C_opt++;
4851                         for(s=checkmap; s->string != NULL; s++)
4852                                 if(!strcmp(s->string, optarg))
4853                                         break;
4854                         if (s->string == NULL) {
4855                                 fprintf(stderr,
4856                                         "%s%s:  Illegal -C arg (%s).  Must be one of: ", 
4857                                         Prog, TagName, tok);
4858
4859                                 for (s = checkmap; s->string != NULL; s++)
4860                                         fprintf(stderr, "%s ", s->string);
4861                                 fprintf(stderr, "\n");
4862                                 exit(1);
4863                         }
4864
4865                         switch(s->value) {
4866                         case C_DEFAULT:
4867                                 Data_Fill = doio_pat_fill;
4868                                 Data_Check = doio_pat_check;
4869                                 break;
4870                         default:
4871                                 fprintf(stderr,
4872                                         "%s%s:  Unrecognised -C arg '%s' %d", 
4873                                         Prog, TagName, s->string, s->value);
4874                                 exit(1);
4875                         }
4876                         break;
4877
4878                 case 'd':       /* delay between i/o ops */
4879                         parse_delay(optarg);
4880                         break;
4881
4882                 case 'e':
4883                         if (Npes > 1 && Nprocs > 1) {
4884                                 fprintf(stderr, "%s%s:  Warning - Program is a multi-pe application - exec option is ignored.\n", Prog, TagName);
4885                         }
4886                         e_opt++;
4887                         break;
4888
4889                 case 'h':
4890                         help(stdout);
4891                         exit(0);
4892                         break;
4893
4894                 case 'k':
4895                         k_opt++;
4896                         break;
4897
4898                 case 'm':
4899                         Message_Interval = strtol(optarg, &cp, 10);
4900                         if (*cp != '\0' || Message_Interval < 0) {
4901                                 fprintf(stderr, "%s%s:  Illegal -m arg (%s):  Must be an integer >= 0\n", Prog, TagName, optarg);
4902                                 exit(1);
4903                         }
4904                         m_opt++;
4905                         break;
4906
4907                 case 'M':       /* memory allocation types */
4908 #ifndef CRAY
4909                         nmemargs = string_to_tokens(optarg, memargs, 32, ",");
4910                         for(ma=0; ma < nmemargs; ma++) {
4911                                 parse_memalloc(memargs[ma]);
4912                         }
4913                         /*dump_memalloc();*/
4914 #else
4915                         fprintf(stderr, "%s%s: Error: -M isn't supported on this platform\n", Prog, TagName);
4916                         exit(1);
4917 #endif
4918                         M_opt++;
4919                         break;
4920
4921                 case 'N':
4922                         sprintf( TagName, "(%.39s)", optarg );
4923                         break;
4924
4925                 case 'n':
4926                         Nprocs = strtol(optarg, &cp, 10);
4927                         if (*cp != '\0' || Nprocs < 1) {
4928                                 fprintf(stderr,
4929                                         "%s%s:  Illegal -n arg (%s):  Must be integer > 0\n",
4930                                         Prog, TagName, optarg);
4931                                 exit(E_USAGE);
4932                         }
4933
4934                         if (Npes > 1 && Nprocs > 1) {
4935                                 fprintf(stderr, "%s%s:  Program has been built as a multi-pe app.  -n1 is the only nprocs value allowed\n", Prog, TagName);
4936                                 exit(E_SETUP);
4937                         }
4938                         n_opt++;
4939                         break;
4940
4941                 case 'r':
4942                         Release_Interval = strtol(optarg, &cp, 10);
4943                         if (*cp != '\0' || Release_Interval < 0) {
4944                                 fprintf(stderr,
4945                                         "%s%s:  Illegal -r arg (%s):  Must be integer >= 0\n",
4946                                         Prog, TagName, optarg);
4947                                 exit(E_USAGE);
4948                         }
4949
4950                         r_opt++;
4951                         break;
4952
4953                 case 'w':
4954                         Write_Log = optarg;
4955                         w_opt++;
4956                         break;
4957
4958                 case 'v':
4959                         v_opt++;
4960                         break;
4961
4962                 case 'V':
4963                         if (strcasecmp(optarg, "sync") == 0) {
4964                                 Validation_Flags = O_SYNC;
4965                         } else if (strcasecmp(optarg, "buffered") == 0) {
4966                                 Validation_Flags = 0;
4967 #ifdef CRAY
4968                         } else if (strcasecmp(optarg, "parallel") == 0) {
4969                                 Validation_Flags = O_PARALLEL;
4970                         } else if (strcasecmp(optarg, "ldraw") == 0) {
4971                                 Validation_Flags = O_LDRAW;
4972                         } else if (strcasecmp(optarg, "raw") == 0) {
4973                                 Validation_Flags = O_RAW;
4974 #endif
4975                         } else if (strcasecmp(optarg, "direct") == 0) {
4976                                 Validation_Flags = O_DIRECT;
4977                         } else {
4978                                 if (sscanf(optarg, "%i%c", &Validation_Flags, &cc) != 1) {
4979                                         fprintf(stderr, "%s:  Invalid -V argument (%s) - must be a decimal, hex, or octal\n", Prog, optarg);
4980                                         fprintf(stderr, "    number, or one of the following strings:  'sync',\n");
4981                                         fprintf(stderr, "    'buffered', 'parallel', 'ldraw', or 'raw'\n");
4982                                         exit(E_USAGE);
4983                                 }
4984                         }
4985                         V_opt++;
4986                         break;
4987                 case 'U':
4988                         tok = strtok(optarg, ",");
4989                         while (tok != NULL) {
4990                                 for (s = Upanic_Args; s->string != NULL; s++)
4991                                         if (strcmp(s->string, tok) == 0)
4992                                                 break;
4993
4994                                 if (s->string == NULL) {
4995                                         fprintf(stderr,
4996                                                 "%s%s:  Illegal -U arg (%s).  Must be one of: ", 
4997                                                 Prog, TagName, tok);
4998
4999                                         for (s = Upanic_Args; s->string != NULL; s++)
5000                                                 fprintf(stderr, "%s ", s->string);
5001
5002                                         fprintf(stderr, "\n");
5003
5004                                         exit(1);
5005                                 }
5006
5007                                 Upanic_Conditions |= s->value;
5008                                 tok = strtok(NULL, ",");
5009                         }
5010
5011                         U_opt++;
5012                         break;
5013
5014                 case '?':
5015                         usage(stderr);
5016                         exit(E_USAGE);
5017                         break;
5018                 }
5019         }
5020         
5021         /*
5022          * Supply defaults
5023          */
5024         
5025         if (! C_opt) {
5026                 Data_Fill = doio_pat_fill;
5027                 Data_Check = doio_pat_check;
5028         }
5029
5030         if (! U_opt)
5031                 Upanic_Conditions = 0;
5032
5033         if (! n_opt)
5034                 Nprocs = 1;
5035         
5036         if (! r_opt)
5037                 Release_Interval = DEF_RELEASE_INTERVAL;
5038
5039         if (! M_opt) {
5040                 Memalloc[Nmemalloc].memtype = MEM_DATA;
5041                 Memalloc[Nmemalloc].flags = 0;
5042                 Memalloc[Nmemalloc].name = NULL;
5043                 Memalloc[Nmemalloc].space = NULL;
5044                 Nmemalloc++;
5045         }
5046
5047         /*
5048          * Initialize input stream
5049          */
5050
5051         if (argc == optind) {
5052                 Infile = NULL;
5053         } else {
5054                 Infile = argv[optind++];
5055         }
5056
5057         if (argc != optind) {
5058                 usage(stderr);
5059                 exit(E_USAGE);
5060         }
5061
5062         return 0;
5063 }       
5064
5065
5066
5067 /*
5068  * Parse memory allocation types
5069  *
5070  * Types are:
5071  *  Data
5072  *  T3E-shmem:blksize[:nblks]
5073  *  SysV-shmem:shmid:blksize:nblks
5074  *      if shmid is "private", use IPC_PRIVATE
5075  *      and nblks is not required
5076  *
5077  *  mmap:flags:filename:blksize[:nblks]
5078  *   flags are one of:
5079  *      p - private (MAP_PRIVATE)
5080  *      a - private, MAP_AUTORESRV
5081  *      l - local (MAP_LOCAL)
5082  *      s - shared (nblks required)
5083  *
5084  *   plus any of:
5085  *      f - fixed address (MAP_FIXED)
5086  *      A - use an address without MAP_FIXED
5087  *      a - autogrow (map once at startup)
5088  *
5089  *  mmap:flags:devzero
5090  *      mmap /dev/zero  (shared not allowd)
5091  *      maps the first 4096 bytes of /dev/zero
5092  *
5093  * - put a directory at the beginning of the shared
5094  *   regions saying what pid has what region.
5095  *      DIRMAGIC
5096  *      BLKSIZE
5097  *      NBLKS
5098  *      nblks worth of directories - 1 int pids
5099  */
5100 #ifndef CRAY
5101 void
5102 parse_memalloc(char *arg)
5103 {
5104         char            *allocargs[NMEMALLOC];
5105         int             nalloc;
5106         struct memalloc *M;
5107
5108         if(Nmemalloc >= NMEMALLOC) {
5109                 doio_fprintf(stderr, "Error - too many memory types (%d).\n", 
5110                         Nmemalloc);
5111                 return;
5112         }
5113
5114         M = &Memalloc[Nmemalloc];
5115
5116         nalloc = string_to_tokens(arg, allocargs, 32, ":");
5117         if(!strcmp(allocargs[0], "data")) {
5118                 M->memtype = MEM_DATA;
5119                 M->flags = 0;
5120                 M->name = NULL;
5121                 M->space = NULL;
5122                 Nmemalloc++;
5123                 if(nalloc >= 2) {
5124                         if(strchr(allocargs[1], 'p'))
5125                                 M->flags |= MEMF_MPIN;
5126                 }
5127         } else if(!strcmp(allocargs[0], "mmap")) {
5128                 /* mmap:flags:filename[:size] */
5129                 M->memtype = MEM_MMAP;
5130                 M->flags = 0;
5131                 M->space = NULL;
5132                 if(nalloc >= 1) {
5133                         if(strchr(allocargs[1], 'p'))
5134                                 M->flags |= MEMF_PRIVATE;
5135                         if(strchr(allocargs[1], 'a'))
5136                                 M->flags |= MEMF_AUTORESRV;
5137                         if(strchr(allocargs[1], 'l'))
5138                                 M->flags |= MEMF_LOCAL;
5139                         if(strchr(allocargs[1], 's'))
5140                                 M->flags |= MEMF_SHARED;
5141
5142                         if(strchr(allocargs[1], 'f'))
5143                                 M->flags |= MEMF_FIXADDR;
5144                         if(strchr(allocargs[1], 'A'))
5145                                 M->flags |= MEMF_ADDR;
5146                         if(strchr(allocargs[1], 'G'))
5147                                 M->flags |= MEMF_AUTOGROW;
5148
5149                         if(strchr(allocargs[1], 'U'))
5150                                 M->flags |= MEMF_FILE;
5151                 } else {
5152                         M->flags |= MEMF_PRIVATE;
5153                 }
5154
5155                 if(nalloc > 2) {
5156                         if(!strcmp(allocargs[2], "devzero")) {
5157                                 M->name = "/dev/zero";
5158                                 if(M->flags & 
5159                                    ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
5160                                         M->flags |= MEMF_PRIVATE;
5161                         } else {
5162                                 M->name = allocargs[2];
5163                         }
5164                 } else {
5165                         M->name = "/dev/zero";
5166                         if(M->flags & 
5167                            ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
5168                                 M->flags |= MEMF_PRIVATE;
5169                 }
5170                 Nmemalloc++;
5171
5172         } else if(!strcmp(allocargs[0], "shmem")) {
5173                 /* shmem:shmid:size */
5174                 M->memtype = MEM_SHMEM;
5175                 M->flags = 0;
5176                 M->space = NULL;
5177                 if(nalloc >= 2) {
5178                         M->name = allocargs[1];
5179                 } else {
5180                         M->name = NULL;
5181                 }
5182                 if(nalloc >= 3) {
5183                         sscanf(allocargs[2], "%i", &M->nblks);
5184                 } else {
5185                         M->nblks = 0;
5186                 }
5187                 if(nalloc >= 4) {
5188                         if(strchr(allocargs[3], 'p'))
5189                                 M->flags |= MEMF_MPIN;
5190                 }
5191
5192                 Nmemalloc++;
5193         } else {
5194                 doio_fprintf(stderr, "Error - unknown memory type '%s'.\n",
5195                         allocargs[0]);
5196                 exit(1);
5197         }
5198 }
5199
5200 void
5201 dump_memalloc()
5202 {
5203         int     ma;
5204         char    *mt;
5205
5206         if(Nmemalloc == 0) {
5207                 printf("No memory allocation strategies devined\n");
5208                 return;
5209         }
5210
5211         for(ma=0; ma < Nmemalloc; ma++) {
5212                 switch(Memalloc[ma].memtype) {
5213                 case MEM_DATA:  mt = "data";    break;
5214                 case MEM_SHMEM: mt = "shmem";   break;
5215                 case MEM_MMAP:  mt = "mmap";    break;
5216                 default:        mt = "unknown"; break;
5217                 }
5218                 printf("mstrat[%d] = %d %s\n", ma, Memalloc[ma].memtype, mt);
5219                 printf("\tflags=%#o name='%s' nblks=%d\n",
5220                        Memalloc[ma].flags,
5221                        Memalloc[ma].name,
5222                        Memalloc[ma].nblks);
5223         }
5224 }
5225
5226 #endif /* !CRAY */
5227
5228 /*
5229  * -d <op>:<time> - doio inter-operation delay
5230  *      currently this permits ONE type of delay between operations.
5231  */
5232
5233 void
5234 parse_delay(char *arg)
5235 {
5236         char            *delayargs[NMEMALLOC];
5237         int             ndelay;
5238         struct smap     *s;
5239
5240         ndelay = string_to_tokens(arg, delayargs, 32, ":");
5241         if(ndelay < 2) {
5242                 doio_fprintf(stderr,
5243                         "Illegal delay arg (%s). Must be operation:time\n", arg);
5244                 exit(1);
5245         }
5246         for(s=delaymap; s->string != NULL; s++)
5247                 if(!strcmp(s->string, delayargs[0]))
5248                         break;
5249         if (s->string == NULL) {
5250                 fprintf(stderr,
5251                         "Illegal Delay arg (%s).  Must be one of: ", arg);
5252
5253                 for (s = delaymap; s->string != NULL; s++)
5254                         fprintf(stderr, "%s ", s->string);
5255                 fprintf(stderr, "\n");
5256                 exit(1);
5257         }
5258
5259         delayop = s->value;
5260
5261         sscanf(delayargs[1], "%i", &delaytime);
5262
5263         if(ndelay > 2) {
5264                 fprintf(stderr,
5265                         "Warning: extra delay arguments ignored.\n");
5266         }
5267 }
5268
5269
5270 /*
5271  * Usage clause - obvious
5272  */
5273
5274 int
5275 usage(stream)
5276 FILE    *stream;
5277 {
5278         /*
5279          * Only do this if we are on vpe 0, to avoid seeing it from every
5280          * process in the application.
5281          */
5282
5283         if (Npes > 1 && Vpe != 0) {
5284                 return 0;
5285         }
5286
5287         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);
5288         return 0;
5289 }
5290
5291 void
5292 help(stream)
5293 FILE    *stream;
5294 {
5295         /*
5296          * Only the app running on vpe 0 gets to issue help - this prevents
5297          * everybody in the application from doing this.
5298          */
5299
5300         if (Npes > 1 && Vpe != 0) {
5301                 return;
5302         }
5303
5304         usage(stream);
5305         fprintf(stream, "\n");
5306         fprintf(stream, "\t-a                   abort - kill all doio processes on data compare\n");
5307         fprintf(stream, "\t                     errors.  Normally only the erroring process exits\n");
5308         fprintf(stream, "\t-C data-pattern-type \n");
5309         fprintf(stream, "\t                     Available data patterns are:\n");
5310         fprintf(stream, "\t                     default - repeating pattern\n");
5311         fprintf(stream, "\t-d Operation:Time    Inter-operation delay.\n");
5312         fprintf(stream, "\t                     Operations are:\n");
5313         fprintf(stream, "\t                         select:time (1 second=1000000)\n");
5314         fprintf(stream, "\t                         sleep:time (1 second=1)\n");
5315 #ifdef sgi
5316         fprintf(stream, "\t                         sginap:time (1 second=CLK_TCK=100)\n");
5317 #endif
5318         fprintf(stream, "\t                         alarm:time (1 second=1)\n");
5319         fprintf(stream, "\t-e                   Re-exec children before entering the main\n");
5320         fprintf(stream, "\t                     loop.  This is useful for spreading\n");
5321         fprintf(stream, "\t                     procs around on multi-pe systems.\n");
5322         fprintf(stream, "\t-k                   Lock file regions during writes using fcntl()\n");
5323         fprintf(stream, "\t-v                   Verify writes - this is done by doing a buffered\n");
5324         fprintf(stream, "\t                     read() of the data if file io was done, or\n");
5325         fprintf(stream, "\t                     an ssread()of the data if sds io was done\n");
5326 #ifndef CRAY
5327         fprintf(stream, "\t-M                   Data buffer allocation method\n");
5328         fprintf(stream, "\t                     alloc-type[,type]\n");
5329 #ifdef sgi
5330         fprintf(stream, "\t                         data:flags\n");
5331         fprintf(stream, "\t                             p - mpin buffer\n");
5332         fprintf(stream, "\t                         shmem:shmid:size:flags\n");
5333         fprintf(stream, "\t                             p - mpin buffer\n");
5334 #else
5335         fprintf(stream, "\t                         data\n");
5336         fprintf(stream, "\t                         shmem:shmid:size\n");
5337 #endif /* sgi */
5338         fprintf(stream, "\t                         mmap:flags:filename\n");
5339         fprintf(stream, "\t                             p - private\n");
5340 #ifdef sgi
5341         fprintf(stream, "\t                             s - shared\n");
5342         fprintf(stream, "\t                             l - local\n");
5343         fprintf(stream, "\t                             a - autoresrv\n");
5344         fprintf(stream, "\t                             G - autogrow\n");
5345 #else
5346         fprintf(stream, "\t                             s - shared (shared file must exist\n"),
5347         fprintf(stream, "\t                                 and have needed length)\n");
5348 #endif
5349         fprintf(stream, "\t                             f - fixed address (not used)\n");
5350         fprintf(stream, "\t                             a - specify address (not used)\n");
5351         fprintf(stream, "\t                             U - Unlink file when done\n");
5352         fprintf(stream, "\t                             The default flag is private\n");
5353         fprintf(stream, "\n");
5354 #endif /* !CRAY */
5355         fprintf(stream, "\t-m message_interval  Generate a message every 'message_interval'\n");
5356         fprintf(stream, "\t                     requests.  An interval of 0 suppresses\n");
5357         fprintf(stream, "\t                     messages.  The default is 0.\n");
5358         fprintf(stream, "\t-N tagname           Tag name, for Monster.\n");
5359         fprintf(stream, "\t-n nprocs            # of processes to start up\n");
5360         fprintf(stream, "\t-r release_interval  Release all memory and close\n");
5361         fprintf(stream, "\t                     files every release_interval operations.\n");
5362         fprintf(stream, "\t                     By default procs never release memory\n");
5363         fprintf(stream, "\t                     or close fds unless they have to.\n");
5364         fprintf(stream, "\t-V validation_ftype  The type of file descriptor to use for doing data\n");
5365         fprintf(stream, "\t                     validation.  validation_ftype may be an octal,\n");
5366         fprintf(stream, "\t                     hex, or decimal number representing the open()\n");
5367         fprintf(stream, "\t                     flags, or may be one of the following strings:\n");
5368         fprintf(stream, "\t                     'buffered' - validate using bufferd read\n");
5369         fprintf(stream, "\t                     'sync'     - validate using O_SYNC read\n");
5370         fprintf(stream, "\t                     'direct    - validate using O_DIRECT read'\n");
5371 #ifdef CRAY
5372         fprintf(stream, "\t                     'ldraw'    - validate using O_LDRAW read\n");
5373         fprintf(stream, "\t                     'parallel' - validate using O_PARALLEL read\n");
5374         fprintf(stream, "\t                     'raw'      - validate using O_RAW read\n");
5375 #endif
5376         fprintf(stream, "\t                     By default, 'parallel'\n");
5377         fprintf(stream, "\t                     is used if the write was done with O_PARALLEL\n");
5378         fprintf(stream, "\t                     or 'buffered' for all other writes.\n");
5379         fprintf(stream, "\t-w write_log         File to log file writes to.  The doio_check\n");
5380         fprintf(stream, "\t                     program can reconstruct datafiles using the\n");
5381         fprintf(stream, "\t                     write_log, and detect if a file is corrupt\n");
5382         fprintf(stream, "\t                     after all procs have exited.\n");
5383         fprintf(stream, "\t-U upanic_cond       Comma separated list of conditions that will\n");
5384         fprintf(stream, "\t                     cause a call to upanic(PA_PANIC).\n");
5385         fprintf(stream, "\t                     'corruption' -> upanic on bad data comparisons\n");
5386         fprintf(stream, "\t                     'iosw'     ---> upanic on unexpected async iosw\n");
5387         fprintf(stream, "\t                     'rval'     ---> upanic on unexpected syscall rvals\n");
5388         fprintf(stream, "\t                     'all'      ---> all of the above\n");
5389         fprintf(stream, "\n");
5390         fprintf(stream, "\tinfile               Input stream - default is stdin - must be a list\n");
5391         fprintf(stream, "\t                     of io_req structures (see doio.h).  Currently\n");
5392         fprintf(stream, "\t                     only the iogen program generates the proper\n");
5393         fprintf(stream, "\t                     format\n");
5394 }       
5395