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