Index: /trunk/src/VBox/Storage/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Storage/testcase/Makefile.kmk	(revision 35595)
+++ /trunk/src/VBox/Storage/testcase/Makefile.kmk	(revision 35596)
@@ -88,5 +88,6 @@
  tstVDIo_SOURCES  = tstVDIo.cpp \
 	VDIoBackendMem.cpp \
-	VDMemDisk.cpp
+	VDMemDisk.cpp \
+	VDIoRnd.cpp
 endif
 
Index: /trunk/src/VBox/Storage/testcase/VDIoBackendMem.cpp
===================================================================
--- /trunk/src/VBox/Storage/testcase/VDIoBackendMem.cpp	(revision 35595)
+++ /trunk/src/VBox/Storage/testcase/VDIoBackendMem.cpp	(revision 35596)
@@ -44,6 +44,4 @@
     /** Size of the transfer. */
     size_t          cbTransfer;
-    /** Segments array. */
-    PCRTSGSEG       paSegs;
     /** Number of segments in the array. */
     unsigned        cSegs;
@@ -52,4 +50,6 @@
     /** Opaque user data. */
     void           *pvUser;
+    /** Segment array - variable in size */
+    RTSGSEG         aSegs[1];
 } VDIOBACKENDREQ, *PVDIOBACKENDREQ;
 
@@ -145,5 +145,5 @@
     size_t cbData;
 
-    RTCircBufAcquireWriteBlock(pIoBackend->pRequestRing, sizeof(VDIOBACKENDREQ), (void **)&pReq, &cbData);
+    RTCircBufAcquireWriteBlock(pIoBackend->pRequestRing, RT_OFFSETOF(VDIOBACKENDREQ, aSegs[cSegs]), (void **)&pReq, &cbData);
     if (!pReq)
         return VERR_NO_MEMORY;
@@ -154,8 +154,12 @@
     pReq->off         = off;
     pReq->pMemDisk    = pMemDisk;
-    pReq->paSegs      = paSegs;
     pReq->cSegs       = cSegs;
     pReq->pfnComplete = pfnComplete;
     pReq->pvUser      = pvUser;
+    for (unsigned i = 0; i < cSegs; i++)
+    {
+        pReq->aSegs[i].pvSeg = paSegs[i].pvSeg;
+        pReq->aSegs[i].cbSeg = paSegs[i].cbSeg;
+    }
     RTCircBufReleaseWriteBlock(pIoBackend->pRequestRing, sizeof(VDIOBACKENDREQ));
     vdIoBackendMemThreadPoke(pIoBackend);
@@ -197,5 +201,5 @@
                 {
                     RTSGBUF SgBuf;
-                    RTSgBufInit(&SgBuf, pReq->paSegs, pReq->cSegs);
+                    RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
                     rcReq = VDMemDiskRead(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
                     break;
@@ -204,5 +208,5 @@
                 {
                     RTSGBUF SgBuf;
-                    RTSgBufInit(&SgBuf, pReq->paSegs, pReq->cSegs);
+                    RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
                     rcReq = VDMemDiskWrite(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
                     break;
Index: /trunk/src/VBox/Storage/testcase/VDIoRnd.cpp
===================================================================
--- /trunk/src/VBox/Storage/testcase/VDIoRnd.cpp	(revision 35596)
+++ /trunk/src/VBox/Storage/testcase/VDIoRnd.cpp	(revision 35596)
@@ -0,0 +1,106 @@
+/** @file
+ *
+ * VBox HDD container test utility - I/O data generator.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#define LOGGROUP LOGGROUP_DEFAULT
+#include <iprt/log.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/rand.h>
+
+#include "VDIoRnd.h"
+
+/**
+ * I/O random data generator instance data.
+ */
+typedef struct VDIORND
+{
+    /** Pointer to the buffer holding the random data. */
+    uint8_t *pbPattern;
+    /** Size of the buffer. */
+    size_t   cbPattern;
+    /** RNG */
+    RTRAND   hRand;
+} VDIORND;
+
+int VDIoRndCreate(PPVDIORND ppIoRnd, size_t cbPattern, uint64_t uSeed)
+{
+    PVDIORND pIoRnd = NULL;
+    int rc = VINF_SUCCESS;
+
+    AssertPtrReturn(ppIoRnd, VERR_INVALID_POINTER);
+
+    pIoRnd = (PVDIORND)RTMemAllocZ(sizeof(VDIORND));
+    if (pIoRnd)
+        pIoRnd->pbPattern = (uint8_t *)RTMemPageAllocZ(cbPattern);
+
+    if (   pIoRnd
+        && pIoRnd->pbPattern)
+    {
+        pIoRnd->cbPattern = cbPattern;
+
+        rc = RTRandAdvCreateParkMiller(&pIoRnd->hRand);
+        if (RT_SUCCESS(rc))
+        {
+            RTRandAdvSeed(pIoRnd->hRand, uSeed);
+            RTRandAdvBytes(pIoRnd->hRand, pIoRnd->pbPattern, cbPattern);
+        }
+        else
+        {
+            RTMemPageFree(pIoRnd->pbPattern, cbPattern);
+            RTMemFree(pIoRnd);
+        }
+    }
+    else
+    {
+        if (pIoRnd)
+            RTMemFree(pIoRnd);
+        rc = VERR_NO_MEMORY;
+    }
+
+    if (RT_SUCCESS(rc))
+        *ppIoRnd = pIoRnd;
+
+    return rc;
+}
+
+void VDIoRndDestroy(PVDIORND pIoRnd)
+{
+    AssertPtrReturnVoid(pIoRnd);
+
+    RTRandAdvDestroy(pIoRnd->hRand);
+    RTMemPageFree(pIoRnd->pbPattern, pIoRnd->cbPattern);
+    RTMemFree(pIoRnd);
+}
+
+int VDIoRndGetBuffer(PVDIORND pIoRnd, void **ppv, size_t cb)
+{
+    AssertPtrReturn(pIoRnd, VERR_INVALID_POINTER);
+    AssertPtrReturn(ppv, VERR_INVALID_POINTER);
+    AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+
+    if (cb > pIoRnd->cbPattern - 512)
+        return VERR_INVALID_PARAMETER;
+
+    *ppv = pIoRnd->pbPattern + RT_ALIGN_64(RTRandAdvU64Ex(pIoRnd->hRand, 0, pIoRnd->cbPattern - cb - 512), 512);
+    return VINF_SUCCESS;
+}
+
+
+uint32_t VDIoRndGetU32Ex(PVDIORND pIoRnd, uint32_t uMin, uint32_t uMax)
+{
+    return RTRandAdvU32Ex(pIoRnd->hRand, uMin, uMax);
+}
+
Index: /trunk/src/VBox/Storage/testcase/VDIoRnd.h
===================================================================
--- /trunk/src/VBox/Storage/testcase/VDIoRnd.h	(revision 35596)
+++ /trunk/src/VBox/Storage/testcase/VDIoRnd.h	(revision 35596)
@@ -0,0 +1,55 @@
+/** @file
+ *
+ * VBox HDD container test utility - I/O data generator.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#ifndef _VDIoRnd_h__
+#define _VDIoRnd_h__
+
+/** Pointer to the I/O random number generator. */
+typedef struct VDIORND *PVDIORND;
+/** Pointer to a I/O random number generator pointer. */
+typedef PVDIORND *PPVDIORND;
+
+/**
+ * Creates a I/O RNG.
+ *
+ * @returns VBox status code.
+ *
+ * @param ppIoRnd    Where to store the handle on success.
+ * @param cbPattern  Size of the test pattern to create.
+ * @param uSeed      Seed for the RNG.
+ */
+int VDIoRndCreate(PPVDIORND ppIoRnd, size_t cbPattern, uint64_t uSeed);
+
+/**
+ * Destroys the I/O RNG.
+ *
+ * @param pIoRnd     I/O RNG handle.
+ */
+void VDIoRndDestroy(PVDIORND pIoRnd);
+
+/**
+ * Returns a pointer filled with random data of the given size.
+ *
+ * @returns VBox status code.
+ *
+ * @param pIoRnd    I/O RNG handle.
+ * @param ppv       Where to store the pointer on success.
+ * @param cb        Size of the buffer.
+ */
+int VDIoRndGetBuffer(PVDIORND pIoRnd, void **ppv, size_t cb);
+
+uint32_t VDIoRndGetU32Ex(PVDIORND pIoRnd, uint32_t uMin, uint32_t uMax);
+#endif /* _VDIoRnd_h__ */
Index: /trunk/src/VBox/Storage/testcase/VDMemDisk.cpp
===================================================================
--- /trunk/src/VBox/Storage/testcase/VDMemDisk.cpp	(revision 35595)
+++ /trunk/src/VBox/Storage/testcase/VDMemDisk.cpp	(revision 35596)
@@ -263,5 +263,5 @@
         }
 
-        /* Kill a blocks coming after. */
+        /* Kill all blocks coming after. */
         do
         {
@@ -269,5 +269,7 @@
             if (pSeg)
             {
+                RTAvlrU64Remove(pMemDisk->pTreeSegments, pSeg->Core.Key);
                 RTMemFree(pSeg->pvSeg);
+                pSeg->pvSeg = NULL;
                 RTMemFree(pSeg);
             }
Index: /trunk/src/VBox/Storage/testcase/tstVDIo.cpp
===================================================================
--- /trunk/src/VBox/Storage/testcase/tstVDIo.cpp	(revision 35595)
+++ /trunk/src/VBox/Storage/testcase/tstVDIo.cpp	(revision 35596)
@@ -27,7 +27,9 @@
 #include <iprt/list.h>
 #include <iprt/ctype.h>
+#include <iprt/semaphore.h>
 
 #include "VDMemDisk.h"
 #include "VDIoBackendMem.h"
+#include "VDIoRnd.h"
 
 /**
@@ -73,5 +75,58 @@
     /** Logical CHS geometry. */
     VDGEOMETRY       LogicalGeom;
+    /** I/O RNG handle. */
+    PVDIORND         pIoRnd;
 } VDTESTGLOB, *PVDTESTGLOB;
+
+/**
+ * Transfer direction.
+ */
+typedef enum VDIOREQTXDIR
+{
+    VDIOREQTXDIR_READ = 0,
+    VDIOREQTXDIR_WRITE,
+    VDIOREQTXDIR_FLUSH
+} VDIOREQTXDIR;
+
+/**
+ * I/O request.
+ */
+typedef struct VDIOREQ
+{
+    /** Transfer type. */
+    VDIOREQTXDIR enmTxDir;
+    /** slot index. */
+    unsigned  idx;
+    /** Start offset. */
+    uint64_t  off;
+    /** Size to transfer. */
+    size_t    cbReq;
+    /** S/G Buffer */
+    RTSGBUF   SgBuf;
+    /** Data segment */
+    RTSGSEG   DataSeg;
+    /** Flag whether the request is outstanding or not. */
+    volatile bool fOutstanding;
+} VDIOREQ, *PVDIOREQ;
+
+/**
+ * I/O test data.
+ */
+typedef struct VDIOTEST
+{
+    /** Start offset. */
+    uint64_t    offStart;
+    /** End offset. */
+    uint64_t    offEnd;
+    /** Flag whether random or sequential access is wanted */
+    bool        fRandomAccess;
+    /** Block size. */
+    size_t      cbBlkIo;
+    /** Number of bytes to transfer. */
+    size_t      cbIo;
+    unsigned    uWriteChance;
+    PVDIORND    pIoRnd;
+    uint64_t    offNext;
+} VDIOTEST, *PVDIOTEST;
 
 /**
@@ -171,4 +226,7 @@
 static DECLCALLBACK(int) vdScriptHandlerMerge(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
 static DECLCALLBACK(int) vdScriptHandlerClose(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
+static DECLCALLBACK(int) vdScriptHandlerIoRngCreate(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
+static DECLCALLBACK(int) vdScriptHandlerIoRngDestroy(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
+static DECLCALLBACK(int) vdScriptHandlerSleep(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
 
 /* create action */
@@ -223,16 +281,34 @@
     /* pcszName  chId enmType                            fFlags */
     {"mode",     'm', VDSCRIPTARGTYPE_STRING,            VDSCRIPTARGDESC_FLAG_MANDATORY},
-    {"delete",   'd', VDSCRIPTARGTYPE_BOOL  ,            VDSCRIPTARGDESC_FLAG_MANDATORY}
+    {"delete",   'd', VDSCRIPTARGTYPE_BOOL,              VDSCRIPTARGDESC_FLAG_MANDATORY}
 };
 
+/* I/O RNG create action */
+const VDSCRIPTARGDESC g_aArgIoRngCreate[] =
+{
+    /* pcszName  chId enmType                            fFlags */
+    {"size",     'd', VDSCRIPTARGTYPE_UNSIGNED_NUMBER,   VDSCRIPTARGDESC_FLAG_MANDATORY | VDSCRIPTARGDESC_FLAG_SIZE_SUFFIX},
+    {"seed",     's', VDSCRIPTARGTYPE_UNSIGNED_NUMBER,   VDSCRIPTARGDESC_FLAG_MANDATORY}
+};
+
+/* Sleep */
+const VDSCRIPTARGDESC g_aArgSleep[] =
+{
+    /* pcszName  chId enmType                            fFlags */
+    {"time",     't', VDSCRIPTARGTYPE_UNSIGNED_NUMBER,   VDSCRIPTARGDESC_FLAG_MANDATORY},
+};
+
 const VDSCRIPTACTION g_aScriptActions[] =
 {
-    /* pcszAction paArgDesc     cArgDescs                  pfnHandler */
-    {"create",    g_aArgCreate, RT_ELEMENTS(g_aArgCreate), vdScriptHandlerCreate},
-    {"open",      g_aArgOpen,   RT_ELEMENTS(g_aArgOpen),   vdScriptHandlerOpen},
-    {"io",        g_aArgIo,     RT_ELEMENTS(g_aArgIo),     vdScriptHandlerIo},
-    {"flush",     g_aArgFlush,  RT_ELEMENTS(g_aArgFlush),  vdScriptHandlerFlush},
-    {"close",     g_aArgClose,  RT_ELEMENTS(g_aArgClose),  vdScriptHandlerClose},
-    {"merge",     g_aArgMerge,  RT_ELEMENTS(g_aArgMerge),  vdScriptHandlerMerge},
+    /* pcszAction    paArgDesc            cArgDescs                        pfnHandler */
+    {"create",       g_aArgCreate,        RT_ELEMENTS(g_aArgCreate),       vdScriptHandlerCreate},
+    {"open",         g_aArgOpen,          RT_ELEMENTS(g_aArgOpen),         vdScriptHandlerOpen},
+    {"io",           g_aArgIo,            RT_ELEMENTS(g_aArgIo),           vdScriptHandlerIo},
+    {"flush",        g_aArgFlush,         RT_ELEMENTS(g_aArgFlush),        vdScriptHandlerFlush},
+    {"close",        g_aArgClose,         RT_ELEMENTS(g_aArgClose),        vdScriptHandlerClose},
+    {"merge",        g_aArgMerge,         RT_ELEMENTS(g_aArgMerge),        vdScriptHandlerMerge},
+    {"iorngcreate",  g_aArgIoRngCreate,   RT_ELEMENTS(g_aArgIoRngCreate),  vdScriptHandlerIoRngCreate},
+    {"iorngdestroy", NULL,                0,                               vdScriptHandlerIoRngDestroy},
+    {"sleep",        g_aArgSleep,         RT_ELEMENTS(g_aArgSleep),        vdScriptHandlerSleep},
 };
 
@@ -253,4 +329,12 @@
     return VINF_SUCCESS;
 }
+
+static int tstVDIoTestInit(PVDIOTEST pIoTest, PVDTESTGLOB pGlob, bool fRandomAcc, size_t cbIo,
+                           size_t cbBlkSize, uint64_t offStart, uint64_t offEnd,
+                           unsigned uWriteChance, unsigned uReadChance);
+static bool tstVDIoTestRunning(PVDIOTEST pIoTest);
+static bool tstVDIoTestReqOutstanding(PVDIOREQ pIoReq);
+static int  tstVDIoTestReqInit(PVDIOTEST pIoTest, PVDIOREQ pIoReq);
+static void tstVDIoTestReqComplete(void *pvUser1, void *pvUser2, int rcReq);
 
 static DECLCALLBACK(int) vdScriptHandlerCreate(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs)
@@ -433,5 +517,148 @@
     }
 
-    rc = VERR_NOT_IMPLEMENTED;
+    if (RT_SUCCESS(rc))
+    {
+        VDIOTEST IoTest;
+
+        rc = tstVDIoTestInit(&IoTest, pGlob, fRandomAcc, cbIo, cbBlkSize, offStart, offEnd, uWriteChance, uReadChance);
+        if (RT_SUCCESS(rc))
+        {
+            PVDIOREQ paIoReq = NULL;
+            unsigned cMaxTasksOutstanding = fAsync ? cMaxReqs : 1;
+            RTSEMEVENT EventSem;
+
+            rc = RTSemEventCreate(&EventSem);
+            paIoReq = (PVDIOREQ)RTMemAllocZ(cMaxTasksOutstanding * sizeof(VDIOREQ));
+            if (paIoReq && RT_SUCCESS(rc))
+            {
+                for (unsigned i = 0; i < cMaxTasksOutstanding; i++)
+                    paIoReq[i].idx = i;
+
+                while (tstVDIoTestRunning(&IoTest))
+                {
+                    bool fTasksOutstanding = false;
+                    unsigned idx = 0;
+
+                    /* Submit all idling requests. */
+                    while (   idx < cMaxTasksOutstanding
+                           && tstVDIoTestRunning(&IoTest))
+                    {
+                        if (!tstVDIoTestReqOutstanding(&paIoReq[idx]))
+                        {
+                            rc = tstVDIoTestReqInit(&IoTest, &paIoReq[idx]);
+                            AssertRC(rc);
+
+                            if (RT_SUCCESS(rc))
+                            {
+                                if (!fAsync)
+                                {
+                                    switch (paIoReq[idx].enmTxDir)
+                                    {
+                                        case VDIOREQTXDIR_READ:
+                                        {
+                                            rc = VDRead(pGlob->pVD, paIoReq[idx].off, paIoReq[idx].DataSeg.pvSeg, paIoReq[idx].cbReq);
+                                            RTMemFree(paIoReq[idx].DataSeg.pvSeg);
+                                            break;
+                                        }
+                                        case VDIOREQTXDIR_WRITE:
+                                        {
+                                            rc = VDWrite(pGlob->pVD, paIoReq[idx].off, paIoReq[idx].DataSeg.pvSeg, paIoReq[idx].cbReq);
+                                            break;
+                                        }
+                                        case VDIOREQTXDIR_FLUSH:
+                                        {
+                                            rc = VDFlush(pGlob->pVD);
+                                            break;
+                                        }
+                                    }
+                                    if (RT_SUCCESS(rc))
+                                        idx++;
+                                }
+                                else
+                                {
+                                    switch (paIoReq[idx].enmTxDir)
+                                    {
+                                        case VDIOREQTXDIR_READ:
+                                        {
+                                            rc = VDAsyncRead(pGlob->pVD, paIoReq[idx].off, paIoReq[idx].cbReq, &paIoReq[idx].SgBuf,
+                                                             tstVDIoTestReqComplete, &paIoReq[idx], EventSem);
+                                            if (rc == VINF_VD_ASYNC_IO_FINISHED)
+                                                RTMemFree(paIoReq[idx].DataSeg.pvSeg);
+                                            break;
+                                        }
+                                        case VDIOREQTXDIR_WRITE:
+                                        {
+                                            rc = VDAsyncWrite(pGlob->pVD, paIoReq[idx].off, paIoReq[idx].cbReq, &paIoReq[idx].SgBuf,
+                                                              tstVDIoTestReqComplete, &paIoReq[idx], EventSem);
+                                            break;
+                                        }
+                                        case VDIOREQTXDIR_FLUSH:
+                                        {
+                                            rc = VDAsyncFlush(pGlob->pVD, tstVDIoTestReqComplete, &paIoReq[idx], EventSem);
+                                            break;
+                                        }
+                                    }
+
+                                    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+                                    {
+                                        idx++;
+                                        fTasksOutstanding = true;
+                                        rc = VINF_SUCCESS;
+                                    }
+                                    else if (rc == VINF_VD_ASYNC_IO_FINISHED)
+                                    {
+                                        ASMAtomicXchgBool(&paIoReq[idx].fOutstanding, false);
+                                        rc = VINF_SUCCESS;
+                                    }
+                                }
+
+                                if (RT_FAILURE(rc))
+                                    RTPrintf("Error submitting task %u rc=%Rrc\n", paIoReq[idx].idx, rc);
+                            }
+                        }
+                    }
+
+                    /* Wait for a request to complete. */
+                    if (   fAsync
+                        && fTasksOutstanding)
+                    {
+                        rc = RTSemEventWait(EventSem, RT_INDEFINITE_WAIT);
+                        AssertRC(rc);
+                    }
+                }
+
+                /* Cleanup, wait for all tasks to complete. */
+                while (fAsync)
+                {
+                    unsigned idx = 0;
+                    bool fAllIdle = true;
+
+                    while (idx < cMaxTasksOutstanding)
+                    {
+                        if (tstVDIoTestReqOutstanding(&paIoReq[idx]))
+                        {
+                            fAllIdle = false;
+                            break;
+                        }
+                        idx++;
+                    }
+
+                    if (!fAllIdle)
+                    {
+                        rc = RTSemEventWait(EventSem, 100);
+                        Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
+                    }
+                    else
+                        break;
+                }
+
+                RTSemEventDestroy(EventSem);
+                RTMemFree(paIoReq);
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+    }
+
     return rc;
 }
@@ -515,4 +742,77 @@
 }
 
+
+static DECLCALLBACK(int) vdScriptHandlerIoRngCreate(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs)
+{
+    int rc = VINF_SUCCESS;
+    size_t cbPattern = 0;
+    uint64_t uSeed = 0;
+
+    for (unsigned i = 0; i < cScriptArgs; i++)
+    {
+        switch (paScriptArgs[i].chId)
+        {
+            case 'd':
+            {
+                cbPattern = paScriptArgs[i].u.u64;
+                break;
+            }
+            case 's':
+            {
+                uSeed = paScriptArgs[i].u.u64;
+                break;
+            }
+            default:
+                AssertMsgFailed(("Invalid argument given!\n"));
+        }
+    }
+
+    if (pGlob->pIoRnd)
+    {
+        RTPrintf("I/O RNG already exists\n");
+        rc = VERR_INVALID_STATE;
+    }
+    else
+        rc = VDIoRndCreate(&pGlob->pIoRnd, cbPattern, uSeed);
+
+    return rc;
+}
+
+static DECLCALLBACK(int) vdScriptHandlerIoRngDestroy(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs)
+{
+    if (pGlob->pIoRnd)
+    {
+        VDIoRndDestroy(pGlob->pIoRnd);
+        pGlob->pIoRnd = NULL;
+    }
+    else
+        RTPrintf("WARNING: No I/O RNG active, faulty script. Continuing\n");
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) vdScriptHandlerSleep(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs)
+{
+    int rc = VINF_SUCCESS;
+    uint64_t cMillies = 0;
+
+    for (unsigned i = 0; i < cScriptArgs; i++)
+    {
+        switch (paScriptArgs[i].chId)
+        {
+            case 't':
+            {
+                cMillies = paScriptArgs[i].u.u64;
+                break;
+            }
+            default:
+                AssertMsgFailed(("Invalid argument given!\n"));
+        }
+    }
+
+    rc = RTThreadSleep(cMillies);
+    return rc;
+}
+
 static DECLCALLBACK(int) tstVDIoFileOpen(void *pvUser, const char *pszLocation,
                                          uint32_t fOpen,
@@ -537,5 +837,5 @@
     if (fFound && pIt->pfnComplete)
         rc = VERR_FILE_LOCK_FAILED;
-    else if (fOpen & RTFILE_O_CREATE)
+    else if ((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE)
     {
         /* If the file exists delete the memory disk. */
@@ -571,5 +871,5 @@
         }
     }
-    else if (fOpen & RTFILE_O_OPEN)
+    else if ((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN)
     {
         if (!fFound)
@@ -784,4 +1084,101 @@
 
     return rc;
+}
+
+static int tstVDIoTestInit(PVDIOTEST pIoTest, PVDTESTGLOB pGlob, bool fRandomAcc, size_t cbIo,
+                           size_t cbBlkSize, uint64_t offStart, uint64_t offEnd,
+                           unsigned uWriteChance, unsigned uReadChance)
+{
+    pIoTest->fRandomAccess = fRandomAcc;
+    pIoTest->cbIo          = cbIo;
+    pIoTest->cbBlkIo       = cbBlkSize;
+    pIoTest->offStart      = offStart;
+    pIoTest->offEnd        = offEnd;
+    pIoTest->uWriteChance  = uWriteChance;
+    pIoTest->pIoRnd        = pGlob->pIoRnd;
+    pIoTest->offNext       = pIoTest->offEnd < pIoTest->offStart ? pIoTest->offEnd - cbBlkSize : 0;
+    return VINF_SUCCESS;
+}
+
+static bool tstVDIoTestRunning(PVDIOTEST pIoTest)
+{
+    return pIoTest->cbIo > 0;
+}
+
+static bool tstVDIoTestReqOutstanding(PVDIOREQ pIoReq)
+{
+    return pIoReq->fOutstanding;
+}
+
+/**
+ * Returns true with the given chance in percent.
+ *
+ * @returns true or false
+ * @param   iPercentage   The percentage of the chance to return true.
+ */
+static bool tstVDIoTestIsTrue(PVDIOTEST pIoTest, int iPercentage)
+{
+    int uRnd = VDIoRndGetU32Ex(pIoTest->pIoRnd, 0, 100);
+
+    return (uRnd <= iPercentage); /* This should be enough for our purpose */
+}
+
+static int tstVDIoTestReqInit(PVDIOTEST pIoTest, PVDIOREQ pIoReq)
+{
+    int rc = VINF_SUCCESS;
+
+    if (pIoTest->cbIo)
+    {
+        /* Read or Write? */
+        pIoReq->enmTxDir = tstVDIoTestIsTrue(pIoTest, pIoTest->uWriteChance) ? VDIOREQTXDIR_WRITE : VDIOREQTXDIR_READ;
+        pIoReq->cbReq = RT_MIN(pIoTest->cbBlkIo, pIoTest->cbIo);
+        pIoTest->cbIo -= pIoReq->cbReq;
+        pIoReq->DataSeg.cbSeg = pIoReq->cbReq;
+        pIoReq->off           = pIoTest->offNext;
+
+        if (pIoReq->enmTxDir == VDIOREQTXDIR_WRITE)
+        {
+            rc = VDIoRndGetBuffer(pIoTest->pIoRnd, &pIoReq->DataSeg.pvSeg, pIoReq->cbReq);
+            AssertRC(rc);
+        }
+        else
+        {
+            /* Read */
+            pIoReq->DataSeg.pvSeg = RTMemAlloc(pIoReq->cbReq);
+            if (!pIoReq->DataSeg.pvSeg)
+                rc = VERR_NO_MEMORY;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            RTSgBufInit(&pIoReq->SgBuf, &pIoReq->DataSeg, 1);
+
+            if (pIoTest->fRandomAccess)
+            {
+                /** @todo */
+            }
+            else
+            {
+                pIoTest->offNext = pIoTest->offEnd < pIoTest->offStart
+                                   ? RT_MAX(pIoTest->offEnd, pIoTest->offNext - pIoTest->cbBlkIo)
+                                   : RT_MIN(pIoTest->offEnd, pIoTest->offNext + pIoTest->cbBlkIo);
+            }
+            pIoReq->fOutstanding = true;
+        }
+    }
+    else
+        rc = VERR_ACCESS_DENIED;
+
+    return rc;
+}
+
+static void tstVDIoTestReqComplete(void *pvUser1, void *pvUser2, int rcReq)
+{
+    PVDIOREQ pIoReq = (PVDIOREQ)pvUser1;
+    RTSEMEVENT hEventSem = (RTSEMEVENT)pvUser2;
+
+    ASMAtomicXchgBool(&pIoReq->fOutstanding, false);
+    RTSemEventSignal(hEventSem);
+    return;
 }
 
@@ -904,5 +1301,5 @@
                             case 'K':
                             {
-                                pScriptArg->u.u64 *= 1024;
+                                pScriptArg->u.u64 *= _1K;
                                 break;
                             }
@@ -910,5 +1307,5 @@
                             case 'M':
                             {
-                                pScriptArg->u.u64 *= 1024*1024;
+                                pScriptArg->u.u64 *= _1M;
                                 break;
                             }
@@ -916,5 +1313,5 @@
                             case 'G':
                             {
-                                pScriptArg->u.u64 *= 1024*1024*1024;
+                                pScriptArg->u.u64 *= _1G;
                                 break;
                             }
@@ -946,5 +1343,5 @@
                                 case 'K':
                                 {
-                                    pScriptArg->u.Range.Start *= 1024;
+                                    pScriptArg->u.u64 *= _1K;
                                     break;
                                 }
@@ -952,5 +1349,5 @@
                                 case 'M':
                                 {
-                                    pScriptArg->u.Range.Start *= 1024*1024;
+                                    pScriptArg->u.u64 *= _1M;
                                     break;
                                 }
@@ -958,5 +1355,5 @@
                                 case 'G':
                                 {
-                                    pScriptArg->u.Range.Start *= 1024*1024*1024;
+                                    pScriptArg->u.u64 *= _1G;
                                     break;
                                 }
@@ -980,5 +1377,5 @@
                                     case 'K':
                                     {
-                                        pScriptArg->u.Range.End *= 1024;
+                                        pScriptArg->u.Range.End *= _1K;
                                         break;
                                     }
@@ -986,5 +1383,5 @@
                                     case 'M':
                                     {
-                                        pScriptArg->u.Range.End *= 1024*1024;
+                                        pScriptArg->u.Range.End *= _1M;
                                         break;
                                     }
@@ -992,5 +1389,5 @@
                                     case 'G':
                                     {
-                                        pScriptArg->u.Range.End *= 1024*1024*1024;
+                                        pScriptArg->u.Range.End *= _1G;
                                         break;
                                     }
@@ -1177,20 +1574,21 @@
                         cScriptArgsMax = pVDScriptAction->cArgDescs;
                         paScriptArgs = (PVDSCRIPTARG)RTMemAllocZ(cScriptArgsMax * sizeof(VDSCRIPTARG));
-                        if (paScriptArgs)
+                    }
+
+                    if (paScriptArgs)
+                    {
+                        unsigned cScriptArgs;
+
+                        rc = tstVDIoScriptArgumentListParse(psz, pVDScriptAction, paScriptArgs, &cScriptArgs);
+                        if (RT_SUCCESS(rc))
                         {
-                            unsigned cScriptArgs;
-
-                            rc = tstVDIoScriptArgumentListParse(psz, pVDScriptAction, paScriptArgs, &cScriptArgs);
-                            if (RT_SUCCESS(rc))
-                            {
-                                /* Execute the handler. */
-                                rc = pVDScriptAction->pfnHandler(pGlob, paScriptArgs, cScriptArgs);
-                            }
+                            /* Execute the handler. */
+                            rc = pVDScriptAction->pfnHandler(pGlob, paScriptArgs, cScriptArgs);
                         }
-                        else
-                        {
-                            RTPrintf("Out of memory while allocating argument array for script action %s\n", pcszAction);
-                            rc = VERR_NO_MEMORY;
-                        }
+                    }
+                    else
+                    {
+                        RTPrintf("Out of memory while allocating argument array for script action %s\n", pcszAction);
+                        rc = VERR_NO_MEMORY;
                     }
                 }
@@ -1209,4 +1607,9 @@
     } while(RT_SUCCESS(rc));
 
+    if (rc == VERR_EOF)
+    {
+        RTPrintf("Successfully executed I/O script\n");
+        rc = VINF_SUCCESS;
+    }
     return rc;
 }
