Fix windowsaio IO error handling and document device write access issue on Windows...
authorBruce Cran <bruce@cran.org.uk>
Tue, 27 Nov 2012 12:16:07 +0000 (12:16 +0000)
committerJens Axboe <axboe@kernel.dk>
Tue, 27 Nov 2012 12:34:48 +0000 (13:34 +0100)
Signed-off-by: Jens Axboe <axboe@kernel.dk>
HOWTO
engines/windowsaio.c

diff --git a/HOWTO b/HOWTO
index 6391b82..32e5d66 100644 (file)
--- 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 <device> -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.
index ea89969..db75730 100644 (file)
@@ -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;