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:
3