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