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
-               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.
 
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'.
 
+Windows:
+Bruce Cran <bruce@cran.org.uk> has fio packages for Windows at
+http://www.bluestop.org/fio .
+
 
 Mailing list
 ------------
@@ -79,10 +83,10 @@ http://maillist.kernel.dk/fio-devel/
 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:
 
@@ -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.
 
-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
@@ -294,8 +298,8 @@ The job file parameters are:
 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).
 
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
 
+#include "compiler/compiler.h"
 #include "io_ddir.h"
+#include "flist.h"
 
 /*
  * 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 "os/os.h"
 
 static int root_warn;
 
@@ -241,7 +242,7 @@ static int bdev_size(struct thread_data *td, struct fio_file *f)
                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);
@@ -273,7 +274,7 @@ static int char_size(struct thread_data *td, struct fio_file *f)
                return 1;
        }
 
-       r = chardev_size(f->fd, &bytes);
+       r = chardev_size(f, &bytes);
        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) {
-               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) {
-               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 "
@@ -885,7 +886,9 @@ static void get_file_type(struct fio_file *f)
                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;
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;
 
-#ifndef __CYGWIN__
-       if (timer_create(CLOCK_MONOTONIC, &evt, &ival_timer) < 0)
+       if (timer_create(FIO_TIMER_CLOCK, &evt, &ival_timer) < 0)
                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>
 
+struct thread_data;
+
 #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 (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;
index 35471ad14d953702fca7a3d91de1c82a107421b7..6b677cb9053a16f7779b81d4a3fd54b9195a0c38 100644 (file)
@@ -14,6 +14,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <dlfcn.h>
+#include <fcntl.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;
 
-               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;
                }
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_CLOCK_MONOTONIC
 
 /*
  * This is broken on AIX if _LARGE_FILES is defined...
 #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;
 }
 
-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;
 
-       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;
index 4a50a3cf9c6a31ee9d39fdf965056087d6a792ee..0cb7ae5e5ca079380e20a514f1f0f1b9df3748c2 100644 (file)
@@ -7,18 +7,21 @@
 
 #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_HAVE_CLOCK_MONOTONIC
 
 #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;
 
-       if (!ioctl(fd, DIOCGMEDIASIZE, &size)) {
+       if (!ioctl(f->fd, DIOCGMEDIASIZE, &size)) {
                *bytes = size;
                return 0;
        }
@@ -27,12 +30,12 @@ static inline int blockdev_size(int fd, unsigned long long *bytes)
        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;
 }
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_CLOCK_MONOTONIC
 
 #ifdef SYNC_FILE_RANGE_WAIT_BEFORE
 #define FIO_HAVE_SYNC_FILE_RANGE
@@ -192,14 +193,14 @@ enum {
 #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;
index 1b786f832f0911f7844774343cc4b70ab30171e7..39a2f827408fd25bf30172e05921908170bef180 100644 (file)
@@ -13,6 +13,7 @@
 #endif
 
 #define FIO_HAVE_POSIXAIO
+#define FIO_HAVE_CLOCK_MONOTONIC
 #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;
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
 {
        return EINVAL;
 }
index 70d2958b47d2695a46c055cc169e2e7eeed50685..ecfcddbb31b14f1fb6843fde7e9d8b25e3dbea75 100644 (file)
 
 #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_CLOCK_MONOTONIC
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_USE_GENERIC_RAND
 
@@ -25,7 +25,7 @@
 
 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;
 }
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_CLOCK_MONOTONIC
 
 #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;
 
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
 {
        return EINVAL;
 }
index f5da6a5d583d53c737b3529a596f50e177f5f7d7..74c0f9e8e6cb63e07857206e11a81be8bdd006ad 100644 (file)
@@ -4,7 +4,11 @@
 \r
 #include <sys/types.h>\r
 #include <errno.h>\r
+#include <windows.h>\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
 #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
-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
-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
@@ -44,42 +31,50 @@ typedef struct {
 \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
-       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
-       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
-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
-       return blockdev_size(fd, bytes);\r
+       return blockdev_size(f, bytes);\r
 }\r
 \r
-static inline int blockdev_invalidate_cache(int fd)\r
 {\r
-       int rc = 0;\r
-       HANDLE hFile = (HANDLE)_get_osfhandle(fd);\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
-       return rc;\r
+       return 0;\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 <stdlib.h>
 
 #if defined(__linux__)
 #include "os-linux.h"
@@ -45,7 +46,7 @@
 #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)
@@ -91,6 +92,12 @@ typedef unsigned long os_cpu_mask_t;
 #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
@@ -124,13 +131,13 @@ static inline int os_cache_line_size(void)
 }
 
 #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;
 
-       end = lseek(fd, 0, SEEK_END);
+       end = lseek(f->fd, 0, SEEK_END);
        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
-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
@@ -9,12 +9,12 @@ BEGIN
     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 "ProductVersion", VERSION_STR\r
+      VALUE "ProductVersion", FIO_VERSION_STRING\r
     END\r
   END\r
   BLOCK "VarFileInfo"\r