From 66c098b8fc67a8892d55deeba064eac937115f63 Mon Sep 17 00:00:00 2001 From: Bruce Cran Date: Tue, 27 Nov 2012 12:16:07 +0000 Subject: [PATCH] Fix windowsaio IO error handling and document device write access issue on Windows and FreeBSD. Signed-off-by: Jens Axboe --- HOWTO | 37 ++++++++++--------- engines/windowsaio.c | 86 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 102 insertions(+), 21 deletions(-) diff --git a/HOWTO b/HOWTO index 6391b82a..32e5d668 100644 --- a/HOWTO +++ b/HOWTO @@ -61,7 +61,7 @@ bottom, it contains the following basic parameters: Num threads How many threads or processes should we spread this workload over. - + The above are the basic parameters defined for a workload, in addition there's a multitude of parameters that modify other aspects of how this job behaves. @@ -274,11 +274,14 @@ filename=str Fio normally makes up a filename based on the job name, as the two working files, you would use filename=/dev/sda:/dev/sdb. On Windows, disk devices are accessed as \\.\PhysicalDrive0 for the first device, \\.\PhysicalDrive1 - for the second etc. If the wanted filename does need to - include a colon, then escape that with a '\' character. - For instance, if the filename is "/dev/dsk/foo@3,0:c", - then you would use filename="/dev/dsk/foo@3,0\:c". - '-' is a reserved name, meaning stdin or stdout. Which of the + for the second etc. + Note: Windows and FreeBSD prevent write access to areas of the disk + containing in-use data (e.g. filesystems). + If the wanted filename does need to include a colon, then escape that + with a '\' character. + For instance, if the filename is "/dev/dsk/foo@3,0:c", + then you would use filename="/dev/dsk/foo@3,0\:c". + '-' is a reserved name, meaning stdin or stdout. Which of the two depends on the read/write direction set. opendir=str Tell fio to recursively add any file it can find in this @@ -1086,7 +1089,7 @@ verify_backlog_batch=int Control how many blocks fio will verify less than verify_backlog then not all blocks will be verified, if verify_backlog_batch is larger than verify_backlog, some blocks will be verified more than once. - + stonewall wait_for_previous Wait for preceeding jobs in the job file to exit, before starting this one. Can be used to insert serialization @@ -1132,7 +1135,7 @@ read_iolog=str Open an iolog with the specified file name and replay the for how to capture such logging data. For blktrace replay, the file needs to be turned into a blkparse binary data file first (blkparse -o /dev/null -d file_for_fio.bin). - + replay_no_stall=int When replaying I/O with read_iolog the default behavior is to attempt to respect the time stamps within the log and replay them with the appropriate delay between IOPS. By @@ -1295,12 +1298,12 @@ ignore_error=str Sometimes you want to ignore some errors during test may be symbol ('ENOSPC', 'ENOMEM') or integer. Example: ignore_error=EAGAIN,ENOSPC:122 - This option will ignore EAGAIN from READ, and ENOSPC and - 122(EDQUOT) from WRITE. + This option will ignore EAGAIN from READ, and ENOSPC and + 122(EDQUOT) from WRITE. error_dump=bool If set dump every error even if it is non fatal, true by default. If disabled only fatal error will be dumped - + cgroup=str Add job to this control group. If it doesn't exist, it will be created. The system must have a mounted cgroup blkio mount point for this to work. If your system doesn't have it @@ -1382,7 +1385,7 @@ that defines them is selected. [e4defrag] donorname=str File will be used as a block donor(swap extents between files) [e4defrag] inplace=int - Configure donor file blocks allocation strategy + Configure donor file blocks allocation strategy 0(default): Preallocate donor's file on init 1 : allocate space immidietly inside defragment event, and free right after event @@ -1570,8 +1573,8 @@ Split up, the format is as follows: Read merges, write merges, Read ticks, write ticks, Time spent in queue, disk utilization percentage - Additional Info (dependant on continue_on_error, default off): total # errors, first error code - + Additional Info (dependant on continue_on_error, default off): total # errors, first error code + Additional Info (dependant on description being set): Text description Completion latency percentiles can be a grouping of up to 20 sets, so @@ -1587,7 +1590,7 @@ there will be a disk utilization section. 8.0 Trace file format --------------------- -There are two trace file format that you can encounter. The older (v1) format +There are two trace file format that you can encounter. The older (v1) format is unsupported since version 1.20-rc3 (March 2008). It will still be described below in case that you get an old trace and want to understand it. @@ -1624,7 +1627,7 @@ filename action The filename is given as an absolute path. The action can be one of these: add Add the given filename to the trace -open Open the file with the given filename. The filename has to have +open Open the file with the given filename. The filename has to have been added with the add action before. close Close the file with the given filename. The file has to have been opened before. @@ -1635,7 +1638,7 @@ The file io action format: filename action offset length The filename is given as an absolute path, and has to have been added and opened -before it can be used with this format. The offset and length are given in +before it can be used with this format. The offset and length are given in bytes. The action can be one of these: wait Wait for 'offset' microseconds. Everything below 100 is discarded. diff --git a/engines/windowsaio.c b/engines/windowsaio.c index ea899698..db757304 100644 --- a/engines/windowsaio.c +++ b/engines/windowsaio.c @@ -14,6 +14,8 @@ typedef BOOL (WINAPI *CANCELIOEX)(HANDLE hFile, LPOVERLAPPED lpOverlapped); +int geterrno_from_win_error (DWORD code, int deferrno); + struct fio_overlapped { OVERLAPPED o; struct io_u *io_u; @@ -48,6 +50,82 @@ static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter); static int fio_windowsaio_init(struct thread_data *td); static int fio_windowsaio_open_file(struct thread_data *td, struct fio_file *f); static int fio_windowsaio_close_file(struct thread_data fio_unused *td, struct fio_file *f); +static int win_to_poxix_error(DWORD winerr); + +static int win_to_poxix_error(DWORD winerr) +{ + switch (winerr) + { + case ERROR_FILE_NOT_FOUND: return ENOENT; + case ERROR_PATH_NOT_FOUND: return ENOENT; + case ERROR_ACCESS_DENIED: return EACCES; + case ERROR_INVALID_HANDLE: return EBADF; + case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; + case ERROR_INVALID_DATA: return EINVAL; + case ERROR_OUTOFMEMORY: return ENOMEM; + case ERROR_INVALID_DRIVE: return ENODEV; + case ERROR_NOT_SAME_DEVICE: return EXDEV; + case ERROR_WRITE_PROTECT: return EROFS; + case ERROR_BAD_UNIT: return ENODEV; + case ERROR_SHARING_VIOLATION: return EACCES; + case ERROR_LOCK_VIOLATION: return EACCES; + case ERROR_SHARING_BUFFER_EXCEEDED: return ENOLCK; + case ERROR_HANDLE_DISK_FULL: return ENOSPC; + case ERROR_NOT_SUPPORTED: return ENOSYS; + case ERROR_FILE_EXISTS: return EEXIST; + case ERROR_CANNOT_MAKE: return EPERM; + case ERROR_INVALID_PARAMETER: return EINVAL; + case ERROR_NO_PROC_SLOTS: return EAGAIN; + case ERROR_BROKEN_PIPE: return EPIPE; + case ERROR_OPEN_FAILED: return EIO; + case ERROR_NO_MORE_SEARCH_HANDLES: return ENFILE; + case ERROR_CALL_NOT_IMPLEMENTED: return ENOSYS; + case ERROR_INVALID_NAME: return ENOENT; + case ERROR_WAIT_NO_CHILDREN: return ECHILD; + case ERROR_CHILD_NOT_COMPLETE: return EBUSY; + case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY; + case ERROR_SIGNAL_REFUSED: return EIO; + case ERROR_BAD_PATHNAME: return ENOENT; + case ERROR_SIGNAL_PENDING: return EBUSY; + case ERROR_MAX_THRDS_REACHED: return EAGAIN; + case ERROR_BUSY: return EBUSY; + case ERROR_ALREADY_EXISTS: return EEXIST; + case ERROR_NO_SIGNAL_SENT: return EIO; + case ERROR_FILENAME_EXCED_RANGE: return EINVAL; + case ERROR_META_EXPANSION_TOO_LONG: return EINVAL; + case ERROR_INVALID_SIGNAL_NUMBER: return EINVAL; + case ERROR_THREAD_1_INACTIVE: return EINVAL; + case ERROR_BAD_PIPE: return EINVAL; + case ERROR_PIPE_BUSY: return EBUSY; + case ERROR_NO_DATA: return EPIPE; + case ERROR_MORE_DATA: return EAGAIN; + case ERROR_DIRECTORY: return ENOTDIR; + case ERROR_PIPE_CONNECTED: return EBUSY; + case ERROR_NO_TOKEN: return EINVAL; + case ERROR_PROCESS_ABORTED: return EFAULT; + case ERROR_BAD_DEVICE: return ENODEV; + case ERROR_BAD_USERNAME: return EINVAL; + case ERROR_OPEN_FILES: return EAGAIN; + case ERROR_ACTIVE_CONNECTIONS: return EAGAIN; + case ERROR_DEVICE_IN_USE: return EAGAIN; + case ERROR_INVALID_AT_INTERRUPT_TIME: return EINTR; + case ERROR_IO_DEVICE: return EIO; + case ERROR_NOT_OWNER: return EPERM; + case ERROR_END_OF_MEDIA: return ENOSPC; + case ERROR_EOM_OVERFLOW: return ENOSPC; + case ERROR_BEGINNING_OF_MEDIA: return ESPIPE; + case ERROR_SETMARK_DETECTED: return ESPIPE; + case ERROR_NO_DATA_DETECTED: return ENOSPC; + case ERROR_POSSIBLE_DEADLOCK: return EDEADLOCK; + case ERROR_CRC: return EIO; + case ERROR_NEGATIVE_SEEK: return EINVAL; + case ERROR_DISK_FULL: return ENOSPC; + case ERROR_NOACCESS: return EFAULT; + case ERROR_FILE_INVALID: return ENXIO; + } + + return winerr; +} int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags) @@ -350,7 +428,7 @@ static int fio_windowsaio_queue(struct thread_data *td, struct io_u *io_u) case DDIR_SYNC_FILE_RANGE: success = FlushFileBuffers(io_u->file->hFile); if (!success) - io_u->error = GetLastError(); + io_u->error = win_to_poxix_error(GetLastError()); return FIO_Q_COMPLETED; break; @@ -368,7 +446,7 @@ static int fio_windowsaio_queue(struct thread_data *td, struct io_u *io_u) if (success || GetLastError() == ERROR_IO_PENDING) rc = FIO_Q_QUEUED; else { - io_u->error = GetLastError(); + io_u->error = win_to_poxix_error(GetLastError()); io_u->resid = io_u->xfer_buflen; } @@ -390,7 +468,7 @@ static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter) wd = ctx->wd; do { - if (!GetQueuedCompletionStatus(ctx->iocp, &bytes, &ulKey, &ovl, 250)) + if (!GetQueuedCompletionStatus(ctx->iocp, &bytes, &ulKey, &ovl, 250) && ovl == NULL) continue; fov = CONTAINING_RECORD(ovl, struct fio_overlapped, o); @@ -401,7 +479,7 @@ static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter) io_u->error = 0; } else { io_u->resid = io_u->xfer_buflen; - io_u->error = ovl->Internal; + io_u->error = win_to_poxix_error(GetLastError()); } fov->io_complete = TRUE; -- 2.25.1