btrfs: add test for zone auto reclaim
[xfstests-dev.git] / lib / tlibio.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000 Silicon Graphics, Inc.
4  * All Rights Reserved.
5  */
6 /*
7  *
8  * Lib i/o
9  *
10  * This file contains several functions to doing reads and writes.
11  * It was written so that a single function could be called in a test
12  * program and only a io type field value would have to change to
13  * do different types of io.  There is even a couple of functions that
14  * will allow you to parse a string to determine the iotype.
15  *
16  * This file contains functions for writing/reading to/from open files
17  * Prototypes:
18  *
19  * Functions declared in this module - see individual function code for
20  * usage comments:
21  *
22  *  int  stride_bounds(int offset, int stride, int nstrides,
23  *                    int bytes_per_stride, int *min, int *max);
24
25  *  int  lio_write_buffer(int fd, int method, char *buffer, int size,
26  *                                              char **errmsg, long wrd);
27  *  int  lio_read_buffer(int fd, int method, char *buffer, int size,
28  *                                              char **errmsg, long wrd);
29  *  int  lio_parse_io_arg1(char *string)
30  *  void lio_help1(char *prefix);
31  *
32  *  int  lio_parse_io_arg2(char *string, char **badtoken)
33  *  void lio_help2(char *prefix);
34  *
35  *  int  lio_set_debug(int level);
36  *
37  *  char Lio_SysCall[];
38  *  struct lio_info_type Lio_info1[];
39  *  struct lio_info_type Lio_info2[];
40  *
41  *  Author : Richard Logan
42  *
43  */
44
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/time.h>          
52 #include <sys/param.h>
53 #include <errno.h>
54 #include <sys/types.h>
55 #include <sys/file.h>
56 #include <signal.h>
57 #include <sys/uio.h> /* readv(2)/writev(2) */
58 #include <string.h>
59 #include <strings.h>
60 #include <stdlib.h> /* atoi, abs */
61
62 #include "tlibio.h"             /* defines LIO* marcos */
63
64 #ifndef PATH_MAX
65 #define PATH_MAX        MAXPATHLEN
66 #endif
67
68 #if 0 /* disabled until it's needed -- roehrich 6/11/97 */
69 #define BUG1_workaround 1 /* Work around a condition where aio_return gives
70                            * a value of zero but there is no errno followup
71                            * and the read/write operation actually did its
72                            * job.   spr/pv 705244
73                            */
74 #endif
75
76
77 #ifndef linux
78 static void lio_async_signal_handler();
79 #endif
80
81 /*
82  * Define the structure as used in lio_parse_arg1 and lio_help1
83  */
84 struct lio_info_type  Lio_info1[] = {
85     { "s", LIO_IO_SYNC, "sync i/o" },
86     { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" },
87     { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" },
88     { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" },
89     { "r", 
90         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
91     { "R", 
92         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
93     { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" },
94     { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" },
95     { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" },
96     { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" },
97     { "P", LIO_IO_SYNCP, "sync pread/pwrite" },
98 };
99
100 /*
101  * Define the structure used by lio_parse_arg2 and lio_help2
102  */
103 struct lio_info_type  Lio_info2[] = {
104     { "sync",      LIO_IO_SYNC,         "sync i/o (read/write)"},
105     { "async",     LIO_IO_ASYNC,        "async i/o (reada/writea/aio_read/aio_write)" },
106     { "slistio",   LIO_IO_SLISTIO,      "single stride sync listio" },
107     { "alistio",   LIO_IO_ALISTIO,      "single stride async listio" },
108     { "syncv",     LIO_IO_SYNCV,        "single buffer sync readv/writev"},
109     { "syncp",     LIO_IO_SYNCP,        "pread/pwrite"},
110     { "active",    LIO_WAIT_ACTIVE,     "spin on status/control values" },
111     { "recall",    LIO_WAIT_RECALL,     "use recall(2)/aio_suspend(3) to wait for i/o to complete" },
112     { "sigactive", LIO_WAIT_SIGACTIVE,  "spin waiting for signal" },
113     { "sigpause",  LIO_WAIT_SIGPAUSE,   "call pause(2) to wait for signal" },
114 /* nowait is a touchy thing, it's an accident that this implementation worked at all.  6/27/97 roehrich */
115 /*    { "nowait",    LIO_WAIT_NONE,     "do not wait for async io to complete" },*/
116     { "random",    LIO_RANDOM,          "set random bit" },
117     { "randomall", 
118         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, 
119         "all random i/o types and wait methods (except nowait)" },
120 };
121
122 char Lio_SysCall[PATH_MAX];     /* string containing last i/o system call */
123
124 static volatile int Received_signal = 0;        /* number of signals received */
125 static volatile int Rec_signal;
126 static char Errormsg[500];
127 static int Debug_level = 0;
128
129
130
131 /***********************************************************************
132  * stride_bounds()
133  *
134  * Determine the bounds of a strided request, normalized to offset.  Returns
135  * the number of bytes needed to satisfy the request, and optionally sets
136  * *min and *max to the mininum and maximum bytes referenced, normalized 
137  * around offset.
138  *
139  * Returns -1 on error - the only possible error conditions are illegal values
140  * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
141  *
142  * (maule, 11/16/95)
143  ***********************************************************************/
144
145 int
146 stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max)
147 int     offset;
148 int     stride;
149 int     nstrides;
150 int     bytes_per_stride;
151 int     *min;
152 int     *max;
153 {
154         int     nbytes, min_byte, max_byte;
155
156         /*
157          * sanity checks ...
158          */
159
160         if (nstrides < 0 || bytes_per_stride < 0) {
161                 return -1;
162         }
163
164         if (stride == 0) {
165                 stride = bytes_per_stride;
166         }
167
168         /*
169          * Determine the # of bytes needed to satisfy the request.  This
170          * value, along with the offset argument, determines the min and max
171          * bytes referenced.
172          */
173
174
175         nbytes = abs(stride) * (nstrides-1) + bytes_per_stride;
176
177         if (stride < 0) {
178                 max_byte = offset + bytes_per_stride - 1;
179                 min_byte = max_byte - nbytes + 1;
180         } else {
181                 min_byte = offset;
182                 max_byte = min_byte + nbytes - 1;
183         }
184         
185         if (min != NULL) {
186                 *min = min_byte;
187         }
188         
189         if (max != NULL) {
190                 *max = max_byte;
191         }
192
193         return nbytes;
194 }
195
196 /***********************************************************************
197  * This function will allow someone to set the debug level.
198  ***********************************************************************/
199 int
200 lio_set_debug(int level)
201 {
202     int old;
203
204     old = Debug_level;
205     Debug_level = level;
206     return old;
207 }
208
209 /***********************************************************************
210  * This function will parse a string and return desired io-method.
211  * Only the first character of the string is used.
212  *
213  * This function does not provide for meaningful option arguments,
214  * but it supports current growfiles/btlk interface.
215  *
216  *  (rrl 04/96)
217  ***********************************************************************/
218 int
219 lio_parse_io_arg1(char *string)
220 {
221     int ind;
222     int found=0;
223     int mask=0;
224
225     /*
226      * Determine if token is a valid string.
227      */
228     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
229         if ( strcmp(string, Lio_info1[ind].token) == 0 ) {
230             mask |= Lio_info1[ind].bits;
231             found = 1;
232             break;
233         }
234     }
235
236     if ( found == 0 ) {
237         return -1;
238     }
239
240     return mask;
241
242 }
243
244 /***********************************************************************
245  * This function will print a help message describing the characters
246  * that can be parsed by lio_parse_io_arg1().
247  * They will be printed one per line.
248  *  (rrl 04/96)
249  ***********************************************************************/
250 void
251 lio_help1(char *prefix)
252 {
253     int ind;
254
255     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
256         printf("%s %s : %s\n", prefix,
257             Lio_info1[ind].token, Lio_info1[ind].desc);
258     }
259
260     return;
261 }
262
263 /***********************************************************************
264  * This function will parse a string and return the desired io-method.
265  * This function will take a comma separated list of io type and wait
266  * method tokens as defined in Lio_info2[].  If a token does not match
267  * any of the tokens in Lio_info2[], it will be coverted to a number.
268  * If it was a number, those bits are also set.
269  * 
270  *  (rrl 04/96)
271  ***********************************************************************/
272 int
273 lio_parse_io_arg2(char *string, char **badtoken)
274 {
275    char *token = string;
276    char *cc = token;
277    char savecc;
278    int found;
279    int mask=0;
280
281    int tmp;
282    int ind;
283    char chr;
284
285    if ( token == NULL )
286         return -1;
287
288    for (;;) {
289         for (; ((*cc != ',') && (*cc != '\0')); cc++);
290         savecc = *cc;
291         *cc = '\0';
292
293         found = 0; 
294
295         /*
296          * Determine if token is a valid string or number and if
297          * so, add the bits to the mask.
298           */
299         for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
300             if ( strcmp(token, Lio_info2[ind].token) == 0 ) {
301                 mask |= Lio_info2[ind].bits;
302                 found = 1;
303                 break;
304             }
305         }
306
307         /*
308          * If token does not match one of the defined tokens, determine
309          * if it is a number, if so, add the bits.
310          */
311         if ( !found ) {
312             if (sscanf(token, "%i%c", &tmp, &chr) == 1 ) {
313                 mask |= tmp;
314                 found=1;
315             }
316         }
317
318         *cc = savecc;
319
320         if (!found) {  /* token is not valid */
321             if ( badtoken != NULL)
322                 *badtoken = token;
323             return(-1);
324         }
325
326         if (savecc == '\0')
327             break;
328
329         token = ++cc;
330     }
331
332     return mask;
333 }
334
335 /***********************************************************************
336  * This function will print a help message describing the tokens
337  * that can be parsed by lio_parse_io_arg2().
338  * It will print them one per line.
339  *
340  * (rrl 04/96)
341  ***********************************************************************/
342 void
343 lio_help2(char *prefix)
344 {
345     int ind;
346
347     for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
348         printf("%s %s : %s\n", prefix,
349             Lio_info2[ind].token, Lio_info2[ind].desc);
350     }
351     return;
352 }
353
354 #ifndef linux
355 /***********************************************************************
356  * This is an internal signal handler.
357  * If the handler is called, it will increment the Received_signal
358  * global variable.
359  ***********************************************************************/
360 static void
361 lio_async_signal_handler(int sig)
362 {
363         if ( Debug_level )
364             printf("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
365                 __FILE__, __LINE__, sig, Received_signal+1);
366
367         Received_signal++;
368
369         return;
370 }
371 #endif
372
373 /***********************************************************************
374  * lio_random_methods
375  * This function will randomly choose an io type and wait method
376  * from set of io types and wait methods.  Since this information
377  * is stored in a bitmask, it randomly chooses an io type from
378  * the io type bits specified and does the same for wait methods.
379  *
380  * Return Value
381  * This function will return a value with all non choosen io type
382  * and wait method bits cleared.  The LIO_RANDOM bit is also 
383  * cleared.  All other bits are left unchanged.
384  *
385  * (rrl 04/96)
386  ***********************************************************************/
387 int
388 lio_random_methods(long curr_mask)
389 {
390     int mask=0;
391     long random_bit(long);
392
393     /* remove random select, io type, and wait method bits from curr_mask */
394     mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
395
396     /* randomly select io type from specified io types */
397     mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
398
399     /* randomly select wait methods  from specified wait methods */
400     mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
401
402     return mask;
403 }
404
405 /***********************************************************************
406  * Generic write function 
407  * This function can be used to do a write using write(2), writea(2),
408  * aio_write(3), writev(2), pwrite(2),
409  * or single stride listio(2)/lio_listio(3).
410  * By setting the desired bits in the method
411  * bitmask, the caller can control the type of write and the wait method
412  * that will be used.  If no io type bits are set, write will be used.
413  *
414  * If async io was attempted and no wait method bits are set then the
415  * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
416  * aio_write(3) and lio_listio(3).
417  *
418  * If multiple wait methods are specified, 
419  * only one wait method will be used. The order is predetermined.
420  *
421  * If the call specifies a signal and one of the two signal wait methods,
422  * a signal handler for the signal is set.  This will reset an already
423  * set handler for this signal. 
424  *
425  * If the LIO_RANDOM method bit is set, this function will randomly
426  * choose a io type and wait method from bits in the method argument.
427  *
428  * If an error is encountered, an error message will be generated
429  * in a internal static buffer.  If errmsg is not NULL, it will
430  * be updated to point to the static buffer, allowing the caller
431  * to print the error message.
432  *
433  * Return Value
434  *   If a system call fails, -errno is returned.
435  *   If LIO_WAIT_NONE bit is set, the return value is the return value
436  *   of the system call.
437  *   If the io did not fail, the amount of data written is returned.
438  *      If the size the system call say was written is different
439  *      then what was asked to be written, errmsg is updated for
440  *      this error condition.  The return value is still the amount
441  *      the system call says was written.  
442  *
443  * (rrl 04/96)
444  ***********************************************************************/
445 int
446 lio_write_buffer(fd, method, buffer, size, sig, errmsg, wrd)
447 int fd;         /* open file descriptor */
448 int method;     /* contains io type and wait method bitmask */
449 char *buffer;   /* pointer to buffer */
450 int size;       /* the size of the io */
451 int sig;        /* signal to use if async io */
452 char **errmsg;  /* char pointer that will be updated to point to err message */
453 long wrd;       /* to allow future features, use zero for now */
454 {
455     int ret = 0;        /* syscall return or used to get random method */
456 #ifndef linux
457     int omethod = method;
458     int listio_cmd;             /* Holds the listio/lio_listio cmd */
459 #endif
460     struct iovec iov;   /* iovec for writev(2) */
461
462     /*
463      * If LIO_RANDOM bit specified, get new method randomly.
464      */
465     if ( method & LIO_RANDOM ) {
466         if( Debug_level > 3 )
467                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
468         method = lio_random_methods(method);
469         if ( Debug_level > 2 )
470             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
471     }
472
473     if ( errmsg != NULL )
474         *errmsg = Errormsg;
475
476     Rec_signal=Received_signal; /* get the current number of signals received */
477     bzero(&iov, sizeof(struct iovec));
478     iov.iov_base = buffer;
479     iov.iov_len = size;
480
481     /*
482      * If the LIO_USE_SIGNAL bit is not set, only use the signal
483      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
484      * Otherwise there is not necessary a signal handler to trap
485      * the signal.
486      */
487     if ( sig && !(method & LIO_USE_SIGNAL) && 
488         ! (method & LIO_WAIT_SIGTYPES) ){
489
490         sig=0;  /* ignore signal parameter */
491     }
492
493     /*
494      * only setup signal hander if sig was specified and
495      * a sig wait method was specified.
496      * Doing this will change the handler for this signal.  The
497      * old signal handler will not be restored.
498      *** restoring the signal handler could be added ***
499      */
500
501     /*
502      * Determine the system call that will be called and produce
503      * the string of the system call and place it in Lio_SysCall.
504      * Execute the system call and check for system call failure.
505      * If sync i/o, return the number of bytes written/read.
506      */
507      
508     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
509         /*
510          * write(2) is used if LIO_IO_SYNC bit is set or not none
511          * of the LIO_IO_TYPES bits are set (default).
512          */
513
514         sprintf(Lio_SysCall,
515             "write(%d, buf, %d)", fd, size);
516
517         if ( Debug_level ) {
518             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
519         }
520
521         if ((ret = write(fd, buffer, size)) == -1) {
522             sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
523                 __FILE__, __LINE__,
524                 fd, size, errno, strerror(errno));
525             return -errno;
526         }
527
528         if ( ret != size ) {
529             sprintf(Errormsg,
530                 "%s/%d write(%d, buf, %d) returned=%d",
531                     __FILE__, __LINE__,
532                     fd, size, ret);
533         }
534         else if ( Debug_level > 1 )
535             printf("DEBUG %s/%d: write completed without error (ret %d)\n",
536                 __FILE__, __LINE__, ret);
537
538         return ret;
539
540     }
541
542     else if ( method & LIO_IO_SYNCV ) {
543
544         sprintf(Lio_SysCall, 
545                 "writev(%d, &iov, 1) nbyte:%d", fd, size);
546
547         if ( Debug_level ) {
548             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
549         }
550         if ((ret = writev(fd, &iov, 1)) == -1) {
551             sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
552                     __FILE__, __LINE__,
553                 fd, size, errno, strerror(errno));
554             return -errno;
555         }
556
557         if ( ret != size ) {
558             sprintf(Errormsg,
559                 "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
560                     __FILE__, __LINE__,
561                     fd, size, ret);
562         }
563         else if ( Debug_level > 1 )
564             printf("DEBUG %s/%d: writev completed without error (ret %d)\n",
565                 __FILE__, __LINE__, ret);
566
567         return ret;
568     } /* LIO_IO_SYNCV */
569
570     else {
571         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
572         return -1;
573     }
574
575     /*
576      * If there was an error waiting for async i/o to complete,
577      * return the error value (errno) to the caller.
578      * Note: Errormsg should already have been updated.
579      */
580     if ( ret < 0 ) {
581         return ret;
582     }
583
584     /*
585      * If i/o was not waited for (may not have been completed at this time),
586      * return the size that was requested.
587      */
588     if ( ret == 1 )
589         return size;
590
591     /*
592      * check that async io was successful.
593      * Note:  if the there was an system call failure, -errno
594      * was returned and Errormsg should already have been updated.
595      * If amount i/o was different than size, Errormsg should already 
596      * have been updated but the actual i/o size if returned.
597      */
598     
599     return ret;
600 }       /* end of lio_write_buffer */
601
602 /***********************************************************************
603  * Generic read function 
604  * This function can be used to do a read using read(2), reada(2),
605  * aio_read(3), readv(2), pread(2),
606  * or single stride listio(2)/lio_listio(3).
607  * By setting the desired bits in the method
608  * bitmask, the caller can control the type of read and the wait method
609  * that will be used.  If no io type bits are set, read will be used.
610  *
611  * If async io was attempted and no wait method bits are set then the
612  * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
613  * aio_read(3) and lio_listio(3).
614  *
615  * If multiple wait methods are specified, 
616  * only one wait method will be used. The order is predetermined.
617  *
618  * If the call specifies a signal and one of the two signal wait methods,
619  * a signal handler for the signal is set.  This will reset an already
620  * set handler for this signal. 
621  *
622  * If the LIO_RANDOM method bit is set, this function will randomly
623  * choose a io type and wait method from bits in the method argument.
624  *
625  * If an error is encountered, an error message will be generated
626  * in a internal static buffer.  If errmsg is not NULL, it will
627  * be updated to point to the static buffer, allowing the caller
628  * to print the error message.
629  *
630  * Return Value
631  *   If a system call fails, -errno is returned.
632  *   If LIO_WAIT_NONE bit is set, the return value is the return value
633  *   of the system call.
634  *   If the io did not fail, the amount of data written is returned.
635  *      If the size the system call say was written is different
636  *      then what was asked to be written, errmsg is updated for
637  *      this error condition.  The return value is still the amount
638  *      the system call says was written.  
639  *
640  * (rrl 04/96)
641  ***********************************************************************/
642 int
643 lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd)
644 int fd;         /* open file descriptor */
645 int method;     /* contains io type and wait method bitmask */
646 char *buffer;   /* pointer to buffer */
647 int size;       /* the size of the io */
648 int sig;        /* signal to use if async io */
649 char **errmsg;  /* char pointer that will be updated to point to err message */
650 long wrd;       /* to allow future features, use zero for now */
651 {
652     int ret = 0;        /* syscall return or used to get random method */
653 #ifndef linux
654     int listio_cmd;             /* Holds the listio/lio_listio cmd */
655     int omethod = method;
656 #endif
657     struct iovec iov; /* iovec for readv(2) */
658
659     /*
660      * If LIO_RANDOM bit specified, get new method randomly.
661      */
662     if ( method & LIO_RANDOM ) {
663         if( Debug_level > 3 )
664                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
665         method = lio_random_methods(method);
666         if ( Debug_level > 2 )
667             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
668     }
669
670     if ( errmsg != NULL )
671         *errmsg = Errormsg;
672
673     Rec_signal=Received_signal; /* get the current number of signals received */
674     bzero(&iov, sizeof(struct iovec));
675     iov.iov_base = buffer;
676     iov.iov_len = size;
677
678     /*
679      * If the LIO_USE_SIGNAL bit is not set, only use the signal
680      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
681      * Otherwise there is not necessarily a signal handler to trap
682      * the signal.
683      */
684     if ( sig && !(method & LIO_USE_SIGNAL) &&
685         ! (method & LIO_WAIT_SIGTYPES) ){
686
687         sig=0;  /* ignore signal parameter */
688     }
689
690     /*
691      * only setup signal hander if sig was specified and
692      * a sig wait method was specified.
693      * Doing this will change the handler for this signal.  The
694      * old signal handler will not be restored.
695      *** restoring the signal handler could be added ***
696      */
697
698     /*
699      * Determine the system call that will be called and produce
700      * the string of the system call and place it in Lio_SysCall.
701      * Execute the system call and check for system call failure.
702      * If sync i/o, return the number of bytes written/read.
703      */
704      
705     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
706         /*
707          * read(2) is used if LIO_IO_SYNC bit is set or not none
708          * of the LIO_IO_TYPES bits are set (default).
709          */
710
711         sprintf(Lio_SysCall,
712             "read(%d, buf, %d)", fd, size);
713
714         if ( Debug_level ) {
715             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
716         }
717
718         if ((ret = read(fd, buffer, size)) == -1) {
719             sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
720                     __FILE__, __LINE__,
721                 fd, size, errno, strerror(errno));
722             return -errno;
723         }
724
725         if ( ret != size ) {
726             sprintf(Errormsg,
727                 "%s/%d read(%d, buf, %d) returned=%d",
728                     __FILE__, __LINE__,
729                     fd, size, ret);
730         }
731         else if ( Debug_level > 1 )
732             printf("DEBUG %s/%d: read completed without error (ret %d)\n",
733                 __FILE__, __LINE__, ret);
734
735         return ret;
736
737     }
738
739     else if ( method & LIO_IO_SYNCV ) {
740
741         sprintf(Lio_SysCall, 
742                 "readv(%d, &iov, 1) nbyte:%d", fd, size);
743
744         if ( Debug_level ) {
745             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
746         }
747         if ((ret = readv(fd, &iov, 1)) == -1) {
748             sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
749                     __FILE__, __LINE__,
750                 fd, size, errno, strerror(errno));
751             return -errno;
752         }
753
754         if ( ret != size ) {
755             sprintf(Errormsg,
756                 "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
757                     __FILE__, __LINE__,
758                     fd, size, ret);
759         }
760         else if ( Debug_level > 1 )
761             printf("DEBUG %s/%d: readv completed without error (ret %d)\n",
762                 __FILE__, __LINE__, ret);
763
764         return ret;
765     } /* LIO_IO_SYNCV */
766
767     else {
768         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
769         return -1;
770     }
771
772     /*
773      * If there was an error waiting for async i/o to complete,
774      * return the error value (errno) to the caller.
775      * Note: Errormsg should already have been updated.
776      */
777     if ( ret < 0 ) {
778         return ret;
779     }
780
781     /*
782      * If i/o was not waited for (may not have been completed at this time),
783      * return the size that was requested.
784      */
785     if ( ret == 1 )
786         return size;
787
788     /*
789      * check that async io was successful.
790      * Note:  if the there was an system call failure, -errno
791      * was returned and Errormsg should already have been updated.
792      * If amount i/o was different than size, Errormsg should already 
793      * have been updated but the actual i/o size if returned.
794      */
795     
796     return ret;
797 }       /* end of lio_read_buffer */
798
799
800 #ifndef linux
801 /***********************************************************************
802  * This function will check that async io was successful.
803  * It can also be used to check sync listio since it uses the
804  * same method.
805  *
806  * Return Values
807  *  If status.sw_error is set, -status.sw_error is returned.
808  *  Otherwise sw_count's field value is returned.
809  *
810  * (rrl 04/96)
811  ***********************************************************************/
812 int
813 lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
814 {
815     int ret;
816     int cnt = 1;
817
818     /* The I/O may have been synchronous with signal completion.  It doesn't
819      * make sense, but the combination could be generated.  Release the
820      * completion signal here otherwise it'll hang around and bite us
821      * later.
822      */
823     if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
824         sigrelse( aiocbp->aio_sigevent.sigev_signo );
825
826     ret = aio_error( aiocbp );
827
828     while( ret == EINPROGRESS ){
829         ret = aio_error( aiocbp );
830         ++cnt;
831     }
832     if( cnt > 1 ){
833         sprintf(Errormsg,
834                 "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
835                 __FILE__, __LINE__, io_type, cnt, method,
836                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
837                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
838                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
839                  "unknown") );
840         return -ret;
841     }
842
843     if( ret != 0 ){
844         sprintf(Errormsg,
845                 "%s/%d %s, aio_error = %d %s; random method %#o",
846                 __FILE__, __LINE__, io_type,
847                 ret, strerror(ret),
848                 method );
849         return -ret;
850     }
851     ret = aio_return( aiocbp );
852     if( ret != size ){
853         sprintf(Errormsg,
854                 "%s/%d %s, aio_return not as expected(%d), but actual:%d",
855                 __FILE__, __LINE__, io_type,
856                 size, ret);
857
858 #ifdef BUG1_workaround
859         if( ret == 0 ){
860                 ret = size;
861                 if( Debug_level > 1 ){
862                         printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
863                                __FILE__, __LINE__, io_type, ret);
864                 }
865         }
866 #endif /* BUG1_workaround */
867
868     }
869     else if( Debug_level > 1 ){
870         printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
871             __FILE__, __LINE__, io_type, ret);
872     }
873
874     return ret;
875
876 } /* end of lio_check_asyncio */
877
878
879 /***********************************************************************
880  *
881  * This function will wait for async io to complete.
882  * If multiple wait methods are specified, the order is predetermined
883  * to LIO_WAIT_RECALL,
884  * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
885  * then LIO_WAIT_NONE.
886  *
887  * If no wait method was specified the default wait method is: recall(2)
888  * or aio_suspend(3), as appropriate.
889  *
890  * Return Values
891  *      <0: errno of failed recall
892  *      0 : async io was completed
893  *      1 : async was not waited for, io may not have completed.
894  *
895  * (rrl 04/96)
896  ***********************************************************************/
897 int
898 lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
899 {
900     int cnt;
901
902     if ( (method & LIO_WAIT_RECALL)
903         || ((method & LIO_WAIT_TYPES) == 0) ){
904         /*
905          * If method has LIO_WAIT_RECALL bit set or method does
906          * not have any wait method bits set (default), use recall/aio_suspend.
907          */
908         if ( Debug_level > 2 )
909             printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__,
910                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
911                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
912                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
913                  "unknown") );
914
915         aioary[0] = aiocbp;
916         ret = aio_suspend( aioary, 1, NULL );
917         if( (ret == -1) && (errno == EINTR) ){
918                 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ){
919                         if( Debug_level > 2 ){
920                                 printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
921                                        __FILE__, __LINE__ );
922                         }
923                 }
924                 else {
925                         sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
926                                 __FILE__, __LINE__,
927                                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
928                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
929                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
930                                  "unknown") );
931                         return -errno;
932                 }
933         }
934         else if ( ret ) {
935             sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
936                     __FILE__, __LINE__,
937                 fd, errno, strerror(errno));
938             return -errno;
939         }
940     } else if ( method & LIO_WAIT_ACTIVE ) {
941         if ( Debug_level > 2 )
942             printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__);
943
944         /* loop while aio_error() returns EINPROGRESS */
945         cnt=0;
946         while(1){
947                 ret = aio_error( aiocbp );
948                 if( (ret == 0) || (ret != EINPROGRESS) ){
949                         break;
950                 }
951                 ++cnt;
952         }
953
954         if ( Debug_level > 5 && cnt && (cnt % 50) == 0 )
955                 printf("DEBUG %s/%d: wait active cnt = %d\n",
956                     __FILE__, __LINE__, cnt);
957
958     } else if ( method & LIO_WAIT_SIGPAUSE ) {
959         if ( Debug_level > 2 )
960             printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__);
961         pause();
962
963     } else if ( method & LIO_WAIT_SIGACTIVE ) {
964         if ( Debug_level > 2 )
965             printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__);
966         if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
967                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
968         else {
969                 printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
970                 return -1;
971         }
972         /* loop waiting for signal */
973         while ( Received_signal == Rec_signal ){
974                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
975         }
976
977     } else if ( method & LIO_WAIT_NONE ) {
978         if ( Debug_level > 2 )
979             printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__);
980         /* It's broken because the aiocb/iosw is an automatic variable in
981          * lio_{read,write}_buffer, so when the function returns and the
982          * I/O completes there will be nowhere to write the I/O status.
983          * It doesn't cause a problem on unicos--probably because of some
984          * compiler quirk, or an accident.  It causes POSIX async I/O
985          * to core dump some threads.   spr/pv 705909.  6/27/97 roehrich
986          */
987         sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
988                 __FILE__, __LINE__ );
989         return -1;
990     }
991     else {
992         if( Debug_level > 2 )
993             printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ );
994         return -1;
995     }
996
997     return 0;
998
999 } /* end of lio_wait4asyncio */
1000
1001 #endif /* ifndef linux */
1002
1003 #if UNIT_TEST
1004 /***********************************************************************
1005  * The following code is provided as unit test.
1006  * Just define add "-DUNIT_TEST=1" to the cc line.
1007  * 
1008  * (rrl 04/96)
1009  ***********************************************************************/
1010 struct unit_info_t {
1011     int method;
1012     int sig;
1013     char *str;
1014 }  Unit_info[] = {
1015     { LIO_IO_SYNC, 0, "sync io" },
1016     { LIO_IO_SYNCV, 0, "sync readv/writev" },
1017     { LIO_IO_SYNCP, 0, "sync pread/pwrite" },
1018     { LIO_IO_ASYNC, 0, "async io, def wait" },
1019     { LIO_IO_SLISTIO,     0, "sync listio" },
1020     { LIO_IO_ALISTIO,     0, "async listio, def wait" },
1021     { LIO_IO_ASYNC|LIO_WAIT_ACTIVE,     0, "async active" },
1022     { LIO_IO_ASYNC|LIO_WAIT_RECALL,     0, "async recall/suspend" },
1023     { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE,   SIGUSR1, "async sigpause" },
1024     { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async sigactive" },
1025     { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE,     0, "async listio active" },
1026     { LIO_IO_ALISTIO|LIO_WAIT_RECALL,     0, "async listio recall" },
1027     { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async listio sigactive" },
1028     { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE,  SIGUSR1, "async listio sigpause" },
1029     { LIO_IO_ASYNC,     SIGUSR2, "async io, def wait, sigusr2" },
1030     { LIO_IO_ALISTIO,   SIGUSR2, "async listio, def wait, sigusr2" },
1031 };
1032
1033 int
1034 main(argc, argv)
1035 int argc;
1036 char **argv;
1037 {
1038     extern char *optarg;
1039     extern int optind;
1040
1041     int fd;
1042     char *err;
1043     char buffer[4096];
1044     int size=4096;
1045     int ret;
1046     int ind;
1047     int iter=3;
1048     int method;
1049     int exit_status = 0;
1050     int c;
1051     int i;
1052     char *symbols = NULL;
1053     int die_on_err = 0;
1054
1055     while( (c = getopt(argc,argv,"s:di:")) != -1 ){
1056         switch(c){
1057         case 's': symbols = optarg; break;
1058         case 'd': ++die_on_err; break;
1059         case 'i': iter = atoi(optarg); break;
1060         }
1061     }
1062
1063     if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1 ) {
1064         perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
1065         exit(1);
1066     }
1067
1068     Debug_level=9;
1069
1070     if ( symbols != NULL ) {
1071         if ( (method=lio_parse_io_arg2(symbols,  &err)) == -1 ){
1072             printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
1073             symbols, err);
1074             if( die_on_err )
1075                 exit(1);
1076         }
1077         else
1078             printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method);
1079
1080         exit_status = 0;
1081         for(ind=0; ind < iter; ind++ ) {
1082           memset( buffer, 'A', 4096 );
1083           if( lseek(fd, 0, 0) == -1 ){
1084                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1085                        __LINE__, errno );
1086                 ++exit_status;
1087           }
1088           if ((ret=lio_write_buffer(fd, method, buffer,
1089                         size, SIGUSR1, &err, 0)) != size ) {
1090             printf("lio_write_buffer returned -1, err = %s\n", err);
1091           } else
1092             printf("lio_write_buffer returned %d\n", ret);
1093
1094           memset( buffer, 'B', 4096 );
1095           if( lseek(fd, 0, 0) == -1 ){
1096                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1097                        __LINE__, errno );
1098                 ++exit_status;
1099           }
1100           if ((ret=lio_read_buffer(fd, method, buffer,
1101                         size, SIGUSR2, &err, 0)) != size ) {
1102             printf("lio_read_buffer returned -1, err = %s\n", err);
1103           } else
1104             printf("lio_read_buffer returned %d\n", ret);
1105
1106           for( i = 0; i < 4096; ++i ){
1107                 if( buffer[i] != 'A' ){
1108                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1109                         ++exit_status;
1110                         break;
1111                 }
1112           }
1113
1114           if( exit_status )
1115                 exit(exit_status);
1116
1117         }
1118
1119         unlink("unit_test_file");
1120         exit(0);
1121     }
1122
1123     for(ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++ ) {
1124
1125         printf("\n********* write %s ***************\n", Unit_info[ind].str);
1126         if( lseek(fd, 0, 0) == -1 ){
1127                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1128                        __LINE__, errno );
1129                 ++exit_status;
1130         }
1131
1132         memset( buffer, 'A', 4096 );
1133         if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer,
1134                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1135             printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1136                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1137             ++exit_status;
1138             if( die_on_err )
1139                 exit(exit_status);
1140         } else{
1141             printf("lio_write_buffer returned %d\n", ret);
1142         }
1143
1144         printf("\n********* read %s ***************\n", Unit_info[ind].str);
1145         if( lseek(fd, 0, 0) == -1 ){
1146                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1147                        __LINE__, errno );
1148                 ++exit_status;
1149         }
1150         memset( buffer, 'B', 4096 );
1151         if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer,
1152                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1153             printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1154                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1155             ++exit_status;
1156             if( die_on_err )
1157                 exit(exit_status);
1158         } else {
1159             printf("lio_read_buffer returned %d\n", ret);
1160         }
1161
1162           for( i = 0; i < 4096; ++i ){
1163                 if( buffer[i] != 'A' ){
1164                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1165                         ++exit_status;
1166                         if( die_on_err )
1167                                 exit(exit_status);
1168                         break;
1169                 }
1170           }
1171
1172         fflush(stdout);
1173         fflush(stderr);
1174         sleep(1);
1175
1176     }
1177
1178     unlink("unit_test_file");
1179
1180     exit(exit_status);
1181 }
1182 #endif