📄 dtaio.c
字号:
/**************************************************************************** * * * COPYRIGHT (c) 1990 - 2004 * * This Software Provided * * By * * Robin's Nest Software Inc. * * * * Permission to use, copy, modify, distribute and sell this software and * * its documentation for any purpose and without fee is hereby granted, * * provided that the above copyright notice appear in all copies and that * * both that copyright notice and this permission notice appear in the * * supporting documentation, and that the name of the author not be used * * in advertising or publicity pertaining to distribution of the software * * without specific, written prior permission. * * * * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * * NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL * * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF * * THIS SOFTWARE. * * * ****************************************************************************//* * Module: dtaio.c * Author: Robin T. Miller * Date: August 26, 1993 * * Description: * Functions to handle POSIX Asynchronous I/O requests for 'dt' program. */#if defined(AIO)#include "dt.h"#include <aio.h>#include <limits.h>#include <sys/stat.h>#if !defined(AIO_PRIO_DFL)# define AIO_PRIO_DFL 0 /* Default scheduling priority. */#endif /* !defined(AIO_PRIO_DFL) *//* * Modification History: * * February 13th, 2004 by Robin Miller. * Factor in the file position when doing reverse I/O, to avoid * writing/reading into that area (which is now deemed protected). * * November 17th, 2003 by Robin Miller. * Breakup output to stdout or stderr, rather than writing * all output to stderr. If output file is stdout ('-') or a log * file is specified, then all output reverts to stderr. * * January 17th, 2003 by Robin Miller. * On HP-UX, accept ENXIO for I/O's pass EOF. * * November 14th, 2002 by Robin Miller. * On HP-UX, initialize aiocb->aio_sigevent field, or else * EINVAL is returned. aio_sigevent.sigev_notify = SIGEV_NONE; * * June 25th, 2001 by Robin Miller. * Restructured code associated with Tru64 Unix EEI, so we obtain * the EEI status for all tape errors, not just EIO errors. * * January 26th, 2001 by Robin Miller. * Added support for reverse reading and writing. * * January 24th, 2001 by Robin Miller. * Add support for variable I/O requests sizes. * * January 14th, 2001 by Robin Miller. * Added support for multiple volumes option. * Fixed multi-volume write w/lbdata option problem. * * October 4th, 2000 by Robin Miller. * Update is_Eof() to accept ENXIO for AIO reads @ EOM on * SCO UnixWare systems. All other systems return ENOSPC or zero. * * May 9th, 2000 by Robin Miller. * Ensure the closing flag gets reset in dtaio_close_file() before * calling close_file(), or the file descriptor won't get closed! * * May 8th, 2000 by Robin Miller. * Honor the di_closing flag, to avoid a race condition with the * close function being called again while still closing, from the * terminate() routine called by the runtime= alarm, or signals. * * February 17th, 2000 by Robin Miller. * Adding better support for multi-volume tape testing. Mainly, * make it work with writing multiple tape files, rather than one file. * * January 6th, 2000 by Robin Miller. * Added support for multi-volume media. * Added a couple missing aio_return() calls. * * December 30th, 1999 by Robin Miller. * Modify call to do_random() to pass the transfer size. * * November 10th, 1999 by Robin Miller. * If aio_return() fails, report device information. * * August 7th, 1999 by Robin Miller. * Minor mods to support AIO on SCO UnixWare 7.1. * * July 29, 1999 by Robin Miller. * Merge in changes made to compile on FreeBSD. * * July 22nd, 1999 by Robin Miller. * o Added support for IOT (DJ's) test pattern. * o Fixed problem writing wrong starting lba, when lbdata * and random I/O options were enabled. * * July 5th, 1999 by Robin Miller. * Cleanup of compilation warnings on Linux. * * May 27, 1999 by Robin Miller. * Added support for micro-second delays. * * March 1, 1999 by Robin Miller. * For tapes when Debug is enabled, report the file number. * * January 13, 1998 by Robin Miller. * Add support for restarting I/O's after EEI reset recovery. * Modified dtaio_waitall() to optionally adjust data/file counts. * * December 21, 1998 by Robin Miller. * Updates necessary to match tape API changes. * * November 16, 1998 by Robin Miller. * Added pointer to current AIO control block for error reporting. * * October 26, 1998 by Robin Miller. * o Fix incorrect record number displayed when Debug is enabled. * o Don't exit read/write loops when processing partial records. * o Fix problem in write function, where short write processing, * caused us not to write sufficent data bytes (actually, the * file loop in write_file() caused dtaio_write_data() to be * called again, and we'd actually end up writing too much! * o When random I/O and lbdata options are both enabled, use the * file offset seeked to as the starting lbdata address. * * March 20, 1998 by Robin Miller. * Update counts in dtaio_waitall() for accurate statistics. * * January 28, 1998 by Robin Miller. * Add dtaio_close() function, to wait for queued I/O's when we're * aborting, to avoid kernel I/O rundown problem, which panic's * the system if we close the CAM disk driver device descriptor, * prior to AIO's completing (fixed in steelos by Anton Verhulst). * * January 9, 1998 by Robin Miller. * Don't initialize data buffer being written for "disable=compare" * which yields better performance. * * April 3, 1997 by Robin Miller. * Removed use of undocumented AIO_SEEK_CUR in aio_offset. * Also fixed bug where random I/O offset was clobbered, thus * resulting in sequential I/O. * * February 28, 1996 by Robin Miller. * Added support for copying and verifying device/files. * Modified logic so read errors honor users' error limit. * [ NOTE: Copy and verify operations are done sequentially. ] * * November 11, 1995 by Robin Miller. * Fix bug with init'ing and performing pad byte verification. * This caused variable length reads with small increment values * to report an (invalid) pad byte data compare error. e.g.: * * % dt of=/dev/rmt0h min=10k max=64k incr=1 pattern=incr * * July 17, 1995 by Robin Miller. * Conditionalize aio_suspend() via "#if defined(POSIX_4D11)" for * earlier POSIX drafts so only one copy of this file is necessary. * [ NOTE: This is accomplished via -DPOSIX_4D11 in our Makefile. ] * * July 15, 1995 by Robin Miller. * Fix end of media error handling (ENOSPC), and cleanup code. * * July 14, 1995 by Robin Miller. * Add logic to allow rotating through 1st ROTATE_SIZE byes of buffers. * [ This option was being silently ignored before, and nobody knew. ] * * April 15, 1994 by Wayne Casagrande. * Update aiosuspend() interface, which now takes different arguments * due to POSIX standard changing. * * January 20, 1994 by Robin Miller. * When initializing the data buffer, don't do the entire buffer since * init'ing large buffer (e.g. 100m) using min, max, and incr options cause * excessive paging and VERY poor performance. * * October 15, 1993 by Robin Miller. * Sorry folks, major screw up on my part. I forgot to redefine the * test function (tf_write_data) field to point a the dtaio_write_data() * function, so... synchronous writes were still being done (damn!!!). * Also fixed bug when writing to stop looping when end of file reached. *//* * Forward References: */#if 0static void dtaio_checkdevice(struct dinfo *dip);#endifstatic int dtaio_wait(struct dinfo *dip, struct aiocb *acbp);static int dtaio_waitall(struct dinfo *dip, bool canceling);static int dtaio_wait_reads(struct dinfo *dip);static int dtaio_wait_writes(struct dinfo *dip);static int dtaio_process_read(struct dinfo *dip, struct aiocb *acbp);static int dtaio_process_write(struct dinfo *dip, struct aiocb *acbp);#define AIO_BUFS 8 /* Default number of AIO buffers. */#define AIO_NotQed -1 /* AIO request not queued flag. */int aio_bufs = AIO_BUFS; /* The number of AIO buffers. */int aio_index; /* Index to AIO control block. */volatile off_t aio_offset; /* AIO offset (we maintain). */v_large aio_data_bytes; /* Total data bytes per pass. */v_large aio_file_bytes; /* # of tape bytes processed. */vu_long aio_record_count; /* # of records to processed. */u_int32 aio_lba; /* AIO logical block address. *//* * The following variables are meant to be used with tape devices to * backup unprocessed files and/or records due to read-ahead, to be * repositioned prior to the next test or before closing the tape. */u_long aio_data_adjust; /* # of data bytes to adjust. */u_long aio_file_adjust; /* # of tape files to adjust. */u_long aio_record_adjust; /* # of tape record to adjust. */struct aiocb *acbs; /* Pointer to AIO control blocks. */u_char **aiobufs; /* Pointer to base buffer addrs. */struct aiocb *current_acb; /* Current acb for error reports. *//* * Declare the POSIX Asynchronous I/O test functions. */struct dtfuncs aio_funcs = { /* tf_open, tf_close, tf_initialize, */ open_file, dtaio_close_file, dtaio_initialize, /* tf_start_test, tf_end_test, */ init_file, nofunc, /* tf_read_file, tf_read_data, tf_cancel_reads, */ read_file, dtaio_read_data, dtaio_cancel_reads, /* tf_write_file, tf_write_data, tf_cancel_writes, */ write_file, dtaio_write_data, nofunc, /* tf_flush_data, tf_verify_data, tf_reopen_file, */ flush_file, verify_data, reopen_file, /* tf_startup, tf_cleanup, tf_validate_opts */ nofunc, nofunc, validate_opts};/************************************************************************ * * * dtaio_close_file() - Close an open file descriptor. * * * * Description: * * This function does the AIO file descriptor close processing. * * * * Inputs: dip = The device information pointer. * * * * Return Value: * * Returns 0 / -1 = SUCCESS / FAILURE. * * * ************************************************************************/intdtaio_close_file (struct dinfo *dip){ int status = SUCCESS; if (dip->di_closing || (dip->di_fd == NoFd)) { return (status); /* Closing or not open. */ } /* * Avoid cancel'ing I/O more than once using the closing flag. * We can get called again by alarm expiring or signal handler. */ dip->di_closing = TRUE; (void) dtaio_cancel (dip); status = dtaio_waitall (dip, FALSE); dip->di_closing = FALSE; return (close_file (dip));}/* * Allocate and initialize AIO data structures. */intdtaio_initialize (struct dinfo *dip){ struct aiocb *acbp; size_t size = (sizeof(struct aiocb) * aio_bufs); int index; int status = SUCCESS;#if 0 /* * This check isn't being done, since when linked with libaio.a, * AIO is mimiced via multiple threads to any device, not just * character devices as with libaioraw.a */ dtaio_checkdevice (dip);#endif if ( (dip->di_dtype->dt_dtype == DT_TAPE) && raw_flag && (aio_bufs > 1) ) { Printf("Sorry, tapes are limited to 1 AIO with raw option!\n"); aio_bufs = 1; size = (sizeof(struct aiocb) * aio_bufs); } aio_index = 0; aio_offset = (off_t) 0; if (acbs == NULL) { acbs = (struct aiocb *) Malloc (size); bzero ((char *) acbs, size); if (rotate_flag) { size_t psize = (aio_bufs * sizeof(u_char *)); aiobufs = (u_char **) Malloc (psize); bzero ((char *) aiobufs, psize); } } for (index = 0, acbp = acbs; index < aio_bufs; index++, acbp++) { if (acbp->aio_buf == NULL) { acbp->aio_buf = myalloc (data_size, align_offset); if (rotate_flag) { aiobufs[index] = (u_char *) acbp->aio_buf; } } acbp->aio_fildes = AIO_NotQed; acbp->aio_offset = (off_t) 0; acbp->aio_nbytes = block_size; acbp->aio_reqprio = AIO_PRIO_DFL; /* Set default priority. */#if defined(SCO) || defined(HP_UX) /* * Note: The AIO manual recommends setting AIO_RAW, but when * this is set, EINVAL is returned by aio_read/aio_write! */# if defined(SCO) acbp->aio_flags = 0; /* Must be zero to work! */# endif /* defined(SCO) */ acbp->aio_sigevent.sigev_notify = SIGEV_NONE;#if 0 acbp->aio_flags = 0; /*AIO_RAW;*/ /* Required on SVR4.2(?) */ /* * This signaling method did not exist with the first release * of POSIX AIO. Perhaps I'll add this completion method in * a future release. Note: Tru64 Unix now supports this too! */ acbp->aio_sigevent.sigev_signo = /* use with SIGEV_SIGNAL */; acbp->aio_sigevent.sigev_notify = SIGEV_CALLBACK; acbp->aio_sigevent.sigev_func = my_aio_completion_function; acbp->aio_sigevent.sigev_value = acbp;#endif#endif /* defined(SCO) || defined(HP_UX) */ /* * Use first buffer allocated for initial skip reads, etc. */ if (index == 0) data_buffer = (u_char *) acbp->aio_buf; } return (status);}#if 0static voiddtaio_checkdevice (struct dinfo *dip){ struct stat sb; /* * Asynchronous I/O is for character devices *only*. * [ Is this true for all operating systems? ] */ if (fstat (dip->di_fd, &sb) == FAILURE) { report_error("fstat", FALSE); exit (FATAL_ERROR); } if (!S_ISCHR(sb.st_mode) ) { LogMsg (efp, logLevelCrit, 0, "'%s' is NOT a character device, cannot use asynchronous I/O.\n", dip->di_dname); exit (FATAL_ERROR); } return;}#endif /* 0 *//* * Cancel outstanding I/O on the specified file descriptor. */intdtaio_cancel (struct dinfo *dip){ int status; /* * This is not a very useful operation on DEC OSF/1 at this time, * since the drivers do *not* contain a cancel entry point. * So... you cannot actually cancel outstanding I/O requests. */ if ((status = aio_cancel (dip->di_fd, NULL)) == FAILURE) { /* * aio_cancel() returns EBADF if we never issued any AIO! */ if (errno != EBADF) { report_error ("aio_cancel", TRUE); } return (status); } if (debug_flag) { switch (status) { case AIO_ALLDONE: Printf ("All requests completed before cancel...\n"); break; case AIO_CANCELED: Printf ("Outstanding requests were canceled...\n"); break; case AIO_NOTCANCELED: Fprintf ("Outstanding (active?) request NOT canceled...\n"); break; default: Fprintf ("Unexpected status of %d from aio_cancel()...\n", status); break; } } return (status);}intdtaio_cancel_reads (struct dinfo *dip){ int status; struct dtype *dtp = dip->di_dtype; aio_data_adjust = aio_file_adjust = aio_record_adjust = 0L; (void) dtaio_cancel (dip); status = dtaio_waitall (dip, TRUE); if (aio_file_adjust && (dtp->dt_dtype == DT_TAPE) ) { daddr_t count = (daddr_t)aio_file_adjust; /* * Tapes are tricky... we must backup prior to the * last file(s) we processed, then forward space over * its' file mark to be properly positioned (yuck!!!). */ if (end_of_file) count++; status = DoBackwardSpaceFile (dip, count); if (status == SUCCESS) { status = DoForwardSpaceFile (dip, (daddr_t) 1); } } else if (aio_record_adjust && (dtp->dt_dtype == DT_TAPE) ) { /* * If we've read partially into the next file, backup. */ status = DoBackwardSpaceFile (dip, (daddr_t) 1); if (status == SUCCESS) { status = DoForwardSpaceFile (dip, (daddr_t) 1); } } return (status);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -