FIO Windows update
authorBruce Cran <bruce@cran.org.uk>
Tue, 4 Jan 2011 09:59:30 +0000 (10:59 +0100)
committerJens Axboe <jaxboe@fusionio.com>
Tue, 4 Jan 2011 09:59:30 +0000 (10:59 +0100)
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
19 files changed:
HOWTO
README
engines/windowsaio.c [new file with mode: 0644]
file.h
filesetup.c
fio.c
fio.h
init.c
ioengines.c
os/os-aix.h
os/os-freebsd.h
os/os-linux.h
os/os-mac.h
os/os-netbsd.h
os/os-solaris.h
os/os-windows.h
os/os.h
os/windows/version.h [new file with mode: 0644]
os/windows/version.rc

diff --git a/HOWTO b/HOWTO
index 3b1eeb0606832a7808b43c309673079b3303d11f..35dccfb16855683115e62ff83109fa9b886f5407 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -272,11 +272,11 @@ filename=str      Fio normally makes up a filename based on the job name,
                ':' colon. So if you wanted a job to open /dev/sda and /dev/sdb
                as the two working files, you would use
                filename=/dev/sda:/dev/sdb. On Windows, disk devices are accessed
                ':' colon. So if you wanted a job to open /dev/sda and /dev/sdb
                as the two working files, you would use
                filename=/dev/sda:/dev/sdb. On Windows, disk devices are accessed
-               as /dev/sda for the first device (i.e. \Device\HardDisk0\Partition0,
-               /dev/sda1 for the first partition on the first disk 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". 
+               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 
                two depends on the read/write direction set.
 
                '-' is a reserved name, meaning stdin or stdout. Which of the 
                two depends on the read/write direction set.
 
diff --git a/README b/README
index f1ee9aa7676ebf08e0060d94fd34f7acd1746698..f136bb5e559b13d27a7f169816fec37781341a35 100644 (file)
--- a/README
+++ b/README
@@ -54,6 +54,10 @@ Packages for Solaris are available from OpenCSW. Install their pkgutil
 tool (http://www.opencsw.org/get-it/pkgutil/) and then install fio via
 'pkgutil -i fio'.
 
 tool (http://www.opencsw.org/get-it/pkgutil/) and then install fio via
 'pkgutil -i fio'.
 
+Windows:
+Bruce Cran <bruce@cran.org.uk> has fio packages for Windows at
+http://www.bluestop.org/fio .
+
 
 Mailing list
 ------------
 
 Mailing list
 ------------
@@ -79,10 +83,10 @@ http://maillist.kernel.dk/fio-devel/
 Building
 --------
 
 Building
 --------
 
-Just type 'make' and 'make install'. If on FreeBSD, for now you have to
-specify the FreeBSD Makefile with -f and use gmake (not make), eg:
+Just type 'make' and 'make install'. If on BSD, for now you have to
+specify the BSD Makefile with -f and use gmake (not make), eg:
 
 
-$ gmake -f Makefile.Freebsd && gmake -f Makefile.FreeBSD install
+$ gmake -f Makefile.FreeBSD && gmake -f Makefile.FreeBSD install
 
 Same goes for AIX:
 
 
 Same goes for AIX:
 
@@ -132,7 +136,7 @@ unless they match a job file parameter. You can add as many as you want,
 each job file will be regarded as a separate group and fio will stonewall
 its execution.
 
 each job file will be regarded as a separate group and fio will stonewall
 its execution.
 
-The --readonly switch is an extra safety guard to prevent accidentically
+The --readonly switch is an extra safety guard to prevent accidentally
 turning on a write setting when that is not desired. Fio will only write
 if rw=write/randwrite/rw/randrw is given, but this extra safety net can
 be used as an extra precaution. It will also enable a write check in the
 turning on a write setting when that is not desired. Fio will only write
 if rw=write/randwrite/rw/randrw is given, but this extra safety net can
 be used as an extra precaution. It will also enable a write check in the
@@ -294,8 +298,8 @@ The job file parameters are:
 Platforms
 ---------
 
 Platforms
 ---------
 
-Fio works on (at least) Linux, Solaris, AIX, OSX, NetBSD, and FreeBSD. Some
-features and/or options may only be available on some of the platforms,
+Fio works on (at least) Linux, Solaris, AIX, OSX, NetBSD, Windows and FreeBSD.
+Some features and/or options may only be available on some of the platforms,
 typically because those features only apply to that platform (like the
 solarisaio engine, or the splice engine on Linux).
 
 typically because those features only apply to that platform (like the
 solarisaio engine, or the splice engine on Linux).
 
diff --git a/engines/windowsaio.c b/engines/windowsaio.c
new file mode 100644 (file)
index 0000000..5c9d85e
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Native Windows async IO engine
+ * Copyright (C) 2010 Bruce Cran <bruce@cran.org.uk>
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <windows.h>
+
+#include "../fio.h"
+
+BOOL windowsaio_debug = FALSE;
+
+struct windowsaio_data {
+       struct io_u **aio_events;
+       unsigned int ioFinished;
+       BOOL running;
+       BOOL stopped;
+       HANDLE hThread;
+};
+
+typedef struct {
+ OVERLAPPED o;
+ struct io_u *io_u;
+} FIO_OVERLAPPED;
+
+struct thread_ctx {
+       HANDLE ioCP;
+       struct windowsaio_data *wd;
+};
+
+static void PrintError(LPCSTR lpszFunction);
+static int fio_windowsaio_cancel(struct thread_data *td,
+                              struct io_u *io_u);
+static DWORD GetEndCount(DWORD startCount, struct timespec *t);
+static BOOL TimedOut(DWORD startCount, DWORD endCount);
+static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,
+                                   unsigned int max, struct timespec *t);
+static struct io_u *fio_windowsaio_event(struct thread_data *td, int event);
+static int fio_windowsaio_queue(struct thread_data *td,
+                             struct io_u *io_u);
+static void fio_windowsaio_cleanup(struct thread_data *td);
+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 void PrintError(LPCSTR lpszFunction)
+{
+       // Retrieve the system error message for the last-error code
+
+       LPSTR lpMsgBuf;
+       DWORD dw = GetLastError();
+
+       FormatMessage(
+               FORMAT_MESSAGE_ALLOCATE_BUFFER |
+               FORMAT_MESSAGE_FROM_SYSTEM |
+               FORMAT_MESSAGE_IGNORE_INSERTS,
+               NULL,
+               dw,
+               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+               (LPTSTR)&lpMsgBuf,
+               0, NULL );
+
+       log_err("%s - %s", lpszFunction, lpMsgBuf);
+       LocalFree(lpMsgBuf);
+}
+
+static int fio_windowsaio_cancel(struct thread_data *td,
+                              struct io_u *io_u)
+{
+       BOOL bSuccess;
+       int rc = 0;
+
+       bSuccess = CancelIo(io_u->file->hFile);
+
+       if (!bSuccess)
+               rc = 1;
+
+       return rc;
+}
+
+static DWORD GetEndCount(DWORD startCount, struct timespec *t)
+{
+       DWORD endCount = startCount;
+
+       if (t == NULL)
+               return 0;
+
+       endCount += (t->tv_sec * 1000) + (t->tv_nsec / 1000000);
+       return endCount;
+}
+
+static BOOL TimedOut(DWORD startCount, DWORD endCount)
+{
+       BOOL expired = FALSE;
+       DWORD currentTime;
+
+       if (startCount == 0 || endCount == 0)
+               return FALSE;
+
+       currentTime = GetTickCount();
+
+       if ((endCount > startCount) && currentTime >= endCount)
+               expired = TRUE;
+       else if (currentTime < startCount && currentTime > endCount)
+               expired = TRUE;
+
+       if (windowsaio_debug)
+               printf("windowsaio: timedout = %d\n", expired);
+
+       return expired;
+}
+
+static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,
+                                   unsigned int max, struct timespec *t)
+{
+       struct windowsaio_data *wd = td->io_ops->data;
+       struct flist_head *entry;
+       unsigned int dequeued = 0;
+       struct io_u *io_u;
+       DWORD startCount = 0, endCount = 0;
+       BOOL timedout = FALSE;
+       unsigned int r = 0;
+
+       if (windowsaio_debug)
+               printf("getevents (min %d, max %d)\n", min, max);
+
+       if (t != NULL) {
+               startCount = GetTickCount();
+               endCount = GetEndCount(startCount, t);
+       }
+
+       while (dequeued < min && !timedout) {
+
+               flist_for_each(entry, &td->io_u_busylist) {
+                       io_u = flist_entry(entry, struct io_u, list);
+
+                       if (io_u->seen == 0)
+                               continue;
+
+                       dequeued++;
+
+                       wd->ioFinished--;
+                       wd->aio_events[r] = io_u;
+                       r++;
+
+                       if (windowsaio_debug)
+                               printf("dequeued %d\n", dequeued);
+
+                       if (dequeued == max)
+                               break;
+               }
+
+               if (TimedOut(startCount, endCount))
+                       timedout = TRUE;
+
+               if (dequeued < min && !timedout)
+                       Sleep(250);
+       }
+
+       if (windowsaio_debug)
+               printf("leave getevents (%d)\n", dequeued);
+
+       return dequeued;
+}
+
+static struct io_u *fio_windowsaio_event(struct thread_data *td, int event)
+{
+       struct windowsaio_data *wd = td->io_ops->data;
+       return wd->aio_events[event];
+}
+
+static int fio_windowsaio_queue(struct thread_data *td,
+                             struct io_u *io_u)
+{
+       FIO_OVERLAPPED *fov;
+       DWORD ioBytes;
+       BOOL bSuccess = TRUE;
+       int rc;
+
+       fio_ro_check(td, io_u);
+
+       if (windowsaio_debug)
+               printf("enqueue enter\n");
+
+       fov = malloc(sizeof(FIO_OVERLAPPED));
+       ZeroMemory(fov, sizeof(FIO_OVERLAPPED));
+
+       io_u->seen = 0;
+
+       fov->o.Offset = io_u->offset & 0xFFFFFFFF;
+       fov->o.OffsetHigh = io_u->offset >> 32;
+       fov->o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+       fov->io_u = io_u;
+
+       if (fov->o.hEvent == NULL) {
+               PrintError(__func__);
+               return 1;
+       }
+
+       if (io_u->ddir == DDIR_WRITE)
+               bSuccess = WriteFile(io_u->file->hFile, io_u->xfer_buf, io_u->xfer_buflen, &ioBytes, &fov->o);
+       else if (io_u->ddir == DDIR_READ)
+               bSuccess = ReadFile(io_u->file->hFile, io_u->xfer_buf, io_u->xfer_buflen, &ioBytes, &fov->o);
+       else if (io_u->ddir == DDIR_SYNC     ||
+                        io_u->ddir == DDIR_DATASYNC ||
+                        io_u->ddir == DDIR_SYNC_FILE_RANGE)
+       {
+               FlushFileBuffers(io_u->file->hFile);
+               return FIO_Q_COMPLETED;
+       } else if (io_u->ddir == DDIR_TRIM) {
+               log_info("explicit TRIM isn't supported on Windows");
+               return FIO_Q_COMPLETED;
+       }
+
+       if (bSuccess) {
+               io_u->seen = 1;
+               io_u->resid = io_u->xfer_buflen - fov->o.InternalHigh;
+               io_u->error = 0;
+               rc = FIO_Q_COMPLETED;
+       } else if (!bSuccess && GetLastError() == ERROR_IO_PENDING) {
+               rc = FIO_Q_QUEUED;
+       } else {
+               PrintError(__func__);
+               io_u->error = GetLastError();
+               io_u->resid = io_u->xfer_buflen;
+               rc = FIO_Q_COMPLETED;
+       }
+
+       if (windowsaio_debug)
+               printf("enqueue - leave (offset %llu)\n", io_u->offset);
+
+       return rc;
+}
+
+static void fio_windowsaio_cleanup(struct thread_data *td)
+{
+       struct windowsaio_data *wd;
+
+       if (windowsaio_debug)
+               printf("windowsaio: cleanup - enter\n");
+
+       wd = td->io_ops->data;
+       wd->running = FALSE;
+
+       while (wd->stopped == FALSE)
+               Sleep(5);
+
+       if (wd != NULL) {
+               CloseHandle(wd->hThread);
+               free(wd->aio_events);
+               wd->aio_events = NULL;
+               free(wd);
+               td->io_ops->data = NULL;
+       }
+
+       if (windowsaio_debug)
+               printf("windowsaio: cleanup - leave\n");
+}
+
+static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter)
+{
+       OVERLAPPED *ovl;
+       FIO_OVERLAPPED *fov;
+       struct io_u *io_u;
+       struct windowsaio_data *wd;
+
+       struct thread_ctx *ctx;
+       ULONG_PTR ulKey = 0;
+       BOOL bSuccess;
+       DWORD bytes;
+
+
+       ctx = (struct thread_ctx*)lpParameter;
+       wd = ctx->wd;
+       bSuccess = TRUE;
+
+       if (windowsaio_debug)
+               printf("windowsaio: IoCompletionRoutine - enter\n");
+
+       while (ctx->wd->running) {
+               bSuccess = GetQueuedCompletionStatus(ctx->ioCP, &bytes, &ulKey, &ovl, 500);
+
+               if (windowsaio_debug)
+                       printf("GetQueuedCompletionStatus returned %d\n", bSuccess);
+
+               if (!bSuccess) {
+                       if (GetLastError() == WAIT_TIMEOUT) {
+                               continue;
+                       } else {
+                               PrintError(__func__);
+                               continue;
+                       }
+               }
+
+               fov = CONTAINING_RECORD(ovl, FIO_OVERLAPPED, o);
+               io_u = fov->io_u;
+
+               if (windowsaio_debug) {
+                       if (io_u->seen == 1)
+                               printf("IoCompletionRoutine - got already completed IO\n");
+                       else
+                               printf("IoCompletionRoutine - completed %d IO\n", ctx->wd->ioFinished);
+               }
+
+               if (io_u->seen == 1)
+                       continue;
+
+               ctx->wd->ioFinished++;
+
+               if (ovl->Internal == ERROR_SUCCESS) {
+                       io_u->resid = io_u->xfer_buflen - ovl->InternalHigh;
+                       io_u->error = 0;
+               } else {
+                       io_u->resid = io_u->xfer_buflen;
+                       io_u->error = 1;
+               }
+
+               io_u->seen = 1;
+               CloseHandle(ovl->hEvent);
+               free(ovl);
+       }
+
+       bSuccess = CloseHandle(ctx->ioCP);
+       if (!bSuccess)
+               PrintError(__func__);
+
+       if (windowsaio_debug)
+               printf("windowsaio: IoCompletionRoutine - leave\n");
+
+       ctx->wd->stopped = TRUE;
+       free(ctx);
+       return 0;
+}
+
+static int fio_windowsaio_init(struct thread_data *td)
+{
+       int rc = 0;
+       struct windowsaio_data *wd;
+
+       if (windowsaio_debug)
+               printf("windowsaio: init\n");
+
+       wd = malloc(sizeof(struct windowsaio_data));
+
+       ZeroMemory(wd, sizeof(*wd));
+       wd->aio_events = malloc((td->o.iodepth + 1) * sizeof(struct io_u *));
+       ZeroMemory(wd->aio_events, (td->o.iodepth + 1) * sizeof(struct io_u *));
+
+       td->io_ops->data = wd;
+       return rc;
+}
+
+static int fio_windowsaio_open_file(struct thread_data *td, struct fio_file *f)
+{
+       int rc = 0;
+       HANDLE hFile;
+       DWORD flags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_OVERLAPPED;
+       DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+       DWORD openmode = OPEN_ALWAYS;
+       DWORD access;
+
+       dprint(FD_FILE, "fd open %s\n", f->file_name);
+
+       if (windowsaio_debug)
+               printf("windowsaio: open file %s - enter\n", f->file_name);
+
+       if (f->filetype == FIO_TYPE_PIPE) {
+               log_err("fio: windowsaio doesn't support pipes\n");
+               return 1;
+       }
+
+       if (!strcmp(f->file_name, "-")) {
+               log_err("fio: can't read/write to stdin/out\n");
+               return 1;
+       }
+
+       if (td->o.odirect)
+               flags |= FILE_FLAG_NO_BUFFERING;
+       if (td->o.sync_io)
+               flags |= FILE_FLAG_WRITE_THROUGH;
+
+
+       if (td->o.td_ddir == TD_DDIR_READ  ||
+               td->o.td_ddir == TD_DDIR_WRITE ||
+               td->o.td_ddir == TD_DDIR_RANDRW)
+       {
+               flags |= FILE_FLAG_SEQUENTIAL_SCAN;
+       }
+       else
+       {
+               flags |= FILE_FLAG_RANDOM_ACCESS;
+       }
+
+       if (td_read(td) || read_only)
+               access = GENERIC_READ;
+       else
+               access = (GENERIC_READ | GENERIC_WRITE);
+
+       if (td->o.create_on_open > 0)
+               openmode = OPEN_ALWAYS;
+       else
+               openmode = OPEN_EXISTING;
+
+       f->hFile = CreateFile(f->file_name, access, sharemode,
+               NULL, openmode, flags, NULL);
+
+       if (f->hFile == INVALID_HANDLE_VALUE) {
+               log_err("Failed to open %s\n", f->file_name);
+               PrintError(__func__);
+               rc = 1;
+       }
+
+       /* Only set up the competion port and thread if we're not just
+        * querying the device size */
+       if (!rc && td->io_ops->data != NULL) {
+               struct windowsaio_data *wd;
+               struct thread_ctx *ctx;
+               hFile = CreateIoCompletionPort(f->hFile, NULL, 0, 0);
+
+               wd = td->io_ops->data;
+               wd->running = TRUE;
+               wd->stopped = FALSE;
+
+               ctx = malloc(sizeof(struct thread_ctx));
+               ctx->ioCP = hFile;
+               ctx->wd = wd;
+
+               wd->hThread = CreateThread(NULL, 0, IoCompletionRoutine, ctx, 0, NULL);
+
+               if (wd->hThread == NULL) {
+                       PrintError(__func__);
+                       rc = 1;
+               }
+       }
+
+       if (windowsaio_debug)
+               printf("windowsaio: open file - leave (%d)\n", rc);
+
+       return rc;
+}
+
+static int fio_windowsaio_close_file(struct thread_data fio_unused *td, struct fio_file *f)
+{
+       BOOL bSuccess;
+
+       if (windowsaio_debug)
+               printf("windowsaio: close file\n");
+
+       if (f->hFile != INVALID_HANDLE_VALUE) {
+               bSuccess = CloseHandle(f->hFile);
+               if (!bSuccess)
+                       PrintError(__func__);
+       }
+
+       f->hFile = INVALID_HANDLE_VALUE;
+       return 0;
+}
+
+static struct ioengine_ops ioengine = {
+       .name           = "windowsaio",
+       .version        = FIO_IOOPS_VERSION,
+       .init           = fio_windowsaio_init,
+       .queue          = fio_windowsaio_queue,
+       .cancel         = fio_windowsaio_cancel,
+       .getevents      = fio_windowsaio_getevents,
+       .event          = fio_windowsaio_event,
+       .cleanup        = fio_windowsaio_cleanup,
+       .open_file      = fio_windowsaio_open_file,
+       .close_file     = fio_windowsaio_close_file,
+       .get_file_size  = generic_get_file_size
+};
+
+static void fio_init fio_posixaio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_posixaio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
diff --git a/file.h b/file.h
index 994d5fd0c828bd8de6c6c39bce44e42d45e11d8f..10c5379c2f3ec6fee8141cc770dadea3b8467532 100644 (file)
--- a/file.h
+++ b/file.h
@@ -1,7 +1,9 @@
 #ifndef FIO_FILE_H
 #define FIO_FILE_H
 
 #ifndef FIO_FILE_H
 #define FIO_FILE_H
 
+#include "compiler/compiler.h"
 #include "io_ddir.h"
 #include "io_ddir.h"
+#include "flist.h"
 
 /*
  * The type of object we are working on
 
 /*
  * The type of object we are working on
index 5b96c66fa739d0af845fab987452d957542175cc..9d42deb02d47dbab2866fcb9d2512409e60aa1b5 100644 (file)
@@ -11,6 +11,7 @@
 #include "fio.h"
 #include "smalloc.h"
 #include "filehash.h"
 #include "fio.h"
 #include "smalloc.h"
 #include "filehash.h"
+#include "os/os.h"
 
 static int root_warn;
 
 
 static int root_warn;
 
@@ -241,7 +242,7 @@ static int bdev_size(struct thread_data *td, struct fio_file *f)
                return 1;
        }
 
                return 1;
        }
 
-       r = blockdev_size(f->fd, &bytes);
+       r = blockdev_size(f, &bytes);
        if (r) {
                td_verror(td, r, "blockdev_size");
                printf("fd is %d\n", f->fd);
        if (r) {
                td_verror(td, r, "blockdev_size");
                printf("fd is %d\n", f->fd);
@@ -273,7 +274,7 @@ static int char_size(struct thread_data *td, struct fio_file *f)
                return 1;
        }
 
                return 1;
        }
 
-       r = chardev_size(f->fd, &bytes);
+       r = chardev_size(f, &bytes);
        if (r) {
                td_verror(td, r, "chardev_size");
                goto err;
        if (r) {
                td_verror(td, r, "chardev_size");
                goto err;
@@ -351,9 +352,9 @@ static int __file_invalidate_cache(struct thread_data *td, struct fio_file *f,
                (void) posix_madvise(f->mmap_ptr, f->mmap_sz, FIO_MADV_FREE);
 #endif
        } else if (f->filetype == FIO_TYPE_FILE) {
                (void) posix_madvise(f->mmap_ptr, f->mmap_sz, FIO_MADV_FREE);
 #endif
        } else if (f->filetype == FIO_TYPE_FILE) {
-               ret = fadvise(f->fd, off, len, POSIX_FADV_DONTNEED);
+               ret = posix_fadvise(f->fd, off, len, POSIX_FADV_DONTNEED);
        } else if (f->filetype == FIO_TYPE_BD) {
        } else if (f->filetype == FIO_TYPE_BD) {
-               ret = blockdev_invalidate_cache(f->fd);
+               ret = blockdev_invalidate_cache(f);
                if (ret < 0 && errno == EACCES && geteuid()) {
                        if (!root_warn) {
                                log_err("fio: only root may flush block "
                if (ret < 0 && errno == EACCES && geteuid()) {
                        if (!root_warn) {
                                log_err("fio: only root may flush block "
@@ -885,7 +886,9 @@ static void get_file_type(struct fio_file *f)
                f->filetype = FIO_TYPE_FILE;
 
        if (!stat(f->file_name, &sb)) {
                f->filetype = FIO_TYPE_FILE;
 
        if (!stat(f->file_name, &sb)) {
-               if (S_ISBLK(sb.st_mode))
+               /* \\.\ is the device namespace in Windows, where every file is
+                * a block device */
+               if (S_ISBLK(sb.st_mode) || strncmp(f->file_name, "\\\\.\\", 4) == 0)
                        f->filetype = FIO_TYPE_BD;
                else if (S_ISCHR(sb.st_mode))
                        f->filetype = FIO_TYPE_CHAR;
                        f->filetype = FIO_TYPE_BD;
                else if (S_ISCHR(sb.st_mode))
                        f->filetype = FIO_TYPE_CHAR;
diff --git a/fio.c b/fio.c
index 2420d1039cd18cf1b99f4c10c6568f61ce42a678..93482f5294ed55c245e25a0e98f8151fe7354ced 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -161,13 +161,8 @@ static void posix_timer_setup(void)
        evt.sigev_notify = SIGEV_THREAD;
        evt.sigev_notify_function = ival_fn;
 
        evt.sigev_notify = SIGEV_THREAD;
        evt.sigev_notify_function = ival_fn;
 
-#ifndef __CYGWIN__
-       if (timer_create(CLOCK_MONOTONIC, &evt, &ival_timer) < 0)
+       if (timer_create(FIO_TIMER_CLOCK, &evt, &ival_timer) < 0)
                perror("timer_create");
                perror("timer_create");
-#else /* Windows (and thus Cygwin) doesn't have a monotonic clock */
-       if (timer_create(CLOCK_REALTIME, &evt, &ival_timer) < 0)
-               perror("timer_create");
-#endif
 
 }
 
 
 }
 
diff --git a/fio.h b/fio.h
index c04ad8b2e37ce8dada1e97f7652174b2009f819c..95988584c037bfec4d1da5a2170cc8c295611205 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -14,6 +14,8 @@
 #include <inttypes.h>
 #include <assert.h>
 
 #include <inttypes.h>
 #include <assert.h>
 
+struct thread_data;
+
 #include "compiler/compiler.h"
 #include "flist.h"
 #include "fifo.h"
 #include "compiler/compiler.h"
 #include "flist.h"
 #include "fifo.h"
diff --git a/init.c b/init.c
index bdbb3774e8598874f2c555724a4f2d7c68f84290..0a3529d08425fa53bb3319a52ad319079a6e3cbd 100644 (file)
--- a/init.c
+++ b/init.c
@@ -431,7 +431,9 @@ static int exists_and_not_file(const char *filename)
        if (lstat(filename, &sb) == -1)
                return 0;
 
        if (lstat(filename, &sb) == -1)
                return 0;
 
-       if (S_ISREG(sb.st_mode))
+       /* \\.\ is the device namespace in Windows, where every file
+        * is a device node */
+       if (S_ISREG(sb.st_mode) && strncmp(filename, "\\\\.\\", 4) != 0)
                return 0;
 
        return 1;
                return 0;
 
        return 1;
index 35471ad14d953702fca7a3d91de1c82a107421b7..6b677cb9053a16f7779b81d4a3fd54b9195a0c38 100644 (file)
@@ -14,6 +14,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <dlfcn.h>
 #include <unistd.h>
 #include <string.h>
 #include <dlfcn.h>
+#include <fcntl.h>
 #include <assert.h>
 
 #include "fio.h"
 #include <assert.h>
 
 #include "fio.h"
@@ -386,7 +387,7 @@ int td_io_open_file(struct thread_data *td, struct fio_file *f)
                else
                        flags = POSIX_FADV_SEQUENTIAL;
 
                else
                        flags = POSIX_FADV_SEQUENTIAL;
 
-               if (fadvise(f->fd, f->file_offset, f->io_size, flags) < 0) {
+               if (posix_fadvise(f->fd, f->file_offset, f->io_size, flags) < 0) {
                        td_verror(td, errno, "fadvise");
                        goto err;
                }
                        td_verror(td, errno, "fadvise");
                        goto err;
                }
index 09a0530fae1464ac4701c5873b82775960f700c6..b5ee5bb35e6a38f73c25bc05df8d3b0a0ed0ace1 100644 (file)
@@ -9,6 +9,7 @@
 #define FIO_HAVE_POSIXAIO
 #define FIO_HAVE_ODIRECT
 #define FIO_USE_GENERIC_RAND
 #define FIO_HAVE_POSIXAIO
 #define FIO_HAVE_ODIRECT
 #define FIO_USE_GENERIC_RAND
+#define FIO_HAVE_CLOCK_MONOTONIC
 
 /*
  * This is broken on AIX if _LARGE_FILES is defined...
 
 /*
  * This is broken on AIX if _LARGE_FILES is defined...
 #define OS_MAP_ANON            MAP_ANON
 #define OS_MSG_DONTWAIT                0
 
 #define OS_MAP_ANON            MAP_ANON
 #define OS_MSG_DONTWAIT                0
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
 {
        return EINVAL;
 }
 
 {
        return EINVAL;
 }
 
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
 {
        struct devinfo info;
 
 {
        struct devinfo info;
 
-       if (!ioctl(fd, IOCINFO, &info)) {
+       if (!ioctl(f->fd, IOCINFO, &info)) {
                *bytes = (unsigned long long)info.un.scdk.numblks *
                                info.un.scdk.blksize;
                return 0;
                *bytes = (unsigned long long)info.un.scdk.numblks *
                                info.un.scdk.blksize;
                return 0;
index 4a50a3cf9c6a31ee9d39fdf965056087d6a792ee..0cb7ae5e5ca079380e20a514f1f0f1b9df3748c2 100644 (file)
@@ -7,18 +7,21 @@
 
 #define FIO_HAVE_POSIXAIO
 #define FIO_HAVE_ODIRECT
 
 #define FIO_HAVE_POSIXAIO
 #define FIO_HAVE_ODIRECT
+#define FIO_HAVE_IOPRIO
+#define FIO_HAVE_STRSEP
 #define FIO_USE_GENERIC_RAND
 #define FIO_HAVE_CHARDEV_SIZE
 #define FIO_USE_GENERIC_RAND
 #define FIO_HAVE_CHARDEV_SIZE
+#define FIO_HAVE_CLOCK_MONOTONIC
 
 #define OS_MAP_ANON            MAP_ANON
 
 typedef off_t off64_t;
 
 
 #define OS_MAP_ANON            MAP_ANON
 
 typedef off_t off64_t;
 
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
 {
        off_t size;
 
 {
        off_t size;
 
-       if (!ioctl(fd, DIOCGMEDIASIZE, &size)) {
+       if (!ioctl(f->fd, DIOCGMEDIASIZE, &size)) {
                *bytes = size;
                return 0;
        }
                *bytes = size;
                return 0;
        }
@@ -27,12 +30,12 @@ static inline int blockdev_size(int fd, unsigned long long *bytes)
        return errno;
 }
 
        return errno;
 }
 
-static inline int chardev_size(int fd, unsigned long long *bytes)
+static inline int chardev_size(struct fio_file *f, unsigned long long *bytes)
 {
 {
-       return blockdev_size(fd, bytes);
+       return blockdev_size(f->fd, bytes);
 }
 
 }
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file *f)
 {
        return EINVAL;
 }
 {
        return EINVAL;
 }
index 20f2a94ef4d06783aa006e202a37644ce64f7a1e..aab74e581e5fc4cb76fa1eb00739ae1c145c9bb4 100644 (file)
@@ -39,6 +39,7 @@
 #define FIO_HAVE_FS_STAT
 #define FIO_HAVE_TRIM
 #define FIO_HAVE_BINJECT
 #define FIO_HAVE_FS_STAT
 #define FIO_HAVE_TRIM
 #define FIO_HAVE_BINJECT
+#define FIO_HAVE_CLOCK_MONOTONIC
 
 #ifdef SYNC_FILE_RANGE_WAIT_BEFORE
 #define FIO_HAVE_SYNC_FILE_RANGE
 
 #ifdef SYNC_FILE_RANGE_WAIT_BEFORE
 #define FIO_HAVE_SYNC_FILE_RANGE
@@ -192,14 +193,14 @@ enum {
 #define BLKDISCARD     _IO(0x12,119)
 #endif
 
 #define BLKDISCARD     _IO(0x12,119)
 #endif
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file *fd)
 {
 {
-       return ioctl(fd, BLKFLSBUF);
+       return ioctl(f->fd, BLKFLSBUF);
 }
 
 }
 
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
 {
 {
-       if (!ioctl(fd, BLKGETSIZE64, bytes))
+       if (!ioctl(f->fd, BLKGETSIZE64, bytes))
                return 0;
 
        return errno;
                return 0;
 
        return errno;
index 1b786f832f0911f7844774343cc4b70ab30171e7..39a2f827408fd25bf30172e05921908170bef180 100644 (file)
@@ -13,6 +13,7 @@
 #endif
 
 #define FIO_HAVE_POSIXAIO
 #endif
 
 #define FIO_HAVE_POSIXAIO
+#define FIO_HAVE_CLOCK_MONOTONIC
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_USE_GENERIC_RAND
 
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_USE_GENERIC_RAND
 
@@ -21,7 +22,7 @@
 typedef unsigned int clockid_t;
 typedef off_t off64_t;
 
 typedef unsigned int clockid_t;
 typedef off_t off64_t;
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
 {
        return EINVAL;
 }
 {
        return EINVAL;
 }
index 70d2958b47d2695a46c055cc169e2e7eeed50685..ecfcddbb31b14f1fb6843fde7e9d8b25e3dbea75 100644 (file)
 
 #define FIO_HAVE_POSIXAIO
 #define FIO_HAVE_FADVISE
 
 #define FIO_HAVE_POSIXAIO
 #define FIO_HAVE_FADVISE
-#define        fadvise posix_fadvise   /* XXX NetBSD doesn't have fadvise */
 #define FIO_HAVE_ODIRECT
 #define FIO_HAVE_STRSEP
 #define FIO_HAVE_FDATASYNC
 #define FIO_HAVE_ODIRECT
 #define FIO_HAVE_STRSEP
 #define FIO_HAVE_FDATASYNC
+#define FIO_HAVE_CLOCK_MONOTONIC
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_USE_GENERIC_RAND
 
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_USE_GENERIC_RAND
 
@@ -25,7 +25,7 @@
 
 typedef off_t off64_t;
 
 
 typedef off_t off64_t;
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
 {
        return EINVAL;
 }
 {
        return EINVAL;
 }
index f8ce1f31cf3d4b610f898b9da3eedc873190257d..14164b01b47cfccfdfe45fd4c340d8a1e2313a19 100644 (file)
@@ -15,6 +15,7 @@
 #define FIO_HAVE_PSHARED_MUTEX
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_HAVE_FDATASYNC
 #define FIO_HAVE_PSHARED_MUTEX
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_HAVE_FDATASYNC
+#define FIO_HAVE_CLOCK_MONOTONIC
 
 #define OS_MAP_ANON            MAP_ANON
 #define OS_RAND_MAX            2147483648UL
 
 #define OS_MAP_ANON            MAP_ANON
 #define OS_RAND_MAX            2147483648UL
@@ -26,7 +27,7 @@ struct solaris_rand_seed {
 typedef psetid_t os_cpu_mask_t;
 typedef struct solaris_rand_seed os_random_state_t;
 
 typedef psetid_t os_cpu_mask_t;
 typedef struct solaris_rand_seed os_random_state_t;
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
 {
        return EINVAL;
 }
 {
        return EINVAL;
 }
index f5da6a5d583d53c737b3529a596f50e177f5f7d7..74c0f9e8e6cb63e07857206e11a81be8bdd006ad 100644 (file)
@@ -4,7 +4,11 @@
 \r
 #include <sys/types.h>\r
 #include <errno.h>\r
 \r
 #include <sys/types.h>\r
 #include <errno.h>\r
+#include <windows.h>\r
 \r
 \r
+#include "../smalloc.h"\r
+#include "../file.h"\r
+#include "../log.h"\r
 \r
 #define FIO_HAVE_ODIRECT\r
 #define FIO_USE_GENERIC_RAND\r
 \r
 #define FIO_HAVE_ODIRECT\r
 #define FIO_USE_GENERIC_RAND\r
 #define FIO_HAVE_FDATASYNC\r
 #define FIO_HAVE_WINDOWSAIO\r
 \r
 #define FIO_HAVE_FDATASYNC\r
 #define FIO_HAVE_WINDOWSAIO\r
 \r
-/* TODO add support for FIO_HAVE_CPU_AFFINITY */\r
-\r
 #define OS_MAP_ANON            MAP_ANON\r
 \r
 #define OS_MAP_ANON            MAP_ANON\r
 \r
-typedef off_t off64_t;\r
-\r
-\r
-#define FIO_NOTUNIX\r
-\r
-#include <windows.h>\r
-#include <io.h>\r
+#define OS_CLOCK CLOCK_REALTIME\r
 \r
 \r
-typedef void* HANDLE;\r
-\r
-BOOL WINAPI GetFileSizeEx(\r
-   HANDLE hFile,\r
-   PLARGE_INTEGER lpFileSize\r
-);\r
-\r
-long _get_osfhandle(\r
-   int fd\r
-);\r
+typedef off_t off64_t;\r
 \r
 typedef struct {\r
   LARGE_INTEGER Length;\r
 \r
 typedef struct {\r
   LARGE_INTEGER Length;\r
@@ -44,42 +31,50 @@ typedef struct {
 \r
 #define IOCTL_DISK_GET_LENGTH_INFO 0x7405C\r
 \r
 \r
 #define IOCTL_DISK_GET_LENGTH_INFO 0x7405C\r
 \r
-\r
-static inline int blockdev_size(int fd, unsigned long long *bytes)\r
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)\r
 {\r
        int rc = 0;\r
 {\r
        int rc = 0;\r
-       HANDLE hFile = (HANDLE)_get_osfhandle(fd);\r
-       if (hFile != INVALID_HANDLE_VALUE)\r
-       {\r
-               GET_LENGTH_INFORMATION info;\r
-               DWORD outBytes;\r
-               LARGE_INTEGER size;\r
-               size.QuadPart = 0;\r
-               if (DeviceIoControl(hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &info, sizeof(info), &outBytes, NULL))\r
-                       *bytes = info.Length.QuadPart;\r
-               else\r
-                       rc = EIO;\r
+       HANDLE hFile;\r
+\r
+       if (f->hFile == NULL) {\r
+               hFile = CreateFile(f->file_name, (GENERIC_READ | GENERIC_WRITE),\r
+                       (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);\r
+       } else {\r
+               hFile = f->hFile;\r
        }\r
 \r
        }\r
 \r
-       return 0;\r
+       GET_LENGTH_INFORMATION info;\r
+       DWORD outBytes;\r
+       LARGE_INTEGER size;\r
+       size.QuadPart = 0;\r
+       if (DeviceIoControl(hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &info, sizeof(info), &outBytes, NULL))\r
+               *bytes = info.Length.QuadPart;\r
+       else\r
+               rc = EIO;\r
+       }\r
+\r
+       /* If we were passed a POSIX fd,\r
+        * close the HANDLE we created via CreateFile */\r
+       if (hFile != INVALID_HANDLE_VALUE && f->hFile == NULL)\r
+               CloseHandle(hFile);\r
+\r
+       return rc;\r
 }\r
 \r
 }\r
 \r
-static inline int chardev_size(int fd, unsigned long long *bytes)\r
+static inline int chardev_size(struct fio_file *f, unsigned long long *bytes)\r
 {\r
 {\r
-       return blockdev_size(fd, bytes);\r
+       return blockdev_size(f, bytes);\r
 }\r
 \r
 }\r
 \r
-static inline int blockdev_invalidate_cache(int fd)\r
 {\r
 {\r
-       int rc = 0;\r
-       HANDLE hFile = (HANDLE)_get_osfhandle(fd);\r
 \r
 \r
-       if (hFile != INVALID_HANDLE_VALUE)\r
-               FlushFileBuffers(hFile);\r
-       else\r
-               rc = EIO;\r
+static inline int blockdev_invalidate_cache(struct fio_file *f)\r
+{\r
+       BOOL bSuccess = FlushFileBuffers(f->hFile);\r
+       if (!bSuccess)\r
+               log_info("blockdev_invalidate_cache - FlushFileBuffers failed\n");\r
 \r
 \r
-       return rc;\r
+       return 0;\r
 }\r
 \r
 static inline unsigned long long os_phys_mem(void)\r
 }\r
 \r
 static inline unsigned long long os_phys_mem(void)\r
diff --git a/os/os.h b/os/os.h
index 95f0ff29e02fad0b8f7ed07b1f1e451c8bbeb1ae..92b6950d305d077261633723b181f35e273b33ae 100644 (file)
--- a/os/os.h
+++ b/os/os.h
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <pthread.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <stdlib.h>
 
 #if defined(__linux__)
 #include "os-linux.h"
 
 #if defined(__linux__)
 #include "os-linux.h"
@@ -45,7 +46,7 @@
 #endif
 
 #ifndef FIO_HAVE_FADVISE
 #endif
 
 #ifndef FIO_HAVE_FADVISE
-#define fadvise(fd, off, len, advice)  (0)
+#define posix_fadvise(fd, off, len, advice)    (0)
 
 #ifndef POSIX_FADV_DONTNEED
 #define POSIX_FADV_DONTNEED    (0)
 
 #ifndef POSIX_FADV_DONTNEED
 #define POSIX_FADV_DONTNEED    (0)
@@ -91,6 +92,12 @@ typedef unsigned long os_cpu_mask_t;
 #define OS_RAND_MAX                    RAND_MAX
 #endif
 
 #define OS_RAND_MAX                    RAND_MAX
 #endif
 
+#ifdef FIO_HAVE_CLOCK_MONOTONIC
+#define FIO_TIMER_CLOCK CLOCK_MONOTONIC
+#else
+#define FIO_TIMER_CLOCK CLOCK_REALTIME
+#endif
+
 #ifndef FIO_HAVE_RAWBIND
 #define fio_lookup_raw(dev, majdev, mindev)    1
 #endif
 #ifndef FIO_HAVE_RAWBIND
 #define fio_lookup_raw(dev, majdev, mindev)    1
 #endif
@@ -124,13 +131,13 @@ static inline int os_cache_line_size(void)
 }
 
 #ifdef FIO_USE_GENERIC_BDEV_SIZE
 }
 
 #ifdef FIO_USE_GENERIC_BDEV_SIZE
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
 {
        off_t end;
 
        *bytes = 0;
 
 {
        off_t end;
 
        *bytes = 0;
 
-       end = lseek(fd, 0, SEEK_END);
+       end = lseek(f->fd, 0, SEEK_END);
        if (end < 0)
                return errno;
 
        if (end < 0)
                return errno;
 
diff --git a/os/windows/version.h b/os/windows/version.h
new file mode 100644 (file)
index 0000000..3642342
--- /dev/null
@@ -0,0 +1,4 @@
+#define FIO_VERSION_MAJOR 1\r
+#define FIO_VERSION_MINOR 44\r
+#define FIO_VERSION_BUILD 3\r
+#define FIO_VERSION_STRING "1.44.3"\r
index f13ba062c3a6af6cdb69b95e6287c5f48c3111ea..d699f097335b2b469d8ad52bef132729a92f4974 100755 (executable)
@@ -1,7 +1,7 @@
-#include "../../version.h"\r
+#include "version.h"\r
 1 VERSIONINFO\r
 1 VERSIONINFO\r
-FILEVERSION     VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,0\r
-PRODUCTVERSION  VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,0\r
+FILEVERSION     FIO_VERSION_MAJOR,FIO_VERSION_MINOR,FIO_VERSION_BUILD,0\r
+PRODUCTVERSION  FIO_VERSION_MAJOR,FIO_VERSION_MINOR,FIO_VERSION_BUILD,0\r
 BEGIN\r
   BLOCK "StringFileInfo"\r
   BEGIN\r
 BEGIN\r
   BLOCK "StringFileInfo"\r
   BEGIN\r
@@ -9,12 +9,12 @@ BEGIN
     BEGIN\r
       VALUE "CompanyName", ""\r
       VALUE "FileDescription", "Flexible IO Tester"\r
     BEGIN\r
       VALUE "CompanyName", ""\r
       VALUE "FileDescription", "Flexible IO Tester"\r
-      VALUE "FileVersion", "1.44.3"\r
+      VALUE "FileVersion", FIO_VERSION_STRING\r
       VALUE "InternalName", "fio"\r
       VALUE "LegalCopyright", "Copyright (C) 2010"\r
       VALUE "OriginalFilename", "fio.exe"\r
       VALUE "ProductName", "FIO"\r
       VALUE "InternalName", "fio"\r
       VALUE "LegalCopyright", "Copyright (C) 2010"\r
       VALUE "OriginalFilename", "fio.exe"\r
       VALUE "ProductName", "FIO"\r
-      VALUE "ProductVersion", VERSION_STR\r
+      VALUE "ProductVersion", FIO_VERSION_STRING\r
     END\r
   END\r
   BLOCK "VarFileInfo"\r
     END\r
   END\r
   BLOCK "VarFileInfo"\r