Index: trunk/src/VBox/Storage/DMG.cpp
===================================================================
--- trunk/src/VBox/Storage/DMG.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/DMG.cpp	(revision 44252)
@@ -1660,8 +1660,9 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnRead */
-static int dmgRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                   size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
+static int dmgRead(void *pBackendData, uint64_t uOffset,  size_t cbToRead,
+                   PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     PDMGIMAGE pThis = (PDMGIMAGE)pBackendData;
     PDMGEXTENT pExtent = NULL;
@@ -1692,12 +1693,12 @@
             case DMGEXTENTTYPE_RAW:
             {
-                rc = vdIfIoIntFileReadSync(pThis->pIfIo, pThis->pStorage,
+                rc = vdIfIoIntFileReadUser(pThis->pIfIo, pThis->pStorage,
                                            pExtent->offFileStart + DMG_BLOCK2BYTE(uExtentRel),
-                                           pvBuf, cbToRead);
+                                           pIoCtx, cbToRead);
                 break;
             }
             case DMGEXTENTTYPE_ZERO:
             {
-                memset(pvBuf, 0, cbToRead);
+                vdIfIoIntIoCtxSet(pThis->pIfIo, pIoCtx, 0, cbToRead);
                 break;
             }
@@ -1729,5 +1730,7 @@
 
                 if (RT_SUCCESS(rc))
-                    memcpy(pvBuf, (uint8_t *)pThis->pvDecompExtent + DMG_BLOCK2BYTE(uExtentRel), cbToRead);
+                    vdIfIoIntIoCtxCopyTo(pThis->pIfIo, pIoCtx,
+                                         (uint8_t *)pThis->pvDecompExtent + DMG_BLOCK2BYTE(uExtentRel),
+                                         cbToRead);
                 break;
             }
@@ -1748,10 +1751,10 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int dmgWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                    size_t cbToWrite, size_t *pcbWriteProcess,
-                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
+static int dmgWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
+                    PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                    size_t *pcbPostRead, unsigned fWrite)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
     PDMGIMAGE pThis = (PDMGIMAGE)pBackendData;
     int rc = VERR_NOT_IMPLEMENTED;
@@ -1775,5 +1778,5 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int dmgFlush(void *pBackendData)
+static int dmgFlush(void *pBackendData, PVDIOCTX pIoCtx)
 {
     LogFlowFunc(("pBackendData=%#p\n", pBackendData));
@@ -2269,4 +2272,6 @@
     /* pfnFlush */
     dmgFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     dmgGetVersion,
@@ -2321,10 +2326,4 @@
     /* pfnSetParentFilename */
     NULL,
-    /* pfnAsyncRead */
-    NULL,
-    /* pfnAsyncWrite */
-    NULL,
-    /* pfnAsyncFlush */
-    NULL,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -2335,8 +2334,4 @@
     /* pfnResize */
     NULL,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
Index: trunk/src/VBox/Storage/ISCSI.cpp
===================================================================
--- trunk/src/VBox/Storage/ISCSI.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/ISCSI.cpp	(revision 44252)
@@ -4604,7 +4604,6 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnRead */
-static int iscsiRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                     size_t cbToRead, size_t *pcbActuallyRead)
+static int iscsiReadSync(void *pBackendData, uint64_t uOffset, void *pvBuf,
+                         size_t cbToRead, size_t *pcbActuallyRead)
 {
     /** @todo reinstate logging of the target everywhere - dropped temporarily */
@@ -4706,8 +4705,7 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int iscsiWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                     size_t cbToWrite, size_t *pcbWriteProcess,
-                     size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
+static int iscsiWriteSync(void *pBackendData, uint64_t uOffset, const void *pvBuf,
+                          size_t cbToWrite, size_t *pcbWriteProcess,
+                          size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
 {
      LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
@@ -4810,6 +4808,5 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int iscsiFlush(void *pBackendData)
+static int iscsiFlushSync(void *pBackendData)
 {
     LogFlowFunc(("pBackendData=%#p\n", pBackendData));
@@ -4853,430 +4850,7 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
-static unsigned iscsiGetVersion(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-
-    Assert(pImage);
-    NOREF(pImage);
-
-    return 0;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetSize */
-static uint64_t iscsiGetSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-
-    Assert(pImage);
-
-    if (pImage)
-        return pImage->cbSize;
-    else
-        return 0;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
-static uint64_t iscsiGetFileSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-
-    Assert(pImage);
-    NOREF(pImage);
-
-    if (pImage)
-        return pImage->cbSize;
-    else
-        return 0;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
-static int iscsiGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-        rc = VERR_VD_GEOMETRY_NOT_SET;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
-static int iscsiSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-        rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
-static int iscsiGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-        rc = VERR_VD_GEOMETRY_NOT_SET;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
-static int iscsiSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-        rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
-static unsigned iscsiGetImageFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    unsigned uImageFlags;
-
-    Assert(pImage);
-    NOREF(pImage);
-
-    uImageFlags = VD_IMAGE_FLAGS_FIXED;
-
-    LogFlowFunc(("returns %#x\n", uImageFlags));
-    return uImageFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
-static unsigned iscsiGetOpenFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    unsigned uOpenFlags;
-
-    Assert(pImage);
-
-    if (pImage)
-        uOpenFlags = pImage->uOpenFlags;
-    else
-        uOpenFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uOpenFlags));
-    return uOpenFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
-static int iscsiSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
-{
-    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    /* Image must be opened and the new flags must be valid. */
-    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
-                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
-                                   | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Implement this operation via reopening the image if we actually need
-     * to do something. A read/write -> readonly transition doesn't need a
-     * reopen. In the other direction we don't have the necessary information
-     * as the "disk is readonly" flag is thrown away. Can be optimized too,
-     * but it's not worth the effort at the moment. */
-    if (   !(uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        && (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-    {
-        iscsiFreeImage(pImage, false);
-        rc = iscsiOpenImage(pImage, uOpenFlags);
-    }
-    else
-    {
-        pImage->uOpenFlags = uOpenFlags;
-        rc = VINF_SUCCESS;
-    }
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetComment */
-static int iscsiGetComment(void *pBackendData, char *pszComment,
-                          size_t cbComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetComment */
-static int iscsiSetComment(void *pBackendData, const char *pszComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
-static int iscsiGetUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
-static int iscsiSetUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    LogFlowFunc(("%RTuuid\n", pUuid));
-    Assert(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
-static int iscsiGetModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
-static int iscsiSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    LogFlowFunc(("%RTuuid\n", pUuid));
-    Assert(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
-static int iscsiGetParentUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
-static int iscsiSetParentUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    LogFlowFunc(("%RTuuid\n", pUuid));
-    Assert(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
-static int iscsiGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    Assert(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
-static int iscsiSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-    int rc;
-
-    LogFlowFunc(("%RTuuid\n", pUuid));
-    Assert(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnDump */
-static void iscsiDump(void *pBackendData)
-{
-    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
-
-    Assert(pImage);
-    if (pImage)
-    {
-        /** @todo put something useful here */
-        vdIfErrorMessage(pImage->pIfError, "Header: cVolume=%u\n", pImage->cVolume);
-    }
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
-static int iscsiAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
-                          PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+/** @copydoc VBOXHDDBACKEND::pfnRead */
+static int iscsiRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
+                     PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
 {
     PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
@@ -5306,5 +4880,5 @@
         Assert(cbSegs == cbToRead);
 
-        return iscsiRead(pBackendData, uOffset, Segment.pvSeg, cbToRead, pcbActuallyRead);
+        return iscsiReadSync(pBackendData, uOffset, Segment.pvSeg, cbToRead, pcbActuallyRead);
     }
 
@@ -5412,8 +4986,7 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
-static int iscsiAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
-                           PVDIOCTX pIoCtx,
-                           size_t *pcbWriteProcess, size_t *pcbPreRead,
-                           size_t *pcbPostRead, unsigned fWrite)
+static int iscsiWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
+                      PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                      size_t *pcbPostRead, unsigned fWrite)
 {
     LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbToWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
@@ -5434,5 +5007,5 @@
     cbToWrite = RT_MIN(cbToWrite, pImage->cbSendDataLength);
 
-    /** @todo: Remove iscsiWrite and integrate properly. */
+    /** @todo: Remove iscsiWriteSync and integrate properly. */
     if (vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx))
     {
@@ -5445,6 +5018,6 @@
         Assert(cbSegs == cbToWrite);
 
-        return iscsiWrite(pBackendData, uOffset, Segment.pvSeg, cbToWrite,
-                          pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite);
+        return iscsiWriteSync(pBackendData, uOffset, Segment.pvSeg, cbToWrite,
+                              pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite);
     }
 
@@ -5551,6 +5124,6 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
-static int iscsiAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
+/** @copydoc VBOXHDDBACKEND::pfnFlush */
+static int iscsiFlush(void *pBackendData, PVDIOCTX pIoCtx)
 {
     LogFlowFunc(("pBackendData=%p pIoCtx=%#p\n", pBackendData, pIoCtx));
@@ -5558,7 +5131,7 @@
     int rc = VINF_SUCCESS;
 
-    /** @todo: Remove iscsiFlush and integrate properly. */
+    /** @todo: Remove iscsiFlushSync and integrate properly. */
     if (vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx))
-        return iscsiFlush(pBackendData);
+        return iscsiFlushSync(pBackendData);
 
     PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)RTMemAllocZ(sizeof(SCSIREQASYNC));
@@ -5616,4 +5189,427 @@
     LogFlowFunc(("returns rc=%Rrc\n", rc));
     return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
+static unsigned iscsiGetVersion(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+
+    Assert(pImage);
+    NOREF(pImage);
+
+    return 0;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetSize */
+static uint64_t iscsiGetSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+
+    Assert(pImage);
+
+    if (pImage)
+        return pImage->cbSize;
+    else
+        return 0;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
+static uint64_t iscsiGetFileSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+
+    Assert(pImage);
+    NOREF(pImage);
+
+    if (pImage)
+        return pImage->cbSize;
+    else
+        return 0;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
+static int iscsiGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+        rc = VERR_VD_GEOMETRY_NOT_SET;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
+static int iscsiSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+        rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
+static int iscsiGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+        rc = VERR_VD_GEOMETRY_NOT_SET;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
+static int iscsiSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+        rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
+static unsigned iscsiGetImageFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    unsigned uImageFlags;
+
+    Assert(pImage);
+    NOREF(pImage);
+
+    uImageFlags = VD_IMAGE_FLAGS_FIXED;
+
+    LogFlowFunc(("returns %#x\n", uImageFlags));
+    return uImageFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
+static unsigned iscsiGetOpenFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    unsigned uOpenFlags;
+
+    Assert(pImage);
+
+    if (pImage)
+        uOpenFlags = pImage->uOpenFlags;
+    else
+        uOpenFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uOpenFlags));
+    return uOpenFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
+static int iscsiSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
+{
+    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    /* Image must be opened and the new flags must be valid. */
+    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
+                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
+                                   | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
+    /* Implement this operation via reopening the image if we actually need
+     * to do something. A read/write -> readonly transition doesn't need a
+     * reopen. In the other direction we don't have the necessary information
+     * as the "disk is readonly" flag is thrown away. Can be optimized too,
+     * but it's not worth the effort at the moment. */
+    if (   !(uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        && (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+    {
+        iscsiFreeImage(pImage, false);
+        rc = iscsiOpenImage(pImage, uOpenFlags);
+    }
+    else
+    {
+        pImage->uOpenFlags = uOpenFlags;
+        rc = VINF_SUCCESS;
+    }
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetComment */
+static int iscsiGetComment(void *pBackendData, char *pszComment,
+                          size_t cbComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetComment */
+static int iscsiSetComment(void *pBackendData, const char *pszComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
+static int iscsiGetUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
+static int iscsiSetUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    LogFlowFunc(("%RTuuid\n", pUuid));
+    Assert(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
+static int iscsiGetModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
+static int iscsiSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    LogFlowFunc(("%RTuuid\n", pUuid));
+    Assert(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
+static int iscsiGetParentUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
+static int iscsiSetParentUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    LogFlowFunc(("%RTuuid\n", pUuid));
+    Assert(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
+static int iscsiGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    Assert(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
+static int iscsiSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+    int rc;
+
+    LogFlowFunc(("%RTuuid\n", pUuid));
+    Assert(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnDump */
+static void iscsiDump(void *pBackendData)
+{
+    PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData;
+
+    Assert(pImage);
+    if (pImage)
+    {
+        /** @todo put something useful here */
+        vdIfErrorMessage(pImage->pIfError, "Header: cVolume=%u\n", pImage->cVolume);
+    }
 }
 
@@ -5705,4 +5701,6 @@
     /* pfnFlush */
     iscsiFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     iscsiGetVersion,
@@ -5757,10 +5755,4 @@
     /* pfnSetParentFilename */
     NULL,
-    /* pfnAsyncRead */
-    iscsiAsyncRead,
-    /* pfnAsyncWrite */
-    iscsiAsyncWrite,
-    /* pfnAsyncFlush */
-    iscsiAsyncFlush,
     /* pfnComposeLocation */
     iscsiComposeLocation,
@@ -5771,8 +5763,4 @@
     /* pfnResize */
     NULL,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
Index: trunk/src/VBox/Storage/Parallels.cpp
===================================================================
--- trunk/src/VBox/Storage/Parallels.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/Parallels.cpp	(revision 44252)
@@ -602,11 +602,14 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnRead */
-static int parallelsRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                         size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+static int parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
+                         PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     int rc = VINF_SUCCESS;
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    uint64_t uSector;
+    uint64_t uOffsetInFile;
+    uint32_t iIndexInAllocationTable;
 
     AssertPtr(pImage);
@@ -615,69 +618,8 @@
 
     if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
-        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf, cbToRead);
-    else
-    {
-        uint64_t uSector;
-        uint32_t iIndexInAllocationTable;
-
-        /* Calculate offset in the real file. */
-        uSector = uOffset / 512;
-
-        /* One chunk in the file is always one track big. */
-        iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
-        uSector = uSector % pImage->PCHSGeometry.cSectors;
-
-        Assert(iIndexInAllocationTable < pImage->cAllocationBitmapEntries);
-
-        cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
-
-        LogFlowFunc(("AllocationBitmap[%u]=%u uSector=%u cbToRead=%zu cAllocationBitmapEntries=%u\n",
-                     iIndexInAllocationTable, pImage->pAllocationBitmap[iIndexInAllocationTable],
-                     uSector, cbToRead, pImage->cAllocationBitmapEntries));
-
-        if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
-            rc = VERR_VD_BLOCK_FREE;
-        else
-        {
-            uint64_t uOffsetInFile = ((uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
-
-            LogFlowFunc(("uOffsetInFile=%llu\n", uOffsetInFile));
-            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
-                                       pvBuf, cbToRead);
-        }
-    }
-
-    if (   (   RT_SUCCESS(rc)
-            || rc == VERR_VD_BLOCK_FREE)
-        && pcbActuallyRead)
-        *pcbActuallyRead = cbToRead;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int parallelsWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                          size_t cbToWrite, size_t *pcbWriteProcess,
-                          size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc = VINF_SUCCESS;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToWrite % 512 == 0);
-
-    if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffset,
-                                    pvBuf, cbToWrite);
-    else
-    {
-        uint64_t uSector;
-        uint64_t uOffsetInFile;
-        uint32_t iIndexInAllocationTable;
-
+        rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
+                                   pIoCtx, cbToRead);
+    else
+    {
         /* Calculate offset in the real file. */
         uSector = uOffset / 512;
@@ -686,552 +628,8 @@
         uSector = uSector % pImage->PCHSGeometry.cSectors;
 
-        Assert(iIndexInAllocationTable < pImage->cAllocationBitmapEntries);
-
-        cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
-
-        LogFlowFunc(("AllocationBitmap[%u]=%u uSector=%u cbToWrite=%zu cAllocationBitmapEntries=%u\n",
-                     iIndexInAllocationTable, pImage->pAllocationBitmap[iIndexInAllocationTable],
-                     uSector, cbToWrite, pImage->cAllocationBitmapEntries));
+        cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
 
         if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
-        {
-            if (   cbToWrite == pImage->PCHSGeometry.cSectors * 512
-                && !(fWrite & VD_WRITE_NO_ALLOC))
-            {
-                /* Stay on the safe side. Do not run the risk of confusing the higher
-                 * level, as that can be pretty lethal to image consistency. */
-                *pcbPreRead = 0;
-                *pcbPostRead = 0;
-
-                /* Allocate new chunk in the file. */
-                AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
-                pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
-                pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
-                pImage->fAllocationBitmapChanged = true;
-
-                uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
-
-                LogFlowFunc(("uOffsetInFile=%llu\n", uOffsetInFile));
-
-                /*
-                 * Write the new block at the current end of the file.
-                 */
-                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                            uOffsetInFile, pvBuf, cbToWrite);
-            }
-            else
-            {
-                /* Trying to do a partial write to an unallocated cluster. Don't do
-                 * anything except letting the upper layer know what to do. */
-                *pcbPreRead  = uSector * 512;
-                *pcbPostRead = (pImage->PCHSGeometry.cSectors * 512) - cbToWrite - *pcbPreRead;
-                rc = VERR_VD_BLOCK_FREE;
-            }
-        }
-        else
-        {
-            uOffsetInFile = ((uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
-
-            LogFlowFunc(("uOffsetInFile=%llu\n", uOffsetInFile));
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
-                                        pvBuf, cbToWrite);
-        }
-    }
-
-    if (pcbWriteProcess)
-        *pcbWriteProcess = cbToWrite;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int parallelsFlush(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    rc = parallelsFlushImage(pImage);
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
-static unsigned parallelsGetVersion(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        return PARALLELS_DISK_VERSION;
-    else
-        return 0;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetSize */
-static uint64_t parallelsGetSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage && pImage->pStorage)
-        cb = pImage->cbSize;
-
-    LogFlowFunc(("returns %llu\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
-static uint64_t parallelsGetFileSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage && pImage->pStorage)
-        cb = pImage->cbFileCurrent;
-
-    LogFlowFunc(("returns %lld\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
-static int parallelsGetPCHSGeometry(void *pBackendData,
-                                    PVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->PCHSGeometry.cCylinders)
-        {
-            *pPCHSGeometry = pImage->PCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
-static int parallelsSetPCHSGeometry(void *pBackendData,
-                                    PCVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->PCHSGeometry = *pPCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
-static int parallelsGetLCHSGeometry(void *pBackendData,
-                                    PVDGEOMETRY pLCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->LCHSGeometry.cCylinders)
-        {
-            *pLCHSGeometry = pImage->LCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
-static int parallelsSetLCHSGeometry(void *pBackendData,
-                                    PCVDGEOMETRY pLCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->LCHSGeometry = *pLCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
-static unsigned parallelsGetImageFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    unsigned uImageFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uImageFlags = pImage->uImageFlags;
-    else
-        uImageFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uImageFlags));
-    return uImageFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
-static unsigned parallelsGetOpenFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    unsigned uOpenFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uOpenFlags = pImage->uOpenFlags;
-    else
-        uOpenFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uOpenFlags));
-    return uOpenFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
-static int parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
-{
-    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    /* Image must be opened and the new flags must be valid. */
-    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
-                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
-                                   | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Implement this operation via reopening the image. */
-    parallelsFreeImage(pImage, false);
-    rc = parallelsOpenImage(pImage, uOpenFlags);
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetComment */
-static int parallelsGetComment(void *pBackendData, char *pszComment,
-                               size_t cbComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetComment */
-static int parallelsSetComment(void *pBackendData, const char *pszComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else
-            rc = VERR_NOT_SUPPORTED;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
-static int parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
-static int parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
-static int parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
-static int parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
-static int parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
-static int parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
-static int parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
-static int parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnDump */
-static void parallelsDump(void *pBackendData)
-{
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
-                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
-                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
-    }
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
-static int parallelsAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
-                              PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
-    int rc = VINF_SUCCESS;
-    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
-    uint64_t uSector;
-    uint64_t uOffsetInFile;
-    uint32_t iIndexInAllocationTable;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToRead % 512 == 0);
-
-    if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
-        rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
-                                   pIoCtx, cbToRead);
-    else
-    {
-        /* Calculate offset in the real file. */
-        uSector = uOffset / 512;
-        /* One chunk in the file is always one track big. */
-        iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
-        uSector = uSector % pImage->PCHSGeometry.cSectors;
-
-        cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
-
-        if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
-        {
             rc = VERR_VD_BLOCK_FREE;
-        }
         else
         {
@@ -1248,9 +646,8 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
-static int parallelsAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
-                               PVDIOCTX pIoCtx,
-                               size_t *pcbWriteProcess, size_t *pcbPreRead,
-                               size_t *pcbPostRead, unsigned fWrite)
+/** @copydoc VBOXHDDBACKEND::pfnWrite */
+static int parallelsWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
+                          PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                          size_t *pcbPostRead, unsigned fWrite)
 {
     LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
@@ -1333,6 +730,6 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
-static int parallelsAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
+/** @copydoc VBOXHDDBACKEND::pfnFlush */
+static int parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
 {
     int rc = VINF_SUCCESS;
@@ -1347,4 +744,444 @@
     return rc;
 }
+
+/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
+static unsigned parallelsGetVersion(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        return PARALLELS_DISK_VERSION;
+    else
+        return 0;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetSize */
+static uint64_t parallelsGetSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage && pImage->pStorage)
+        cb = pImage->cbSize;
+
+    LogFlowFunc(("returns %llu\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
+static uint64_t parallelsGetFileSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage && pImage->pStorage)
+        cb = pImage->cbFileCurrent;
+
+    LogFlowFunc(("returns %lld\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
+static int parallelsGetPCHSGeometry(void *pBackendData,
+                                    PVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->PCHSGeometry.cCylinders)
+        {
+            *pPCHSGeometry = pImage->PCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
+static int parallelsSetPCHSGeometry(void *pBackendData,
+                                    PCVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->PCHSGeometry = *pPCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
+static int parallelsGetLCHSGeometry(void *pBackendData,
+                                    PVDGEOMETRY pLCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->LCHSGeometry.cCylinders)
+        {
+            *pLCHSGeometry = pImage->LCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
+static int parallelsSetLCHSGeometry(void *pBackendData,
+                                    PCVDGEOMETRY pLCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->LCHSGeometry = *pLCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
+static unsigned parallelsGetImageFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    unsigned uImageFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uImageFlags = pImage->uImageFlags;
+    else
+        uImageFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uImageFlags));
+    return uImageFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
+static unsigned parallelsGetOpenFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    unsigned uOpenFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uOpenFlags = pImage->uOpenFlags;
+    else
+        uOpenFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uOpenFlags));
+    return uOpenFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
+static int parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
+{
+    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    /* Image must be opened and the new flags must be valid. */
+    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
+                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
+                                   | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
+    /* Implement this operation via reopening the image. */
+    parallelsFreeImage(pImage, false);
+    rc = parallelsOpenImage(pImage, uOpenFlags);
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetComment */
+static int parallelsGetComment(void *pBackendData, char *pszComment,
+                               size_t cbComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetComment */
+static int parallelsSetComment(void *pBackendData, const char *pszComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else
+            rc = VERR_NOT_SUPPORTED;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
+static int parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
+static int parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
+static int parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
+static int parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
+static int parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
+static int parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
+static int parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
+static int parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnDump */
+static void parallelsDump(void *pBackendData)
+{
+    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
+                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
+                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
+    }
+}
+
 
 
@@ -1379,4 +1216,6 @@
     /* pfnFlush */
     parallelsFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     parallelsGetVersion,
@@ -1431,10 +1270,4 @@
     /* pfnSetParentFilename */
     NULL,
-    /* pfnAsyncRead */
-    parallelsAsyncRead,
-    /* pfnAsyncWrite */
-    parallelsAsyncWrite,
-    /* pfnAsyncFlush */
-    parallelsAsyncFlush,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -1445,8 +1278,4 @@
     /* pfnResize */
     NULL,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
Index: trunk/src/VBox/Storage/QCOW.cpp
===================================================================
--- trunk/src/VBox/Storage/QCOW.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/QCOW.cpp	(revision 44252)
@@ -684,62 +684,10 @@
  * @returns VBox status code.
  * @param   pImage    Image instance data.
- * @param   offL2Tbl  The offset of the L2 table in the image.
- * @param   ppL2Entry Where to store the L2 table on success.
- */
-static int qcowL2TblCacheFetch(PQCOWIMAGE pImage, uint64_t offL2Tbl, PQCOWL2CACHEENTRY *ppL2Entry)
-{
-    int rc = VINF_SUCCESS;
-
-    LogFlowFunc(("pImage=%#p offL2Tbl=%llu ppL2Entry=%#p\n", pImage, offL2Tbl, ppL2Entry));
-
-    /* Try to fetch the L2 table from the cache first. */
-    PQCOWL2CACHEENTRY pL2Entry = qcowL2TblCacheRetain(pImage, offL2Tbl);
-    if (!pL2Entry)
-    {
-        LogFlowFunc(("Reading L2 table from image\n"));
-        pL2Entry = qcowL2TblCacheEntryAlloc(pImage);
-
-        if (pL2Entry)
-        {
-            /* Read from the image. */
-            pL2Entry->offL2Tbl = offL2Tbl;
-            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offL2Tbl,
-                                       pL2Entry->paL2Tbl, pImage->cbL2Table);
-            if (RT_SUCCESS(rc))
-            {
-#if defined(RT_LITTLE_ENDIAN)
-                qcowTableConvertToHostEndianess(pL2Entry->paL2Tbl, pImage->cL2TableEntries);
-#endif
-                qcowL2TblCacheEntryInsert(pImage, pL2Entry);
-            }
-            else
-            {
-                qcowL2TblCacheEntryRelease(pL2Entry);
-                qcowL2TblCacheEntryFree(pImage, pL2Entry);
-            }
-        }
-        else
-            rc = VERR_NO_MEMORY;
-    }
-
-    if (RT_SUCCESS(rc))
-        *ppL2Entry = pL2Entry;
-
-    LogFlowFunc(("returns rc=%Rrc\n", rc));
-    return rc;
-}
-
-/**
- * Fetches the L2 from the given offset trying the LRU cache first and
- * reading it from the image after a cache miss - version for async I/O.
- *
- * @returns VBox status code.
- * @param   pImage    Image instance data.
  * @param   pIoCtx    The I/O context.
  * @param   offL2Tbl  The offset of the L2 table in the image.
  * @param   ppL2Entry Where to store the L2 table on success.
  */
-static int qcowL2TblCacheFetchAsync(PQCOWIMAGE pImage, PVDIOCTX pIoCtx,
-                                    uint64_t offL2Tbl, PQCOWL2CACHEENTRY *ppL2Entry)
+static int qcowL2TblCacheFetch(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, uint64_t offL2Tbl,
+                               PQCOWL2CACHEENTRY *ppL2Entry)
 {
     int rc = VINF_SUCCESS;
@@ -876,68 +824,4 @@
  *          VERR_VD_BLOCK_FREE if the cluster is not yet allocated.
  * @param   pImage        The image instance data.
- * @param   idxL1         The L1 index.
- * @param   idxL2         The L2 index.
- * @param   offCluster    Offset inside the cluster.
- * @param   poffImage     Where to store the image offset on success;
- */
-static int qcowConvertToImageOffset(PQCOWIMAGE pImage, uint32_t idxL1, uint32_t idxL2,
-                                    uint32_t offCluster, uint64_t *poffImage)
-{
-    int rc = VERR_VD_BLOCK_FREE;
-    LogFlowFunc(("pImage=%#p idxL1=%u idxL2=%u offCluster=%u poffImage=%#p\n",
-                 pImage, idxL1, idxL2, offCluster, poffImage));
-
-    AssertReturn(idxL1 < pImage->cL1TableEntries, VERR_INVALID_PARAMETER);
-    AssertReturn(idxL2 < pImage->cL2TableEntries, VERR_INVALID_PARAMETER);
-
-    if (pImage->paL1Table[idxL1])
-    {
-        PQCOWL2CACHEENTRY pL2Entry;
-
-        rc = qcowL2TblCacheFetch(pImage, pImage->paL1Table[idxL1], &pL2Entry);
-        if (RT_SUCCESS(rc))
-        {
-            LogFlowFunc(("cluster start offset %llu\n", pL2Entry->paL2Tbl[idxL2]));
-            /* Get real file offset. */
-            if (pL2Entry->paL2Tbl[idxL2])
-            {
-                uint64_t off = pL2Entry->paL2Tbl[idxL2];
-
-                /* Strip flags */
-                if (pImage->uVersion == 2)
-                {
-                    if (RT_UNLIKELY(off & QCOW_V2_COMPRESSED_FLAG))
-                        rc = VERR_NOT_SUPPORTED;
-                    else
-                        off &= ~(QCOW_V2_COMPRESSED_FLAG | QCOW_V2_COPIED_FLAG);
-                }
-                else
-                {
-                    if (RT_UNLIKELY(off & QCOW_V1_COMPRESSED_FLAG))
-                        rc = VERR_NOT_SUPPORTED;
-                    else
-                        off &= ~QCOW_V1_COMPRESSED_FLAG;
-                }
-
-                *poffImage = off + offCluster;
-            }
-            else
-                rc = VERR_VD_BLOCK_FREE;
-
-            qcowL2TblCacheEntryRelease(pL2Entry);
-        }
-    }
-
-    LogFlowFunc(("returns rc=%Rrc\n", rc));
-    return rc;
-}
-
-/**
- * Returns the real image offset for a given cluster or an error if the cluster is not
- * yet allocated- version for async I/O.
- *
- * @returns VBox status code.
- *          VERR_VD_BLOCK_FREE if the cluster is not yet allocated.
- * @param   pImage        The image instance data.
  * @param   pIoCtx        The I/O context.
  * @param   idxL1         The L1 index.
@@ -946,7 +830,7 @@
  * @param   poffImage     Where to store the image offset on success;
  */
-static int qcowConvertToImageOffsetAsync(PQCOWIMAGE pImage, PVDIOCTX pIoCtx,
-                                         uint32_t idxL1, uint32_t idxL2,
-                                         uint32_t offCluster, uint64_t *poffImage)
+static int qcowConvertToImageOffset(PQCOWIMAGE pImage, PVDIOCTX pIoCtx,
+                                    uint32_t idxL1, uint32_t idxL2,
+                                    uint32_t offCluster, uint64_t *poffImage)
 {
     int rc = VERR_VD_BLOCK_FREE;
@@ -959,6 +843,5 @@
         PQCOWL2CACHEENTRY pL2Entry;
 
-        rc = qcowL2TblCacheFetchAsync(pImage, pIoCtx, pImage->paL1Table[idxL1],
-                                     &pL2Entry);
+        rc = qcowL2TblCacheFetch(pImage, pIoCtx, pImage->paL1Table[idxL1], &pL2Entry);
         if (RT_SUCCESS(rc))
         {
@@ -1787,10 +1670,9 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnRead */
-static int qcowRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                   size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
+static int qcowRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
+                    PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
     uint32_t offCluster = 0;
@@ -1804,4 +1686,10 @@
     Assert(cbToRead % 512 == 0);
 
+    if (!VALID_PTR(pIoCtx) || !cbToRead)
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
     if (   uOffset + cbToRead > pImage->cbSize
         || cbToRead == 0)
@@ -1812,5 +1700,4 @@
 
     qcowConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
-    LogFlowFunc(("idxL1=%u idxL2=%u offCluster=%u\n", idxL1, idxL2, offCluster));
 
     /* Clip read size to remain in the cluster. */
@@ -1818,727 +1705,5 @@
 
     /* Get offset in image. */
-    rc = qcowConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offFile);
-    if (RT_SUCCESS(rc))
-    {
-        LogFlowFunc(("offFile=%llu\n", offFile));
-        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offFile,
-                                   pvBuf, cbToRead);
-    }
-
-    if (   (RT_SUCCESS(rc) || rc == VERR_VD_BLOCK_FREE)
-        && pcbActuallyRead)
-        *pcbActuallyRead = cbToRead;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int qcowWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                    size_t cbToWrite, size_t *pcbWriteProcess,
-                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    uint32_t offCluster = 0;
-    uint32_t idxL1      = 0;
-    uint32_t idxL2      = 0;
-    uint64_t offImage   = 0;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToWrite % 512 == 0);
-
-    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-    {
-        rc = VERR_VD_IMAGE_READ_ONLY;
-        goto out;
-    }
-
-    if (   uOffset + cbToWrite > pImage->cbSize
-        || cbToWrite == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Convert offset to L1, L2 index and cluster offset. */
-    qcowConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
-
-    /* Clip write size to remain in the cluster. */
-    cbToWrite = RT_MIN(cbToWrite, pImage->cbCluster - offCluster);
-    Assert(!(cbToWrite % 512));
-
-    /* Get offset in image. */
-    rc = qcowConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offImage);
-    if (RT_SUCCESS(rc))
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, offImage,
-                                    pvBuf, cbToWrite);
-    else if (rc == VERR_VD_BLOCK_FREE)
-    {
-        if (   cbToWrite == pImage->cbCluster
-            && !(fWrite & VD_WRITE_NO_ALLOC))
-        {
-            PQCOWL2CACHEENTRY pL2Entry = NULL;
-
-            /* Full cluster write to previously unallocated cluster.
-             * Allocate cluster and write data. */
-            Assert(!offCluster);
-
-            do
-            {
-                uint64_t idxUpdateLe = 0;
-
-                /* Check if we have to allocate a new cluster for L2 tables. */
-                if (!pImage->paL1Table[idxL1])
-                {
-                    uint64_t offL2Tbl = qcowClusterAllocate(pImage, qcowByte2Cluster(pImage, pImage->cbL2Table));
-
-                    pL2Entry = qcowL2TblCacheEntryAlloc(pImage);
-                    if (!pL2Entry)
-                    {
-                        rc = VERR_NO_MEMORY;
-                        break;
-                    }
-
-                    pL2Entry->offL2Tbl = offL2Tbl;
-                    memset(pL2Entry->paL2Tbl, 0, pImage->cbL2Table);
-                    qcowL2TblCacheEntryInsert(pImage, pL2Entry);
-
-                    /*
-                     * Write the L2 table first and link to the L1 table afterwards.
-                     * If something unexpected happens the worst case which can happen
-                     * is a leak of some clusters.
-                     */
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, offL2Tbl,
-                                                pL2Entry->paL2Tbl, pImage->cbL2Table);
-                    if (RT_FAILURE(rc))
-                        break;
-
-                    /* Write the L1 link now. */
-                    pImage->paL1Table[idxL1] = offL2Tbl;
-                    idxUpdateLe = RT_H2BE_U64(offL2Tbl);
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                pImage->offL1Table + idxL1*sizeof(uint64_t),
-                                                &idxUpdateLe, sizeof(uint64_t));
-                    if (RT_FAILURE(rc))
-                        break;
-                }
-                else
-                    rc = qcowL2TblCacheFetch(pImage, pImage->paL1Table[idxL1], &pL2Entry);
-
-                if (RT_SUCCESS(rc))
-                {
-                    /* Allocate new cluster for the data. */
-                    uint64_t offData = qcowClusterAllocate(pImage, 1);
-
-                    /* Write data. */
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                offData, pvBuf, cbToWrite);
-                    if (RT_FAILURE(rc))
-                        break;
-
-                    /* Link L2 table and update it. */
-                    pL2Entry->paL2Tbl[idxL2] = offData;
-                    idxUpdateLe = RT_H2BE_U64(offData);
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                pImage->paL1Table[idxL1] + idxL2*sizeof(uint64_t),
-                                                &idxUpdateLe, sizeof(uint64_t));
-                    qcowL2TblCacheEntryRelease(pL2Entry);
-                }
-
-            } while (0);
-
-            *pcbPreRead = 0;
-            *pcbPostRead = 0;
-        }
-        else
-        {
-            /* Trying to do a partial write to an unallocated cluster. Don't do
-             * anything except letting the upper layer know what to do. */
-            *pcbPreRead = offCluster;
-            *pcbPostRead = pImage->cbCluster - cbToWrite - *pcbPreRead;
-        }
-    }
-
-    if (pcbWriteProcess)
-        *pcbWriteProcess = cbToWrite;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int qcowFlush(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    rc = qcowFlushImage(pImage);
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
-static unsigned qcowGetVersion(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        return pImage->uVersion;
-    else
-        return 0;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetSize */
-static uint64_t qcowGetSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage && pImage->pStorage)
-        cb = pImage->cbSize;
-
-    LogFlowFunc(("returns %llu\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
-static uint64_t qcowGetFileSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        uint64_t cbFile;
-        if (pImage->pStorage)
-        {
-            int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
-            if (RT_SUCCESS(rc))
-                cb += cbFile;
-        }
-    }
-
-    LogFlowFunc(("returns %lld\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
-static int qcowGetPCHSGeometry(void *pBackendData,
-                              PVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->PCHSGeometry.cCylinders)
-        {
-            *pPCHSGeometry = pImage->PCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
-static int qcowSetPCHSGeometry(void *pBackendData,
-                              PCVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->PCHSGeometry = *pPCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
-static int qcowGetLCHSGeometry(void *pBackendData,
-                              PVDGEOMETRY pLCHSGeometry)
-{
-     LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->LCHSGeometry.cCylinders)
-        {
-            *pLCHSGeometry = pImage->LCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
-static int qcowSetLCHSGeometry(void *pBackendData,
-                               PCVDGEOMETRY pLCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->LCHSGeometry = *pLCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
-static unsigned qcowGetImageFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    unsigned uImageFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uImageFlags = pImage->uImageFlags;
-    else
-        uImageFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uImageFlags));
-    return uImageFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
-static unsigned qcowGetOpenFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    unsigned uOpenFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uOpenFlags = pImage->uOpenFlags;
-    else
-        uOpenFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uOpenFlags));
-    return uOpenFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
-static int qcowSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
-{
-    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    /* Image must be opened and the new flags must be valid. */
-    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
-                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Implement this operation via reopening the image. */
-    rc = qcowFreeImage(pImage, false);
-    if (RT_FAILURE(rc))
-        goto out;
-    rc = qcowOpenImage(pImage, uOpenFlags);
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetComment */
-static int qcowGetComment(void *pBackendData, char *pszComment,
-                          size_t cbComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetComment */
-static int qcowSetComment(void *pBackendData, const char *pszComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else
-            rc = VERR_NOT_SUPPORTED;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
-static int qcowGetUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
-static int qcowSetUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    LogFlowFunc(("%RTuuid\n", pUuid));
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
-static int qcowGetModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
-static int qcowSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
-static int qcowGetParentUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
-static int qcowSetParentUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
-static int qcowGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
-static int qcowSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnDump */
-static void qcowDump(void *pBackendData)
-{
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cSector=%llu\n",
-                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
-                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
-                         pImage->cbSize / 512);
-    }
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentFilename */
-static int qcowGetParentFilename(void *pBackendData, char **ppszParentFilename)
-{
-    int rc = VINF_SUCCESS;
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-        if (pImage->pszFilename)
-            *ppszParentFilename = RTStrDup(pImage->pszBackingFilename);
-        else
-            rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentFilename */
-static int qcowSetParentFilename(void *pBackendData, const char *pszParentFilename)
-{
-    int rc = VINF_SUCCESS;
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else if (   pImage->pszBackingFilename
-                 && (strlen(pszParentFilename) > pImage->cbBackingFilename))
-            rc = VERR_NOT_SUPPORTED; /* The new filename is longer than the old one. */
-        else
-        {
-            if (pImage->pszBackingFilename)
-                RTStrFree(pImage->pszBackingFilename);
-            pImage->pszBackingFilename = RTStrDup(pszParentFilename);
-            if (!pImage->pszBackingFilename)
-                rc = VERR_NO_MEMORY;
-            else
-            {
-                if (!pImage->offBackingFilename)
-                {
-                    /* Allocate new cluster. */
-                    uint64_t offData = qcowClusterAllocate(pImage, 1);
-
-                    Assert((offData & UINT32_MAX) == offData);
-                    pImage->offBackingFilename = (uint32_t)offData;
-                    pImage->cbBackingFilename  = strlen(pszParentFilename);
-                    rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage,
-                                              offData + pImage->cbCluster);
-                }
-
-                if (RT_SUCCESS(rc))
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                pImage->offBackingFilename,
-                                                pImage->pszBackingFilename,
-                                                strlen(pImage->pszBackingFilename));
-            }
-        }
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-static int qcowAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
-                        PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
-    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
-    uint32_t offCluster = 0;
-    uint32_t idxL1      = 0;
-    uint32_t idxL2      = 0;
-    uint64_t offFile    = 0;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToRead % 512 == 0);
-
-    if (!VALID_PTR(pIoCtx) || !cbToRead)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    if (   uOffset + cbToRead > pImage->cbSize
-        || cbToRead == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    qcowConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
-
-    /* Clip read size to remain in the cluster. */
-    cbToRead = RT_MIN(cbToRead, pImage->cbCluster - offCluster);
-
-    /* Get offset in image. */
-    rc = qcowConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster,
-                                       &offFile);
+    rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offFile);
     if (RT_SUCCESS(rc))
         rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, offFile,
@@ -2556,8 +1721,7 @@
 }
 
-static int qcowAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
-                         PVDIOCTX pIoCtx,
-                         size_t *pcbWriteProcess, size_t *pcbPreRead,
-                         size_t *pcbPostRead, unsigned fWrite)
+static int qcowWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
+                     PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                     size_t *pcbPostRead, unsigned fWrite)
 {
     LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
@@ -2601,6 +1765,5 @@
 
     /* Get offset in image. */
-    rc = qcowConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster,
-                                      &offImage);
+    rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offImage);
     if (RT_SUCCESS(rc))
         rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
@@ -2676,7 +1839,6 @@
                 else
                 {
-                    rc = qcowL2TblCacheFetchAsync(pImage, pIoCtx, pImage->paL1Table[idxL1],
-                                                 &pL2Entry);
-
+                    rc = qcowL2TblCacheFetch(pImage, pIoCtx, pImage->paL1Table[idxL1],
+                                             &pL2Entry);
                     if (RT_SUCCESS(rc))
                     {
@@ -2741,5 +1903,5 @@
 }
 
-static int qcowAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
+static int qcowFlush(void *pBackendData, PVDIOCTX pIoCtx)
 {
     LogFlowFunc(("pBackendData=%#p\n", pBackendData));
@@ -2757,4 +1919,525 @@
     return rc;
 }
+
+/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
+static unsigned qcowGetVersion(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        return pImage->uVersion;
+    else
+        return 0;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetSize */
+static uint64_t qcowGetSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage && pImage->pStorage)
+        cb = pImage->cbSize;
+
+    LogFlowFunc(("returns %llu\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
+static uint64_t qcowGetFileSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        uint64_t cbFile;
+        if (pImage->pStorage)
+        {
+            int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
+            if (RT_SUCCESS(rc))
+                cb += cbFile;
+        }
+    }
+
+    LogFlowFunc(("returns %lld\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
+static int qcowGetPCHSGeometry(void *pBackendData,
+                              PVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->PCHSGeometry.cCylinders)
+        {
+            *pPCHSGeometry = pImage->PCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
+static int qcowSetPCHSGeometry(void *pBackendData,
+                              PCVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->PCHSGeometry = *pPCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
+static int qcowGetLCHSGeometry(void *pBackendData,
+                              PVDGEOMETRY pLCHSGeometry)
+{
+     LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->LCHSGeometry.cCylinders)
+        {
+            *pLCHSGeometry = pImage->LCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
+static int qcowSetLCHSGeometry(void *pBackendData,
+                               PCVDGEOMETRY pLCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->LCHSGeometry = *pLCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
+static unsigned qcowGetImageFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    unsigned uImageFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uImageFlags = pImage->uImageFlags;
+    else
+        uImageFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uImageFlags));
+    return uImageFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
+static unsigned qcowGetOpenFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    unsigned uOpenFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uOpenFlags = pImage->uOpenFlags;
+    else
+        uOpenFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uOpenFlags));
+    return uOpenFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
+static int qcowSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
+{
+    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    /* Image must be opened and the new flags must be valid. */
+    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
+                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
+    /* Implement this operation via reopening the image. */
+    rc = qcowFreeImage(pImage, false);
+    if (RT_FAILURE(rc))
+        goto out;
+    rc = qcowOpenImage(pImage, uOpenFlags);
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetComment */
+static int qcowGetComment(void *pBackendData, char *pszComment,
+                          size_t cbComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetComment */
+static int qcowSetComment(void *pBackendData, const char *pszComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else
+            rc = VERR_NOT_SUPPORTED;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
+static int qcowGetUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
+static int qcowSetUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    LogFlowFunc(("%RTuuid\n", pUuid));
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
+static int qcowGetModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
+static int qcowSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
+static int qcowGetParentUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
+static int qcowSetParentUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
+static int qcowGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
+static int qcowSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnDump */
+static void qcowDump(void *pBackendData)
+{
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cSector=%llu\n",
+                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
+                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
+                         pImage->cbSize / 512);
+    }
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentFilename */
+static int qcowGetParentFilename(void *pBackendData, char **ppszParentFilename)
+{
+    int rc = VINF_SUCCESS;
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+        if (pImage->pszFilename)
+            *ppszParentFilename = RTStrDup(pImage->pszBackingFilename);
+        else
+            rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentFilename */
+static int qcowSetParentFilename(void *pBackendData, const char *pszParentFilename)
+{
+    int rc = VINF_SUCCESS;
+    PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else if (   pImage->pszBackingFilename
+                 && (strlen(pszParentFilename) > pImage->cbBackingFilename))
+            rc = VERR_NOT_SUPPORTED; /* The new filename is longer than the old one. */
+        else
+        {
+            if (pImage->pszBackingFilename)
+                RTStrFree(pImage->pszBackingFilename);
+            pImage->pszBackingFilename = RTStrDup(pszParentFilename);
+            if (!pImage->pszBackingFilename)
+                rc = VERR_NO_MEMORY;
+            else
+            {
+                if (!pImage->offBackingFilename)
+                {
+                    /* Allocate new cluster. */
+                    uint64_t offData = qcowClusterAllocate(pImage, 1);
+
+                    Assert((offData & UINT32_MAX) == offData);
+                    pImage->offBackingFilename = (uint32_t)offData;
+                    pImage->cbBackingFilename  = strlen(pszParentFilename);
+                    rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage,
+                                              offData + pImage->cbCluster);
+                }
+
+                if (RT_SUCCESS(rc))
+                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
+                                                pImage->offBackingFilename,
+                                                pImage->pszBackingFilename,
+                                                strlen(pImage->pszBackingFilename));
+            }
+        }
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+
 
 VBOXHDDBACKEND g_QCowBackend =
@@ -2788,4 +2471,6 @@
     /* pfnFlush */
     qcowFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     qcowGetVersion,
@@ -2840,10 +2525,4 @@
     /* pfnSetParentFilename */
     qcowSetParentFilename,
-    /* pfnAsyncRead */
-    qcowAsyncRead,
-    /* pfnAsyncWrite */
-    qcowAsyncWrite,
-    /* pfnAsyncFlush */
-    qcowAsyncFlush,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -2854,8 +2533,4 @@
     /* pfnResize */
     NULL,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
Index: trunk/src/VBox/Storage/QED.cpp
===================================================================
--- trunk/src/VBox/Storage/QED.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/QED.cpp	(revision 44252)
@@ -772,48 +772,4 @@
  *          VERR_VD_BLOCK_FREE if the cluster is not yet allocated.
  * @param   pImage        The image instance data.
- * @param   idxL1         The L1 index.
- * @param   idxL2         The L2 index.
- * @param   offCluster    Offset inside the cluster.
- * @param   poffImage     Where to store the image offset on success;
- */
-static int qedConvertToImageOffset(PQEDIMAGE pImage, uint32_t idxL1, uint32_t idxL2,
-                                   uint32_t offCluster, uint64_t *poffImage)
-{
-    int rc = VERR_VD_BLOCK_FREE;
-    LogFlowFunc(("pImage=%#p idxL1=%u idxL2=%u offCluster=%u poffImage=%#p\n",
-                 pImage, idxL1, idxL2, offCluster, poffImage));
-
-    AssertReturn(idxL1 < pImage->cTableEntries, VERR_INVALID_PARAMETER);
-    AssertReturn(idxL2 < pImage->cTableEntries, VERR_INVALID_PARAMETER);
-
-    if (pImage->paL1Table[idxL1])
-    {
-        PQEDL2CACHEENTRY pL2Entry;
-
-        rc = qedL2TblCacheFetch(pImage, pImage->paL1Table[idxL1], &pL2Entry);
-        if (RT_SUCCESS(rc))
-        {
-            LogFlowFunc(("cluster start offset %llu\n", pL2Entry->paL2Tbl[idxL2]));
-            /* Get real file offset. */
-            if (pL2Entry->paL2Tbl[idxL2])
-                *poffImage = pL2Entry->paL2Tbl[idxL2] + offCluster;
-            else
-                rc = VERR_VD_BLOCK_FREE;
-
-            qedL2TblCacheEntryRelease(pL2Entry);
-        }
-    }
-
-    LogFlowFunc(("returns rc=%Rrc\n", rc));
-    return rc;
-}
-
-/**
- * Returns the real image offset for a given cluster or an error if the cluster is not
- * yet allocated- version for async I/O.
- *
- * @returns VBox status code.
- *          VERR_VD_BLOCK_FREE if the cluster is not yet allocated.
- * @param   pImage        The image instance data.
  * @param   pIoCtx        The I/O context.
  * @param   idxL1         The L1 index.
@@ -822,7 +778,7 @@
  * @param   poffImage     Where to store the image offset on success;
  */
-static int qedConvertToImageOffsetAsync(PQEDIMAGE pImage, PVDIOCTX pIoCtx,
-                                        uint32_t idxL1, uint32_t idxL2,
-                                        uint32_t offCluster, uint64_t *poffImage)
+static int qedConvertToImageOffset(PQEDIMAGE pImage, PVDIOCTX pIoCtx,
+                                   uint32_t idxL1, uint32_t idxL2,
+                                   uint32_t offCluster, uint64_t *poffImage)
 {
     int rc = VERR_VD_BLOCK_FREE;
@@ -1801,10 +1757,9 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnRead */
-static int qedRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                   size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
+static int qedRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
+                   PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
     uint32_t offCluster = 0;
@@ -1818,4 +1773,10 @@
     Assert(cbToRead % 512 == 0);
 
+    if (!VALID_PTR(pIoCtx) || !cbToRead)
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
     if (   uOffset + cbToRead > pImage->cbSize
         || cbToRead == 0)
@@ -1826,5 +1787,4 @@
 
     qedConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
-    LogFlowFunc(("idxL1=%u idxL2=%u offCluster=%u\n", idxL1, idxL2, offCluster));
 
     /* Clip read size to remain in the cluster. */
@@ -1832,727 +1792,5 @@
 
     /* Get offset in image. */
-    rc = qedConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offFile);
-    if (RT_SUCCESS(rc))
-    {
-        LogFlowFunc(("offFile=%llu\n", offFile));
-        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offFile,
-                                   pvBuf, cbToRead);
-    }
-
-    if (   (RT_SUCCESS(rc) || rc == VERR_VD_BLOCK_FREE)
-        && pcbActuallyRead)
-        *pcbActuallyRead = cbToRead;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int qedWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                    size_t cbToWrite, size_t *pcbWriteProcess,
-                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    uint32_t offCluster = 0;
-    uint32_t idxL1      = 0;
-    uint32_t idxL2      = 0;
-    uint64_t offImage   = 0;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToWrite % 512 == 0);
-
-    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-    {
-        rc = VERR_VD_IMAGE_READ_ONLY;
-        goto out;
-    }
-
-    if (   uOffset + cbToWrite > pImage->cbSize
-        || cbToWrite == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Convert offset to L1, L2 index and cluster offset. */
-    qedConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
-
-    /* Clip write size to remain in the cluster. */
-    cbToWrite = RT_MIN(cbToWrite, pImage->cbCluster - offCluster);
-    Assert(!(cbToWrite % 512));
-
-    /* Get offset in image. */
-    rc = qedConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offImage);
-    if (RT_SUCCESS(rc))
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, offImage,
-                                    pvBuf, cbToWrite);
-    else if (rc == VERR_VD_BLOCK_FREE)
-    {
-        if (   cbToWrite == pImage->cbCluster
-            && !(fWrite & VD_WRITE_NO_ALLOC))
-        {
-            PQEDL2CACHEENTRY pL2Entry = NULL;
-
-            /* Full cluster write to previously unallocated cluster.
-             * Allocate cluster and write data. */
-            Assert(!offCluster);
-
-            do
-            {
-                uint64_t idxUpdateLe = 0;
-
-                /* Check if we have to allocate a new cluster for L2 tables. */
-                if (!pImage->paL1Table[idxL1])
-                {
-                    uint64_t offL2Tbl = qedClusterAllocate(pImage, qedByte2Cluster(pImage, pImage->cbTable));
-
-                    pL2Entry = qedL2TblCacheEntryAlloc(pImage);
-                    if (!pL2Entry)
-                    {
-                        rc = VERR_NO_MEMORY;
-                        break;
-                    }
-
-                    pL2Entry->offL2Tbl = offL2Tbl;
-                    memset(pL2Entry->paL2Tbl, 0, pImage->cbTable);
-                    qedL2TblCacheEntryInsert(pImage, pL2Entry);
-
-                    /*
-                     * Write the L2 table first and link to the L1 table afterwards.
-                     * If something unexpected happens the worst case which can happen
-                     * is a leak of some clusters.
-                     */
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, offL2Tbl,
-                                                pL2Entry->paL2Tbl, pImage->cbTable);
-                    if (RT_FAILURE(rc))
-                        break;
-
-                    /* Write the L1 link now. */
-                    pImage->paL1Table[idxL1] = offL2Tbl;
-                    idxUpdateLe = RT_H2LE_U64(offL2Tbl);
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                pImage->offL1Table + idxL1*sizeof(uint64_t),
-                                                &idxUpdateLe, sizeof(uint64_t));
-                    if (RT_FAILURE(rc))
-                        break;
-                }
-                else
-                    rc = qedL2TblCacheFetch(pImage, pImage->paL1Table[idxL1], &pL2Entry);
-
-                if (RT_SUCCESS(rc))
-                {
-                    /* Allocate new cluster for the data. */
-                    uint64_t offData = qedClusterAllocate(pImage, 1);
-
-                    /* Write data. */
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                offData, pvBuf, cbToWrite);
-                    if (RT_FAILURE(rc))
-                        break;
-
-                    /* Link L2 table and update it. */
-                    pL2Entry->paL2Tbl[idxL2] = offData;
-                    idxUpdateLe = RT_H2LE_U64(offData);
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                pImage->paL1Table[idxL1] + idxL2*sizeof(uint64_t),
-                                                &idxUpdateLe, sizeof(uint64_t));
-                    qedL2TblCacheEntryRelease(pL2Entry);
-                }
-
-            } while (0);
-
-            *pcbPreRead = 0;
-            *pcbPostRead = 0;
-        }
-        else
-        {
-            /* Trying to do a partial write to an unallocated cluster. Don't do
-             * anything except letting the upper layer know what to do. */
-            *pcbPreRead = offCluster;
-            *pcbPostRead = pImage->cbCluster - cbToWrite - *pcbPreRead;
-        }
-    }
-
-    if (pcbWriteProcess)
-        *pcbWriteProcess = cbToWrite;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int qedFlush(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    rc = qedFlushImage(pImage);
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
-static unsigned qedGetVersion(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        return 1;
-    else
-        return 0;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetSize */
-static uint64_t qedGetSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage && pImage->pStorage)
-        cb = pImage->cbSize;
-
-    LogFlowFunc(("returns %llu\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
-static uint64_t qedGetFileSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        uint64_t cbFile;
-        if (pImage->pStorage)
-        {
-            int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
-            if (RT_SUCCESS(rc))
-                cb += cbFile;
-        }
-    }
-
-    LogFlowFunc(("returns %lld\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
-static int qedGetPCHSGeometry(void *pBackendData,
-                              PVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->PCHSGeometry.cCylinders)
-        {
-            *pPCHSGeometry = pImage->PCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
-static int qedSetPCHSGeometry(void *pBackendData,
-                              PCVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->PCHSGeometry = *pPCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
-static int qedGetLCHSGeometry(void *pBackendData,
-                              PVDGEOMETRY pLCHSGeometry)
-{
-     LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->LCHSGeometry.cCylinders)
-        {
-            *pLCHSGeometry = pImage->LCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
-static int qedSetLCHSGeometry(void *pBackendData,
-                               PCVDGEOMETRY pLCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->LCHSGeometry = *pLCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
-static unsigned qedGetImageFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    unsigned uImageFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uImageFlags = pImage->uImageFlags;
-    else
-        uImageFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uImageFlags));
-    return uImageFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
-static unsigned qedGetOpenFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    unsigned uOpenFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uOpenFlags = pImage->uOpenFlags;
-    else
-        uOpenFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uOpenFlags));
-    return uOpenFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
-static int qedSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
-{
-    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    /* Image must be opened and the new flags must be valid. */
-    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
-                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Implement this operation via reopening the image. */
-    rc = qedFreeImage(pImage, false);
-    if (RT_FAILURE(rc))
-        goto out;
-    rc = qedOpenImage(pImage, uOpenFlags);
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetComment */
-static int qedGetComment(void *pBackendData, char *pszComment,
-                          size_t cbComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetComment */
-static int qedSetComment(void *pBackendData, const char *pszComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else
-            rc = VERR_NOT_SUPPORTED;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
-static int qedGetUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
-static int qedSetUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    LogFlowFunc(("%RTuuid\n", pUuid));
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
-static int qedGetModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
-static int qedSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
-static int qedGetParentUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
-static int qedSetParentUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
-static int qedGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
-static int qedSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnDump */
-static void qedDump(void *pBackendData)
-{
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
-                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
-                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
-                         pImage->cbSize / 512);
-    }
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentFilename */
-static int qedGetParentFilename(void *pBackendData, char **ppszParentFilename)
-{
-    int rc = VINF_SUCCESS;
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-        if (pImage->pszFilename)
-            *ppszParentFilename = RTStrDup(pImage->pszBackingFilename);
-        else
-            rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentFilename */
-static int qedSetParentFilename(void *pBackendData, const char *pszParentFilename)
-{
-    int rc = VINF_SUCCESS;
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else if (   pImage->pszBackingFilename
-                 && (strlen(pszParentFilename) > pImage->cbBackingFilename))
-            rc = VERR_NOT_SUPPORTED; /* The new filename is longer than the old one. */
-        else
-        {
-            if (pImage->pszBackingFilename)
-                RTStrFree(pImage->pszBackingFilename);
-            pImage->pszBackingFilename = RTStrDup(pszParentFilename);
-            if (!pImage->pszBackingFilename)
-                rc = VERR_NO_MEMORY;
-            else
-            {
-                if (!pImage->offBackingFilename)
-                {
-                    /* Allocate new cluster. */
-                    uint64_t offData = qedClusterAllocate(pImage, 1);
-
-                    Assert((offData & UINT32_MAX) == offData);
-                    pImage->offBackingFilename = (uint32_t)offData;
-                    pImage->cbBackingFilename  = strlen(pszParentFilename);
-                    rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage,
-                                              offData + pImage->cbCluster);
-                }
-
-                if (RT_SUCCESS(rc))
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                pImage->offBackingFilename,
-                                                pImage->pszBackingFilename,
-                                                strlen(pImage->pszBackingFilename));
-            }
-        }
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-static int qedAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
-                        PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
-    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
-    uint32_t offCluster = 0;
-    uint32_t idxL1      = 0;
-    uint32_t idxL2      = 0;
-    uint64_t offFile    = 0;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToRead % 512 == 0);
-
-    if (!VALID_PTR(pIoCtx) || !cbToRead)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    if (   uOffset + cbToRead > pImage->cbSize
-        || cbToRead == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    qedConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
-
-    /* Clip read size to remain in the cluster. */
-    cbToRead = RT_MIN(cbToRead, pImage->cbCluster - offCluster);
-
-    /* Get offset in image. */
-    rc = qedConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster,
-                                      &offFile);
+    rc = qedConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offFile);
     if (RT_SUCCESS(rc))
         rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, offFile,
@@ -2570,8 +1808,7 @@
 }
 
-static int qedAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
-                         PVDIOCTX pIoCtx,
-                         size_t *pcbWriteProcess, size_t *pcbPreRead,
-                         size_t *pcbPostRead, unsigned fWrite)
+static int qedWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
+                    PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                    size_t *pcbPostRead, unsigned fWrite)
 {
     LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
@@ -2615,6 +1852,5 @@
 
     /* Get offset in image. */
-    rc = qedConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster,
-                                      &offImage);
+    rc = qedConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offImage);
     if (RT_SUCCESS(rc))
         rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
@@ -2755,5 +1991,5 @@
 }
 
-static int qedAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
+static int qedFlush(void *pBackendData, PVDIOCTX pIoCtx)
 {
     LogFlowFunc(("pBackendData=%#p\n", pBackendData));
@@ -2767,4 +2003,523 @@
     else
         rc = VERR_INVALID_PARAMETER;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
+static unsigned qedGetVersion(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        return 1;
+    else
+        return 0;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetSize */
+static uint64_t qedGetSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage && pImage->pStorage)
+        cb = pImage->cbSize;
+
+    LogFlowFunc(("returns %llu\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
+static uint64_t qedGetFileSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        uint64_t cbFile;
+        if (pImage->pStorage)
+        {
+            int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
+            if (RT_SUCCESS(rc))
+                cb += cbFile;
+        }
+    }
+
+    LogFlowFunc(("returns %lld\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
+static int qedGetPCHSGeometry(void *pBackendData,
+                              PVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->PCHSGeometry.cCylinders)
+        {
+            *pPCHSGeometry = pImage->PCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
+static int qedSetPCHSGeometry(void *pBackendData,
+                              PCVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->PCHSGeometry = *pPCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
+static int qedGetLCHSGeometry(void *pBackendData,
+                              PVDGEOMETRY pLCHSGeometry)
+{
+     LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->LCHSGeometry.cCylinders)
+        {
+            *pLCHSGeometry = pImage->LCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
+static int qedSetLCHSGeometry(void *pBackendData,
+                               PCVDGEOMETRY pLCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->LCHSGeometry = *pLCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
+static unsigned qedGetImageFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    unsigned uImageFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uImageFlags = pImage->uImageFlags;
+    else
+        uImageFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uImageFlags));
+    return uImageFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
+static unsigned qedGetOpenFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    unsigned uOpenFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uOpenFlags = pImage->uOpenFlags;
+    else
+        uOpenFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uOpenFlags));
+    return uOpenFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
+static int qedSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
+{
+    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    /* Image must be opened and the new flags must be valid. */
+    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
+                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
+    /* Implement this operation via reopening the image. */
+    rc = qedFreeImage(pImage, false);
+    if (RT_FAILURE(rc))
+        goto out;
+    rc = qedOpenImage(pImage, uOpenFlags);
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetComment */
+static int qedGetComment(void *pBackendData, char *pszComment,
+                          size_t cbComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetComment */
+static int qedSetComment(void *pBackendData, const char *pszComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else
+            rc = VERR_NOT_SUPPORTED;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
+static int qedGetUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
+static int qedSetUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    LogFlowFunc(("%RTuuid\n", pUuid));
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
+static int qedGetModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
+static int qedSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
+static int qedGetParentUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
+static int qedSetParentUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
+static int qedGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
+static int qedSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnDump */
+static void qedDump(void *pBackendData)
+{
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
+                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
+                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
+                         pImage->cbSize / 512);
+    }
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentFilename */
+static int qedGetParentFilename(void *pBackendData, char **ppszParentFilename)
+{
+    int rc = VINF_SUCCESS;
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+        if (pImage->pszFilename)
+            *ppszParentFilename = RTStrDup(pImage->pszBackingFilename);
+        else
+            rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentFilename */
+static int qedSetParentFilename(void *pBackendData, const char *pszParentFilename)
+{
+    int rc = VINF_SUCCESS;
+    PQEDIMAGE pImage = (PQEDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else if (   pImage->pszBackingFilename
+                 && (strlen(pszParentFilename) > pImage->cbBackingFilename))
+            rc = VERR_NOT_SUPPORTED; /* The new filename is longer than the old one. */
+        else
+        {
+            if (pImage->pszBackingFilename)
+                RTStrFree(pImage->pszBackingFilename);
+            pImage->pszBackingFilename = RTStrDup(pszParentFilename);
+            if (!pImage->pszBackingFilename)
+                rc = VERR_NO_MEMORY;
+            else
+            {
+                if (!pImage->offBackingFilename)
+                {
+                    /* Allocate new cluster. */
+                    uint64_t offData = qedClusterAllocate(pImage, 1);
+
+                    Assert((offData & UINT32_MAX) == offData);
+                    pImage->offBackingFilename = (uint32_t)offData;
+                    pImage->cbBackingFilename  = strlen(pszParentFilename);
+                    rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage,
+                                              offData + pImage->cbCluster);
+                }
+
+                if (RT_SUCCESS(rc))
+                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
+                                                pImage->offBackingFilename,
+                                                pImage->pszBackingFilename,
+                                                strlen(pImage->pszBackingFilename));
+            }
+        }
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
 
     LogFlowFunc(("returns %Rrc\n", rc));
@@ -2854,4 +2609,6 @@
     /* pfnFlush */
     qedFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     qedGetVersion,
@@ -2906,10 +2663,4 @@
     /* pfnSetParentFilename */
     qedSetParentFilename,
-    /* pfnAsyncRead */
-    qedAsyncRead,
-    /* pfnAsyncWrite */
-    qedAsyncWrite,
-    /* pfnAsyncFlush */
-    qedAsyncFlush,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -2920,8 +2671,4 @@
     /* pfnResize */
     qedResize,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
Index: trunk/src/VBox/Storage/RAW.cpp
===================================================================
--- trunk/src/VBox/Storage/RAW.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/RAW.cpp	(revision 44252)
@@ -602,95 +602,48 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnRead */
-static int rawRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                   size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
-    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToRead % 512 == 0);
-
-    if (   uOffset + cbToRead > pImage->cbSize
-        || cbToRead == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* For sequential access do not allow to go back. */
-    if (   pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
-        && uOffset < pImage->offAccess)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf,
-                               cbToRead);
-    pImage->offAccess = uOffset + cbToRead;
-    if (pcbActuallyRead)
-        *pcbActuallyRead = cbToRead;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
+static int rawRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
+                   PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    int rc = VINF_SUCCESS;
+    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
+
+    rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
+                               pIoCtx, cbRead);
+    if (RT_SUCCESS(rc))
+        *pcbActuallyRead = cbRead;
+
     return rc;
 }
 
 /** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int rawWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                    size_t cbToWrite, size_t *pcbWriteProcess,
-                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
-    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbToWrite % 512 == 0);
-
-    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-    {
-        rc = VERR_VD_IMAGE_READ_ONLY;
-        goto out;
-    }
-
-    if (   uOffset + cbToWrite > pImage->cbSize
-        || cbToWrite == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* For sequential access do not allow to go back. */
-    if (   pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
-        && uOffset < pImage->offAccess)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf,
-                                cbToWrite);
-    pImage->offAccess = uOffset + cbToWrite;
-    if (pcbWriteProcess)
-        *pcbWriteProcess = cbToWrite;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
+static int rawWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
+                    PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                    size_t *pcbPostRead, unsigned fWrite)
+{
+    int rc = VINF_SUCCESS;
+    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
+
+    rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
+                                pIoCtx, cbWrite, NULL, NULL);
+    if (RT_SUCCESS(rc))
+    {
+        *pcbWriteProcess = cbWrite;
+        *pcbPostRead = 0;
+        *pcbPreRead  = 0;
+    }
+
     return rc;
 }
 
 /** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int rawFlush(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
-    int rc;
-
-    rc = rawFlushImage(pImage);
-    LogFlowFunc(("returns %Rrc\n", rc));
+static int rawFlush(void *pBackendData, PVDIOCTX pIoCtx)
+{
+    int rc = VINF_SUCCESS;
+    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
+
+    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+        rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
+                                NULL, NULL);
+
     return rc;
 }
@@ -1147,52 +1100,4 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
-static int rawAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
-                        PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
-{
-    int rc = VINF_SUCCESS;
-    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
-
-    rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
-                               pIoCtx, cbRead);
-    if (RT_SUCCESS(rc))
-        *pcbActuallyRead = cbRead;
-
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
-static int rawAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
-                         PVDIOCTX pIoCtx,
-                         size_t *pcbWriteProcess, size_t *pcbPreRead,
-                         size_t *pcbPostRead, unsigned fWrite)
-{
-    int rc = VINF_SUCCESS;
-    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
-
-    rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
-                                pIoCtx, cbWrite, NULL, NULL);
-    if (RT_SUCCESS(rc))
-    {
-        *pcbWriteProcess = cbWrite;
-        *pcbPostRead = 0;
-        *pcbPreRead  = 0;
-    }
-
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
-static int rawAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
-{
-    int rc = VINF_SUCCESS;
-    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
-
-    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-        rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
-                                NULL, NULL);
-
-    return rc;
-}
 
 
@@ -1227,4 +1132,6 @@
     /* pfnFlush */
     rawFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     rawGetVersion,
@@ -1279,10 +1186,4 @@
     /* pfnSetParentFilename */
     NULL,
-    /* pfnAsyncRead */
-    rawAsyncRead,
-    /* pfnAsyncWrite */
-    rawAsyncWrite,
-    /* pfnAsyncFlush */
-    rawAsyncFlush,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -1293,8 +1194,4 @@
     /* pfnResize */
     NULL,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
Index: trunk/src/VBox/Storage/VD.cpp
===================================================================
--- trunk/src/VBox/Storage/VD.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/VD.cpp	(revision 44252)
@@ -913,5 +913,5 @@
      * If the block is not allocated read from override chain if present.
      */
-    rc = pImage->Backend->pfnAsyncRead(pImage->pBackendData,
+    rc = pImage->Backend->pfnRead(pImage->pBackendData,
                                        uOffset, cbThisRead, &IoCtx,
                                        &cbThisRead);
@@ -923,5 +923,5 @@
              pCurrImage = pCurrImage->pPrev)
         {
-            rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData,
+            rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
                                                    uOffset, cbThisRead, &IoCtx,
                                                    &cbThisRead);
@@ -1013,5 +1013,5 @@
              * If the block is not allocated read from override chain if present.
              */
-            rc = pImage->Backend->pfnAsyncRead(pImage->pBackendData,
+            rc = pImage->Backend->pfnRead(pImage->pBackendData,
                                                uOffset, cbThisRead, &IoCtx,
                                                &cbThisRead);
@@ -1026,5 +1026,5 @@
                      pCurrImage = pCurrImage->pPrev)
                 {
-                    rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData,
+                    rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
                                                            uOffset, cbThisRead,
                                                            &IoCtx, &cbThisRead);
@@ -1161,5 +1161,5 @@
                 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL,
                             NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-                rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData,
+                rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData,
                                                             &IoCtx, offStart, cbThis, NULL,
                                                             NULL, &cbThis, NULL,
@@ -1256,5 +1256,5 @@
             vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL,
                         NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-            rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData,
+            rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData,
                                                         &IoCtx, offStart,
                                                         cbThisDiscard, &cbPreAllocated,
@@ -1313,5 +1313,5 @@
                 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL,
                             NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-                rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData,
+                rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData,
                                                             &IoCtx, pBlock->Core.Key,
                                                             pBlock->cbDiscard, &cbPreAllocated,
@@ -1650,13 +1650,12 @@
 }
 
-static size_t vdIoCtxCopyTo(PVDIOCTX pIoCtx, uint8_t *pbData, size_t cbData)
+static size_t vdIoCtxCopyTo(PVDIOCTX pIoCtx, const uint8_t *pbData, size_t cbData)
+{
+    return RTSgBufCopyFromBuf(&pIoCtx->Req.Io.SgBuf, pbData, cbData);
+}
+
+static size_t vdIoCtxCopyFrom(PVDIOCTX pIoCtx, uint8_t *pbData, size_t cbData)
 {
     return RTSgBufCopyToBuf(&pIoCtx->Req.Io.SgBuf, pbData, cbData);
-}
-
-
-static size_t vdIoCtxCopyFrom(PVDIOCTX pIoCtx, uint8_t *pbData, size_t cbData)
-{
-    return RTSgBufCopyFromBuf(&pIoCtx->Req.Io.SgBuf, pbData, cbData);
 }
 
@@ -2054,5 +2053,5 @@
          * If the block is not allocated read from override chain if present.
          */
-        rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData,
+        rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
                                                uOffset, cbThisRead,
                                                pIoCtx, &cbThisRead);
@@ -2064,5 +2063,5 @@
             {
                 pCurrImage =  pCurrImage->pPrev;
-                rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData,
+                rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
                                                        uOffset, cbThisRead,
                                                        pIoCtx, &cbThisRead);
@@ -2161,5 +2160,5 @@
             vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_FLUSH, 0, 0, NULL,
                         NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-            pDisk->pLast->Backend->pfnAsyncFlush(pDisk->pLast->pBackendData, &IoCtx);
+            pDisk->pLast->Backend->pfnFlush(pDisk->pLast->pBackendData, &IoCtx);
         }
     }
@@ -2249,5 +2248,5 @@
     vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_WRITE, 0, 0, NULL,
                 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-    rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, uOffset - cbPreRead,
+    rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffset - cbPreRead,
                                         cbPreRead + cbThisWrite + cbPostRead,
                                         &IoCtx, NULL, &cbPreRead, &cbPostRead, 0);
@@ -2339,5 +2338,5 @@
     vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_WRITE, 0, 0, NULL,
                 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-    rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, uOffset - cbPreRead,
+    rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffset - cbPreRead,
                                         cbPreRead + cbThisWrite + cbPostRead,
                                         &IoCtx, NULL, &cbPreRead, &cbPostRead, 0);
@@ -2387,5 +2386,5 @@
         vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_WRITE, 0, 0, NULL,
                     &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-        rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, uOffsetCur, cbThisWrite,
+        rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffsetCur, cbThisWrite,
                                             &IoCtx, &cbThisWrite, &cbPreRead,
                                             &cbPostRead, fWrite);
@@ -2501,5 +2500,5 @@
 
             /* Read the source data. */
-            rc = pImageFrom->Backend->pfnAsyncRead(pImageFrom->pBackendData,
+            rc = pImageFrom->Backend->pfnRead(pImageFrom->pBackendData,
                                                    uOffset, cbThisRead, &IoCtx,
                                                    &cbThisRead);
@@ -2514,5 +2513,5 @@
                      pCurrImage = pCurrImage->pPrev)
                 {
-                    rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData,
+                    rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
                                                            uOffset, cbThisRead,
                                                            &IoCtx, &cbThisRead);
@@ -2607,5 +2606,5 @@
     PVDIMAGE pImage = pIoCtx->Req.Io.pImageCur;
 
-    rc = pImage->Backend->pfnAsyncFlush(pImage->pBackendData, pIoCtx);
+    rc = pImage->Backend->pfnFlush(pImage->pBackendData, pIoCtx);
     if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
         rc = VINF_SUCCESS;
@@ -2736,5 +2735,5 @@
         /* Write the full block to the virtual disk. */
         vdIoCtxChildReset(pIoCtxDst);
-        rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData,
+        rc = pImage->Backend->pfnWrite(pImage->pBackendData,
                                             uOffset - cbPreRead,
                                             cbPreRead + cbThisWrite + cbPostRead,
@@ -2767,5 +2766,5 @@
 
     LogFlowFunc(("pIoCtx=%#p\n", pIoCtx));
-    rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData,
+    rc = pImage->Backend->pfnWrite(pImage->pBackendData,
                                         pIoCtx->Req.Io.uOffset - cbPreRead,
                                         cbPreRead + cbThisWrite + cbPostRead,
@@ -2973,5 +2972,5 @@
         fWrite =   (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME)
                  ? 0 : VD_WRITE_NO_ALLOC;
-        rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, uOffset,
+        rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffset,
                                             cbThisWrite, pIoCtx,
                                             &cbThisWrite, &cbPreRead,
@@ -3100,5 +3099,5 @@
     {
         vdResetModifiedFlag(pDisk);
-        rc = pImage->Backend->pfnAsyncFlush(pImage->pBackendData, pIoCtx);
+        rc = pImage->Backend->pfnFlush(pImage->pBackendData, pIoCtx);
         if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
             rc = VINF_SUCCESS;
@@ -3129,5 +3128,5 @@
     AssertPtr(pBlock);
 
-    rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, pIoCtx,
+    rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData, pIoCtx,
                                                 pBlock->Core.Key, pBlock->cbDiscard,
                                                 &cbPreAllocated, &cbPostAllocated,
@@ -3211,5 +3210,5 @@
                     cbThis = (idxEnd - idxStart) * 512;
 
-                rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, pIoCtx,
+                rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData, pIoCtx,
                                                             offStart, cbThis, NULL, NULL, &cbThis,
                                                             NULL, VD_DISCARD_MARK_UNUSED);
@@ -3268,5 +3267,5 @@
 
     /* No block found, try to discard using the backend first. */
-    rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, pIoCtx,
+    rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData, pIoCtx,
                                                 offStart, cbThisDiscard, &cbPreAllocated,
                                                 &cbPostAllocated, &cbThisDiscard,
@@ -4750,5 +4749,5 @@
 
 static size_t vdIOIntIoCtxCopyTo(void *pvUser, PVDIOCTX pIoCtx,
-                                 void *pvBuf, size_t cbBuf)
+                                 const void *pvBuf, size_t cbBuf)
 {
     PVDIO    pVDIo = (PVDIO)pvUser;
@@ -6958,5 +6957,5 @@
                 fLockWrite = true;
 
-                rc = pImageTo->Backend->pfnAsyncRead(pImageTo->pBackendData,
+                rc = pImageTo->Backend->pfnRead(pImageTo->pBackendData,
                                                      uOffset, cbThisRead,
                                                      &IoCtx, &cbThisRead);
@@ -6971,5 +6970,5 @@
                          pCurrImage = pCurrImage->pPrev)
                     {
-                        rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData,
+                        rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
                                                                uOffset, cbThisRead,
                                                                &IoCtx, &cbThisRead);
@@ -7097,5 +7096,5 @@
                      pCurrImage = pCurrImage->pPrev)
                 {
-                    rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData,
+                    rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
                                                            uOffset, cbThisRead,
                                                            &IoCtx, &cbThisRead);
@@ -8298,5 +8297,5 @@
         vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_FLUSH, 0, 0, NULL,
                     NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC);
-        rc = pImage->Backend->pfnAsyncFlush(pImage->pBackendData, &IoCtx);
+        rc = pImage->Backend->pfnFlush(pImage->pBackendData, &IoCtx);
 
 #if 0 /** @todo: Change cache implementation. */
Index: trunk/src/VBox/Storage/VDI.cpp
===================================================================
--- trunk/src/VBox/Storage/VDI.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/VDI.cpp	(revision 44252)
@@ -1062,5 +1062,5 @@
  * Internal: Flush the image file to disk - async version.
  */
-static int vdiFlushImageAsync(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx)
+static int vdiFlushImageIoCtx(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx)
 {
     int rc = VINF_SUCCESS;
@@ -1078,79 +1078,4 @@
     }
 
-    return rc;
-}
-
-/**
- * Internal: Discard a whole block from the image filling the created hole with
- * data from another block.
- *
- * @returns VBox status code.
- * @param   pImage    VDI image instance data.
- * @param   uBlock    The block to discard.
- * @param   pvBlock   Memory to use for the I/O.
- */
-static int vdiDiscardBlock(PVDIIMAGEDESC pImage, unsigned uBlock, void *pvBlock)
-{
-    int rc = VINF_SUCCESS;
-    uint64_t cbImage;
-    unsigned idxLastBlock = getImageBlocksAllocated(&pImage->Header) - 1;
-    unsigned uBlockLast = pImage->paBlocksRev[idxLastBlock];
-    VDIIMAGEBLOCKPOINTER ptrBlockDiscard = pImage->paBlocks[uBlock];
-
-    LogFlowFunc(("pImage=%#p uBlock=%u pvBlock=%#p\n",
-                 pImage, uBlock, pvBlock));
-
-    pImage->paBlocksRev[idxLastBlock] = VDI_IMAGE_BLOCK_FREE;
-
-    do
-    {
-        /*
-         * The block is empty, remove it.
-         * Read the last block of the image first.
-         */
-        if (idxLastBlock != ptrBlockDiscard)
-        {
-            uint64_t u64Offset;
-
-            LogFlowFunc(("Moving block [%u]=%u into [%u]=%u\n",
-                         uBlockLast, idxLastBlock, uBlock, pImage->paBlocks[uBlock]));
-
-            u64Offset = (uint64_t)idxLastBlock * pImage->cbTotalBlockData + pImage->offStartData;
-            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, u64Offset,
-                                       pvBlock, pImage->cbTotalBlockData);
-            if (RT_FAILURE(rc))
-                break;
-
-            /* Write to the now unallocated block. */
-            u64Offset = (uint64_t)ptrBlockDiscard * pImage->cbTotalBlockData + pImage->offStartData;
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, u64Offset,
-                                        pvBlock, pImage->cbTotalBlockData);
-            if (RT_FAILURE(rc))
-                break;
-
-            /* Update block and reverse block tables. */
-            pImage->paBlocks[uBlockLast] = ptrBlockDiscard;
-            pImage->paBlocksRev[ptrBlockDiscard] = uBlockLast;
-            rc = vdiUpdateBlockInfo(pImage, uBlockLast);
-            if (RT_FAILURE(rc))
-                break;
-        }
-        else
-            LogFlowFunc(("Discard last block [%u]=%u\n", uBlock, pImage->paBlocks[uBlock]));
-
-        pImage->paBlocks[uBlock] = VDI_IMAGE_BLOCK_ZERO;
-
-        /* Update the block pointers. */
-        setImageBlocksAllocated(&pImage->Header, idxLastBlock);
-        rc = vdiUpdateBlockInfo(pImage, uBlock);
-        if (RT_FAILURE(rc))
-            break;
-
-        pImage->cbImage -= pImage->cbTotalBlockData;
-        LogFlowFunc(("Set new size %llu\n", pImage->cbImage));
-        rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbImage);
-    } while (0);
-
-    LogFlowFunc(("returns rc=%Rrc\n", rc));
     return rc;
 }
@@ -1353,5 +1278,5 @@
  * @param   rcReq           Status code for the completed request.
  */
-static DECLCALLBACK(int) vdiAsyncBlockAllocUpdate(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
+static DECLCALLBACK(int) vdiBlockAllocUpdate(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
 {
     int rc = VINF_SUCCESS;
@@ -1621,9 +1546,9 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnRead */
-static int vdiRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                   size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
+static int vdiRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
+                   PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
     unsigned uBlock;
@@ -1636,5 +1561,5 @@
 
     if (   uOffset + cbToRead > getImageDiskSize(&pImage->Header)
-        || !VALID_PTR(pvBuf)
+        || !VALID_PTR(pIoCtx)
         || !cbToRead)
     {
@@ -1655,5 +1580,9 @@
     else if (pImage->paBlocks[uBlock] == VDI_IMAGE_BLOCK_ZERO)
     {
-        memset(pvBuf, 0, cbToRead);
+        size_t cbSet;
+
+        cbSet = vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
+        Assert(cbSet == cbToRead);
+
         rc = VINF_SUCCESS;
     }
@@ -1665,11 +1594,11 @@
 
         if (u64Offset + cbToRead <= pImage->cbImage)
-            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, u64Offset,
-                                       pvBuf, cbToRead);
+            rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, u64Offset,
+                                       pIoCtx, cbToRead);
         else
         {
             LogRel(("VDI: Out of range access (%llu) in image %s, image size %llu\n",
                     u64Offset, pImage->pszFilename, pImage->cbImage));
-            memset(pvBuf, 0, cbToRead);
+            vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
             rc = VERR_VD_READ_OUT_OF_RANGE;
         }
@@ -1684,10 +1613,10 @@
 }
 
-/**@copydoc VBOXHDDBACKEND::pfnWrite */
-static int vdiWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                    size_t cbToWrite, size_t *pcbWriteProcess,
-                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
+static int vdiWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
+                    PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                    size_t *pcbPostRead, unsigned fWrite)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
     PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
     unsigned uBlock;
@@ -1705,5 +1634,5 @@
     }
 
-    if (!VALID_PTR(pvBuf) || !cbToWrite)
+    if (!VALID_PTR(pIoCtx) || !cbToWrite)
     {
         rc = VERR_INVALID_PARAMETER;
@@ -1736,7 +1665,5 @@
                  * (which also means that it's a zero block. Don't need to write
                  * anything to this block  if the data consists of just zeroes. */
-                Assert(!(cbToWrite % 4));
-                Assert(cbToWrite * 8 <= UINT32_MAX);
-                if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbToWrite * 8) == -1)
+                if (vdIfIoIntIoCtxIsZero(pImage->pIfIo, pIoCtx, cbToWrite, true))
                 {
                     pImage->paBlocks[uBlock] = VDI_IMAGE_BLOCK_ZERO;
@@ -1753,25 +1680,33 @@
                  * Allocate block and write data. */
                 Assert(!offWrite);
+                PVDIASYNCBLOCKALLOC pBlockAlloc = (PVDIASYNCBLOCKALLOC)RTMemAllocZ(sizeof(VDIASYNCBLOCKALLOC));
+                if (!pBlockAlloc)
+                {
+                    rc = VERR_NO_MEMORY;
+                    break;
+                }
+
                 unsigned cBlocksAllocated = getImageBlocksAllocated(&pImage->Header);
                 uint64_t u64Offset = (uint64_t)cBlocksAllocated * pImage->cbTotalBlockData
                                    + (pImage->offStartData + pImage->offStartBlockData);
-                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                            u64Offset, pvBuf, cbToWrite);
-                if (RT_FAILURE(rc))
-                    goto out;
-                pImage->paBlocks[uBlock] = cBlocksAllocated;
-
-                if (pImage->paBlocksRev)
-                    pImage->paBlocksRev[cBlocksAllocated] = uBlock;
-
-                setImageBlocksAllocated(&pImage->Header, cBlocksAllocated + 1);
-
-                rc = vdiUpdateBlockInfo(pImage, uBlock);
-                if (RT_FAILURE(rc))
-                    goto out;
-
-                pImage->cbImage += cbToWrite;
+
+                pBlockAlloc->cBlocksAllocated = cBlocksAllocated;
+                pBlockAlloc->uBlock           = uBlock;
+
                 *pcbPreRead = 0;
                 *pcbPostRead = 0;
+
+                rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
+                                            u64Offset, pIoCtx, cbToWrite,
+                                            vdiBlockAllocUpdate, pBlockAlloc);
+                if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+                    break;
+                else if (RT_FAILURE(rc))
+                {
+                    RTMemFree(pBlockAlloc);
+                    break;
+                }
+
+                rc = vdiBlockAllocUpdate(pImage, pIoCtx, pBlockAlloc, rc);
             }
             else
@@ -1789,6 +1724,6 @@
             uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData
                                + (pImage->offStartData + pImage->offStartBlockData + offWrite);
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, u64Offset,
-                                        pvBuf, cbToWrite);
+            rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
+                                        u64Offset, pIoCtx, cbToWrite, NULL, NULL);
         }
     } while (0);
@@ -1802,6 +1737,5 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int vdiFlush(void *pBackendData)
+static int vdiFlush(void *pBackendData, PVDIOCTX pIoCtx)
 {
     LogFlowFunc(("pBackendData=%#p\n", pBackendData));
@@ -1811,5 +1745,5 @@
     Assert(pImage);
 
-    vdiFlushImage(pImage);
+    rc = vdiFlushImageIoCtx(pImage, pIoCtx);
     LogFlowFunc(("returns %Rrc\n", rc));
     return rc;
@@ -2432,209 +2366,4 @@
 }
 
-static int vdiAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
-                        PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
-    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
-    unsigned uBlock;
-    unsigned offRead;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(!(uOffset % 512));
-    Assert(!(cbToRead % 512));
-
-    if (   uOffset + cbToRead > getImageDiskSize(&pImage->Header)
-        || !VALID_PTR(pIoCtx)
-        || !cbToRead)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Calculate starting block number and offset inside it. */
-    uBlock = (unsigned)(uOffset >> pImage->uShiftOffset2Index);
-    offRead = (unsigned)uOffset & pImage->uBlockMask;
-
-    /* Clip read range to at most the rest of the block. */
-    cbToRead = RT_MIN(cbToRead, getImageBlockSize(&pImage->Header) - offRead);
-    Assert(!(cbToRead % 512));
-
-    if (pImage->paBlocks[uBlock] == VDI_IMAGE_BLOCK_FREE)
-        rc = VERR_VD_BLOCK_FREE;
-    else if (pImage->paBlocks[uBlock] == VDI_IMAGE_BLOCK_ZERO)
-    {
-        size_t cbSet;
-
-        cbSet = vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
-        Assert(cbSet == cbToRead);
-
-        rc = VINF_SUCCESS;
-    }
-    else
-    {
-        /* Block present in image file, read relevant data. */
-        uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData
-                           + (pImage->offStartData + pImage->offStartBlockData + offRead);
-
-        if (u64Offset + cbToRead <= pImage->cbImage)
-            rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, u64Offset,
-                                       pIoCtx, cbToRead);
-        else
-        {
-            LogRel(("VDI: Out of range access (%llu) in image %s, image size %llu\n",
-                    u64Offset, pImage->pszFilename, pImage->cbImage));
-            vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
-            rc = VERR_VD_READ_OUT_OF_RANGE;
-        }
-    }
-
-    if (pcbActuallyRead)
-        *pcbActuallyRead = cbToRead;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-static int vdiAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
-                         PVDIOCTX pIoCtx,
-                         size_t *pcbWriteProcess, size_t *pcbPreRead,
-                         size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
-                 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
-    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
-    unsigned uBlock;
-    unsigned offWrite;
-    int rc = VINF_SUCCESS;
-
-    AssertPtr(pImage);
-    Assert(!(uOffset % 512));
-    Assert(!(cbToWrite % 512));
-
-    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-    {
-        rc = VERR_VD_IMAGE_READ_ONLY;
-        goto out;
-    }
-
-    if (!VALID_PTR(pIoCtx) || !cbToWrite)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* No size check here, will do that later.  For dynamic images which are
-     * not multiples of the block size in length, this would prevent writing to
-     * the last block. */
-
-    /* Calculate starting block number and offset inside it. */
-    uBlock = (unsigned)(uOffset >> pImage->uShiftOffset2Index);
-    offWrite = (unsigned)uOffset & pImage->uBlockMask;
-
-    /* Clip write range to at most the rest of the block. */
-    cbToWrite = RT_MIN(cbToWrite, getImageBlockSize(&pImage->Header) - offWrite);
-    Assert(!(cbToWrite % 512));
-
-    do
-    {
-        if (!IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[uBlock]))
-        {
-            /* Block is either free or zero. */
-            if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
-                && (   pImage->paBlocks[uBlock] == VDI_IMAGE_BLOCK_ZERO
-                    || cbToWrite == getImageBlockSize(&pImage->Header)))
-            {
-                /* If the destination block is unallocated at this point, it's
-                 * either a zero block or a block which hasn't been used so far
-                 * (which also means that it's a zero block. Don't need to write
-                 * anything to this block  if the data consists of just zeroes. */
-                if (vdIfIoIntIoCtxIsZero(pImage->pIfIo, pIoCtx, cbToWrite, true))
-                {
-                    pImage->paBlocks[uBlock] = VDI_IMAGE_BLOCK_ZERO;
-                    *pcbPreRead = 0;
-                    *pcbPostRead = 0;
-                    break;
-                }
-            }
-
-            if (   cbToWrite == getImageBlockSize(&pImage->Header)
-                && !(fWrite & VD_WRITE_NO_ALLOC))
-            {
-                /* Full block write to previously unallocated block.
-                 * Allocate block and write data. */
-                Assert(!offWrite);
-                PVDIASYNCBLOCKALLOC pBlockAlloc = (PVDIASYNCBLOCKALLOC)RTMemAllocZ(sizeof(VDIASYNCBLOCKALLOC));
-                if (!pBlockAlloc)
-                {
-                    rc = VERR_NO_MEMORY;
-                    break;
-                }
-
-                unsigned cBlocksAllocated = getImageBlocksAllocated(&pImage->Header);
-                uint64_t u64Offset = (uint64_t)cBlocksAllocated * pImage->cbTotalBlockData
-                                   + (pImage->offStartData + pImage->offStartBlockData);
-
-                pBlockAlloc->cBlocksAllocated = cBlocksAllocated;
-                pBlockAlloc->uBlock           = uBlock;
-
-                *pcbPreRead = 0;
-                *pcbPostRead = 0;
-
-                rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
-                                            u64Offset, pIoCtx, cbToWrite,
-                                            vdiAsyncBlockAllocUpdate, pBlockAlloc);
-                if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
-                    break;
-                else if (RT_FAILURE(rc))
-                {
-                    RTMemFree(pBlockAlloc);
-                    break;
-                }
-
-                rc = vdiAsyncBlockAllocUpdate(pImage, pIoCtx, pBlockAlloc, rc);
-            }
-            else
-            {
-                /* Trying to do a partial write to an unallocated block. Don't do
-                 * anything except letting the upper layer know what to do. */
-                *pcbPreRead = offWrite % getImageBlockSize(&pImage->Header);
-                *pcbPostRead = getImageBlockSize(&pImage->Header) - cbToWrite - *pcbPreRead;
-                rc = VERR_VD_BLOCK_FREE;
-            }
-        }
-        else
-        {
-            /* Block present in image file, write relevant data. */
-            uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData
-                               + (pImage->offStartData + pImage->offStartBlockData + offWrite);
-            rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
-                                        u64Offset, pIoCtx, cbToWrite, NULL, NULL);
-        }
-    } while (0);
-
-    if (pcbWriteProcess)
-        *pcbWriteProcess = cbToWrite;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-static int vdiAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
-    int rc = VINF_SUCCESS;
-
-    Assert(pImage);
-
-    rc = vdiFlushImageAsync(pImage, pIoCtx);
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
 /** @copydoc VBOXHDDBACKEND::pfnCompact */
 static int vdiCompact(void *pBackendData, unsigned uPercentStart,
@@ -3088,136 +2817,6 @@
 }
 
-
 /** @copydoc VBOXHDDBACKEND::pfnDiscard */
-static DECLCALLBACK(int) vdiDiscard(void *pBackendData,
-                                    uint64_t uOffset, size_t cbDiscard,
-                                    size_t *pcbPreAllocated,
-                                    size_t *pcbPostAllocated,
-                                    size_t *pcbActuallyDiscarded,
-                                    void   **ppbmAllocationBitmap,
-                                    unsigned fDiscard)
-{
-    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
-    unsigned uBlock;
-    unsigned offDiscard;
-    int rc = VINF_SUCCESS;
-    void *pvBlock = NULL;
-
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu cbDiscard=%zu pcbPreAllocated=%#p pcbPostAllocated=%#p pcbActuallyDiscarded=%#p ppbmAllocationBitmap=%#p fDiscard=%#x\n",
-                 pBackendData, uOffset, cbDiscard, pcbPreAllocated, pcbPostAllocated, pcbActuallyDiscarded, ppbmAllocationBitmap, fDiscard));
-
-    AssertPtr(pImage);
-    Assert(!(uOffset % 512));
-    Assert(!(cbDiscard % 512));
-
-    AssertMsgReturn(!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY),
-                    ("Image is readonly\n"), VERR_VD_IMAGE_READ_ONLY);
-    AssertMsgReturn(   uOffset + cbDiscard <= getImageDiskSize(&pImage->Header)
-                    && cbDiscard,
-                    ("Invalid parameters uOffset=%llu cbDiscard=%zu\n",
-                     uOffset, cbDiscard),
-                     VERR_INVALID_PARAMETER);
-
-    do
-    {
-        AssertMsgBreakStmt(!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY),
-                           ("Image is opened readonly\n"),
-                           rc = VERR_VD_IMAGE_READ_ONLY);
-
-        AssertMsgBreakStmt(cbDiscard,
-                           ("cbDiscard=%u\n", cbDiscard),
-                           rc = VERR_INVALID_PARAMETER);
-
-        /* Calculate starting block number and offset inside it. */
-        uBlock = (unsigned)(uOffset >> pImage->uShiftOffset2Index);
-        offDiscard = (unsigned)uOffset & pImage->uBlockMask;
-
-        /* Clip range to at most the rest of the block. */
-        cbDiscard = RT_MIN(cbDiscard, getImageBlockSize(&pImage->Header) - offDiscard);
-        Assert(!(cbDiscard % 512));
-
-        if (pcbPreAllocated)
-            *pcbPreAllocated = 0;
-
-        if (pcbPostAllocated)
-            *pcbPostAllocated = 0;
-
-        if (IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[uBlock]))
-        {
-            uint8_t *pbBlockData;
-            size_t cbPreAllocated, cbPostAllocated;
-
-            cbPreAllocated = offDiscard % getImageBlockSize(&pImage->Header);
-            cbPostAllocated = getImageBlockSize(&pImage->Header) - cbDiscard - cbPreAllocated;
-
-            /* Read the block data. */
-            pvBlock = RTMemAlloc(pImage->cbTotalBlockData);
-            if (!pvBlock)
-            {
-                rc = VERR_NO_MEMORY;
-                break;
-            }
-
-            if (!cbPreAllocated && !cbPostAllocated)
-            {
-                /*
-                 * Discarding a whole block, don't check for allocated sectors.
-                 * It is possible to just remove the whole block which avoids
-                 * one read and checking the whole block for data.
-                 */
-                rc = vdiDiscardBlock(pImage, uBlock, pvBlock);
-            }
-            else
-            {
-                /* Read data. */
-                pbBlockData = (uint8_t *)pvBlock + pImage->offStartBlockData;
-
-                uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData + pImage->offStartData;
-                rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, u64Offset,
-                                           pvBlock, pImage->cbTotalBlockData);
-                if (RT_FAILURE(rc))
-                    break;
-
-                /* Clear data. */
-                memset(pbBlockData + offDiscard , 0, cbDiscard);
-
-                Assert(!(cbDiscard % 4));
-                Assert(cbDiscard * 8 <= UINT32_MAX);
-                if (ASMBitFirstSet((volatile void *)pbBlockData, getImageBlockSize(&pImage->Header) * 8) == -1)
-                    rc = vdiDiscardBlock(pImage, uBlock, pvBlock);
-                else if (fDiscard & VD_DISCARD_MARK_UNUSED)
-                {
-                    /* Write changed data to the image. */
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, u64Offset + offDiscard,
-                                                pbBlockData + offDiscard, cbDiscard);
-                }
-                else
-                {
-                    /* Block has data, create allocation bitmap. */
-                    *pcbPreAllocated = cbPreAllocated;
-                    *pcbPostAllocated = cbPostAllocated;
-                    *ppbmAllocationBitmap = vdiAllocationBitmapCreate(pbBlockData, getImageBlockSize(&pImage->Header));
-                    if (RT_UNLIKELY(!*ppbmAllocationBitmap))
-                        rc = VERR_NO_MEMORY;
-                    else
-                        rc = VERR_VD_DISCARD_ALIGNMENT_NOT_MET;
-                }
-            } /* if: no complete block discarded */
-        } /* if: Block is allocated. */
-        /* else: nothing to do. */
-    } while (0);
-
-    if (pcbActuallyDiscarded)
-        *pcbActuallyDiscarded = cbDiscard;
-
-    if (pvBlock)
-        RTMemFree(pvBlock);
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnDiscard */
-static DECLCALLBACK(int) vdiAsyncDiscard(void *pBackendData, PVDIOCTX pIoCtx,
+static DECLCALLBACK(int) vdiDiscard(void *pBackendData, PVDIOCTX pIoCtx,
                                          uint64_t uOffset, size_t cbDiscard,
                                          size_t *pcbPreAllocated,
@@ -3602,4 +3201,6 @@
     /* pfnFlush */
     vdiFlush,
+    /* pfnDiscard */
+    vdiDiscard,
     /* pfnGetVersion */
     vdiGetVersion,
@@ -3654,10 +3255,4 @@
     /* pfnSetParentFilename */
     NULL,
-    /* pfnAsyncRead */
-    vdiAsyncRead,
-    /* pfnAsyncWrite */
-    vdiAsyncWrite,
-    /* pfnAsyncFlush */
-    vdiAsyncFlush,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -3668,8 +3263,4 @@
     /* pfnResize */
     vdiResize,
-    /* pfnDiscard */
-    vdiDiscard,
-    /* pfnAsyncDiscard */
-    vdiAsyncDiscard,
     /* pfnRepair */
     vdiRepair
Index: trunk/src/VBox/Storage/VHD.cpp
===================================================================
--- trunk/src/VBox/Storage/VHD.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/VHD.cpp	(revision 44252)
@@ -1451,837 +1451,6 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnRead */
-static int vhdRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                   size_t cbBuf, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%p uOffset=%#llu pvBuf=%p cbBuf=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbActuallyRead));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc = VINF_SUCCESS;
-
-    if (uOffset + cbBuf > pImage->cbSize)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /*
-     * If we have a dynamic disk image, we need to find the data block and sector to read.
-     */
-    if (pImage->pBlockAllocationTable)
-    {
-        /*
-         * Get the data block first.
-         */
-        uint32_t cBlockAllocationTableEntry = (uOffset / VHD_SECTOR_SIZE) / pImage->cSectorsPerDataBlock;
-        uint32_t cBATEntryIndex = (uOffset / VHD_SECTOR_SIZE) % pImage->cSectorsPerDataBlock;
-        uint64_t uVhdOffset;
-
-        LogFlowFunc(("cBlockAllocationTableEntry=%u cBatEntryIndex=%u\n", cBlockAllocationTableEntry, cBATEntryIndex));
-        LogFlowFunc(("BlockAllocationEntry=%u\n", pImage->pBlockAllocationTable[cBlockAllocationTableEntry]));
-
-        /*
-         * Clip read range to remain in this data block.
-         */
-        cbBuf = RT_MIN(cbBuf, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
-
-        /*
-         * If the block is not allocated the content of the entry is ~0
-         */
-        if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U)
-            rc = VERR_VD_BLOCK_FREE;
-        else
-        {
-            uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
-            LogFlowFunc(("uVhdOffset=%llu cbBuf=%u\n", uVhdOffset, cbBuf));
-
-            /* Read in the block's bitmap. */
-            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
-                                       ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
-                                       pImage->pu8Bitmap, pImage->cbDataBlockBitmap);
-            if (RT_SUCCESS(rc))
-            {
-                uint32_t cSectors = 0;
-
-                if (vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
-                {
-                    cBATEntryIndex++;
-                    cSectors = 1;
-
-                    /*
-                     * The first sector being read is marked dirty, read as much as we
-                     * can from child. Note that only sectors that are marked dirty
-                     * must be read from child.
-                     */
-                    while (   (cSectors < (cbBuf / VHD_SECTOR_SIZE))
-                           && vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
-                    {
-                        cBATEntryIndex++;
-                        cSectors++;
-                    }
-
-                    cbBuf = cSectors * VHD_SECTOR_SIZE;
-
-                    LogFlowFunc(("uVhdOffset=%llu cbBuf=%u\n", uVhdOffset, cbBuf));
-                    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
-                                               uVhdOffset, pvBuf, cbBuf);
-                }
-                else
-                {
-                    /*
-                     * The first sector being read is marked clean, so we should read from
-                     * our parent instead, but only as much as there are the following
-                     * clean sectors, because the block may still contain dirty sectors
-                     * further on. We just need to compute the number of clean sectors
-                     * and pass it to our caller along with the notification that they
-                     * should be read from the parent.
-                     */
-                    cBATEntryIndex++;
-                    cSectors = 1;
-
-                    while (   (cSectors < (cbBuf / VHD_SECTOR_SIZE))
-                           && !vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
-                    {
-                        cBATEntryIndex++;
-                        cSectors++;
-                    }
-
-                    cbBuf = cSectors * VHD_SECTOR_SIZE;
-                    LogFunc(("Sectors free: uVhdOffset=%llu cbBuf=%u\n", uVhdOffset, cbBuf));
-                    rc = VERR_VD_BLOCK_FREE;
-                }
-            }
-            else
-                AssertMsgFailed(("Reading block bitmap failed rc=%Rrc\n", rc));
-        }
-    }
-    else
-        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf, cbBuf);
-
-    if (   RT_SUCCESS(rc)
-        || rc == VERR_VD_BLOCK_FREE)
-    {
-        if (pcbActuallyRead)
-            *pcbActuallyRead = cbBuf;
-
-        Log2(("vhdRead: off=%#llx pvBuf=%p cbBuf=%d\n", uOffset, pvBuf, cbBuf));
-    }
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int vhdWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                    size_t cbBuf, size_t *pcbWriteProcess,
-                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbBuf=%zu pcbWriteProcess=%#p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbWriteProcess));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc = VINF_SUCCESS;
-
-    LogFlowFunc(("pBackendData=%p uOffset=%llu pvBuf=%p cbBuf=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
-             pBackendData, uOffset, pvBuf, cbBuf, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite));
-
-    AssertPtr(pImage);
-    Assert(uOffset % VHD_SECTOR_SIZE == 0);
-    Assert(cbBuf % VHD_SECTOR_SIZE == 0);
-
-    if (pImage->pBlockAllocationTable)
-    {
-        /*
-         * Get the data block first.
-         */
-        uint32_t cSector = uOffset / VHD_SECTOR_SIZE;
-        uint32_t cBlockAllocationTableEntry = cSector / pImage->cSectorsPerDataBlock;
-        uint32_t cBATEntryIndex = cSector % pImage->cSectorsPerDataBlock;
-        uint64_t uVhdOffset;
-
-        /*
-         * Clip write range.
-         */
-        cbBuf = RT_MIN(cbBuf, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
-
-        /*
-         * If the block is not allocated the content of the entry is ~0
-         * and we need to allocate a new block. Note that while blocks are
-         * allocated with a relatively big granularity, each sector has its
-         * own bitmap entry, indicating whether it has been written or not.
-         * So that means for the purposes of the higher level that the
-         * granularity is invisible. This means there's no need to return
-         * VERR_VD_BLOCK_FREE unless the block hasn't been allocated yet.
-         */
-        if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U)
-        {
-            /* Check if the block allocation should be suppressed. */
-            if (fWrite & VD_WRITE_NO_ALLOC)
-            {
-                *pcbPreRead = cBATEntryIndex * VHD_SECTOR_SIZE;
-                *pcbPostRead = pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE - cbBuf - *pcbPreRead;
-
-                if (pcbWriteProcess)
-                    *pcbWriteProcess = cbBuf;
-                rc = VERR_VD_BLOCK_FREE;
-                goto out;
-            }
-
-            size_t  cbNewBlock = pImage->cbDataBlock + (pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE);
-            uint8_t *pNewBlock = (uint8_t *)RTMemAllocZ(cbNewBlock);
-
-            if (!pNewBlock)
-            {
-                rc = VERR_NO_MEMORY;
-                goto out;
-            }
-
-            /*
-             * Write the new block at the current end of the file.
-             */
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->uCurrentEndOfFile,
-                                        pNewBlock, cbNewBlock);
-            AssertRC(rc);
-
-            /*
-             * Set the new end of the file and link the new block into the BAT.
-             */
-            pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
-            pImage->uCurrentEndOfFile += cbNewBlock;
-            RTMemFree(pNewBlock);
-
-            /* Write the updated BAT and the footer to remain in a consistent state. */
-            rc = vhdFlushImage(pImage);
-            AssertRC(rc);
-        }
-
-        /*
-         * Calculate the real offset in the file.
-         */
-        uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
-
-        /* Write data. */
-        vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uVhdOffset,
-                               pvBuf, cbBuf);
-
-        /* Read in the block's bitmap. */
-        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
-                                   ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
-                                   pImage->pu8Bitmap, pImage->cbDataBlockBitmap);
-        if (RT_SUCCESS(rc))
-        {
-            bool fChanged = false;
-
-            /* Set the bits for all sectors having been written. */
-            for (uint32_t iSector = 0; iSector < (cbBuf / VHD_SECTOR_SIZE); iSector++)
-            {
-                fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex);
-                cBATEntryIndex++;
-            }
-
-            if (fChanged)
-            {
-                /* Write the bitmap back. */
-                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                            ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
-                                            pImage->pu8Bitmap, pImage->cbDataBlockBitmap);
-            }
-        }
-    }
-    else
-    {
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf, cbBuf);
-    }
-
-    if (pcbWriteProcess)
-        *pcbWriteProcess = cbBuf;
-
-    /* Stay on the safe side. Do not run the risk of confusing the higher
-     * level, as that can be pretty lethal to image consistency. */
-    *pcbPreRead = 0;
-    *pcbPostRead = 0;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int vhdFlush(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p", pBackendData));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    rc = vhdFlushImage(pImage);
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
-static unsigned vhdGetVersion(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    unsigned ver = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        ver = 1; /**< @todo use correct version */
-
-    LogFlowFunc(("returns %u\n", ver));
-    return ver;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetSize */
-static uint64_t vhdGetSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage && pImage->pStorage)
-        cb = pImage->cbSize;
-
-    LogFlowFunc(("returns %llu\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
-static uint64_t vhdGetFileSize(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    uint64_t cb = 0;
-
-    AssertPtr(pImage);
-
-    if (pImage && pImage->pStorage)
-        cb = pImage->uCurrentEndOfFile + sizeof(VHDFooter);
-
-    LogFlowFunc(("returns %lld\n", cb));
-    return cb;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
-static int vhdGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->PCHSGeometry.cCylinders)
-        {
-            *pPCHSGeometry = pImage->PCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (CHS=%u/%u/%u)\n", rc, pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
-static int vhdSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
-{
-    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->PCHSGeometry = *pPCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
-static int vhdGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
-{
-LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->LCHSGeometry.cCylinders)
-        {
-            *pLCHSGeometry = pImage->LCHSGeometry;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_GEOMETRY_NOT_SET;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (CHS=%u/%u/%u)\n", rc, pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
-static int vhdSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
-{
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-        {
-            rc = VERR_VD_IMAGE_READ_ONLY;
-            goto out;
-        }
-
-        pImage->LCHSGeometry = *pLCHSGeometry;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
-static unsigned vhdGetImageFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    unsigned uImageFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uImageFlags = pImage->uImageFlags;
-    else
-        uImageFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uImageFlags));
-    return uImageFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
-static unsigned vhdGetOpenFlags(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    unsigned uOpenFlags;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        uOpenFlags = pImage->uOpenFlags;
-    else
-        uOpenFlags = 0;
-
-    LogFlowFunc(("returns %#x\n", uOpenFlags));
-    return uOpenFlags;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
-static int vhdSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
-{
-    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    /* Image must be opened and the new flags must be valid. */
-    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
-                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
-                                   | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* Implement this operation via reopening the image. */
-    rc = vhdFreeImage(pImage, false);
-    if (RT_FAILURE(rc))
-        goto out;
-    rc = vhdOpenImage(pImage, uOpenFlags);
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetComment */
-static int vhdGetComment(void *pBackendData, char *pszComment,
-                         size_t cbComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetComment */
-static int vhdSetComment(void *pBackendData, const char *pszComment)
-{
-    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else
-            rc = VERR_NOT_SUPPORTED;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
-static int vhdGetUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        *pUuid = pImage->ImageUuid;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
-static int vhdSetUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-        {
-            pImage->ImageUuid = *pUuid;
-            /* Update the footer copy. It will get written to disk when the image is closed. */
-            memcpy(&pImage->vhdFooterCopy.UniqueID, pUuid, 16);
-            /* Update checksum. */
-            pImage->vhdFooterCopy.Checksum = 0;
-            pImage->vhdFooterCopy.Checksum = RT_H2BE_U32(vhdChecksum(&pImage->vhdFooterCopy, sizeof(VHDFooter)));
-
-            /* Need to update the dynamic disk header to update the disk footer copy at the beginning. */
-            if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED))
-                pImage->fDynHdrNeedsUpdate = true;
-            rc = VINF_SUCCESS;
-        }
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
-static int vhdGetModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
-static int vhdSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
-static int vhdGetParentUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        *pUuid = pImage->ParentUuid;
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
-static int vhdSetParentUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc = VINF_SUCCESS;
-
-    AssertPtr(pImage);
-
-    if (pImage && pImage->pStorage)
-    {
-        if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED))
-        {
-            pImage->ParentUuid = *pUuid;
-            pImage->fDynHdrNeedsUpdate = true;
-        }
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
-static int vhdGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = VERR_NOT_SUPPORTED;
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
-static int vhdSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
-{
-    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-    int rc;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-    {
-        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-            rc = VERR_NOT_SUPPORTED;
-        else
-            rc = VERR_VD_IMAGE_READ_ONLY;
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnDump */
-static void vhdDump(void *pBackendData)
-{
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%u\n",
-                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
-                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
-                         VHD_SECTOR_SIZE);
-        vdIfErrorMessage(pImage->pIfError, "Header: uuidCreation={%RTuuid}\n", &pImage->ImageUuid);
-        vdIfErrorMessage(pImage->pIfError, "Header: uuidParent={%RTuuid}\n", &pImage->ParentUuid);
-    }
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetTimestamp */
-static int vhdGetTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp)
-{
-    int rc = VINF_SUCCESS;
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        rc = vdIfIoIntFileGetModificationTime(pImage->pIfIo, pImage->pszFilename, pTimeStamp);
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentTimeStamp */
-static int vhdGetParentTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp)
-{
-    int rc = VINF_SUCCESS;
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-
-    if (pImage)
-        vhdTime2RtTime(pTimeStamp, pImage->u32ParentTimeStamp);
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentTimeStamp */
-static int vhdSetParentTimeStamp(void *pBackendData, PCRTTIMESPEC pTimeStamp)
-{
-    int rc = VINF_SUCCESS;
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else
-        {
-            pImage->u32ParentTimeStamp = vhdRtTime2VhdTime(pTimeStamp);
-            pImage->fDynHdrNeedsUpdate = true;
-        }
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnGetParentFilename */
-static int vhdGetParentFilename(void *pBackendData, char **ppszParentFilename)
-{
-    int rc = VINF_SUCCESS;
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-        *ppszParentFilename = RTStrDup(pImage->pszParentFilename);
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnSetParentFilename */
-static int vhdSetParentFilename(void *pBackendData, const char *pszParentFilename)
-{
-    int rc = VINF_SUCCESS;
-    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-
-    AssertPtr(pImage);
-    if (pImage)
-    {
-        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-            rc = VERR_VD_IMAGE_READ_ONLY;
-        else
-        {
-            if (pImage->pszParentFilename)
-                RTStrFree(pImage->pszParentFilename);
-            pImage->pszParentFilename = RTStrDup(pszParentFilename);
-            if (!pImage->pszParentFilename)
-                rc = VERR_NO_MEMORY;
-            else
-                pImage->fDynHdrNeedsUpdate = true;
-        }
-    }
-    else
-        rc = VERR_VD_NOT_OPENED;
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
-static int vhdAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
-                        PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+static int vhdRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
+                   PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
 {
     PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
@@ -2397,9 +1566,8 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
-static int vhdAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
-                         PVDIOCTX pIoCtx,
-                         size_t *pcbWriteProcess, size_t *pcbPreRead,
-                         size_t *pcbPostRead, unsigned fWrite)
+/** @copydoc VBOXHDDBACKEND::pfnWrite */
+static int vhdWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
+                    PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                    size_t *pcbPostRead, unsigned fWrite)
 {
     PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
@@ -2632,6 +1800,6 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
-static int vhdAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
+/** @copydoc VBOXHDDBACKEND::pfnFlush */
+static int vhdFlush(void *pBackendData, PVDIOCTX pIoCtx)
 {
     PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
@@ -2639,4 +1807,569 @@
     /* No need to write anything here. Data is always updated on a write. */
     return vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
+static unsigned vhdGetVersion(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    unsigned ver = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        ver = 1; /**< @todo use correct version */
+
+    LogFlowFunc(("returns %u\n", ver));
+    return ver;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetSize */
+static uint64_t vhdGetSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage && pImage->pStorage)
+        cb = pImage->cbSize;
+
+    LogFlowFunc(("returns %llu\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
+static uint64_t vhdGetFileSize(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    uint64_t cb = 0;
+
+    AssertPtr(pImage);
+
+    if (pImage && pImage->pStorage)
+        cb = pImage->uCurrentEndOfFile + sizeof(VHDFooter);
+
+    LogFlowFunc(("returns %lld\n", cb));
+    return cb;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
+static int vhdGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->PCHSGeometry.cCylinders)
+        {
+            *pPCHSGeometry = pImage->PCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (CHS=%u/%u/%u)\n", rc, pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
+static int vhdSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
+{
+    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->PCHSGeometry = *pPCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
+static int vhdGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
+{
+LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->LCHSGeometry.cCylinders)
+        {
+            *pLCHSGeometry = pImage->LCHSGeometry;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_GEOMETRY_NOT_SET;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (CHS=%u/%u/%u)\n", rc, pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
+static int vhdSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
+{
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+        {
+            rc = VERR_VD_IMAGE_READ_ONLY;
+            goto out;
+        }
+
+        pImage->LCHSGeometry = *pLCHSGeometry;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
+static unsigned vhdGetImageFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    unsigned uImageFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uImageFlags = pImage->uImageFlags;
+    else
+        uImageFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uImageFlags));
+    return uImageFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
+static unsigned vhdGetOpenFlags(void *pBackendData)
+{
+    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    unsigned uOpenFlags;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        uOpenFlags = pImage->uOpenFlags;
+    else
+        uOpenFlags = 0;
+
+    LogFlowFunc(("returns %#x\n", uOpenFlags));
+    return uOpenFlags;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
+static int vhdSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
+{
+    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    /* Image must be opened and the new flags must be valid. */
+    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
+                                   | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
+                                   | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
+    /* Implement this operation via reopening the image. */
+    rc = vhdFreeImage(pImage, false);
+    if (RT_FAILURE(rc))
+        goto out;
+    rc = vhdOpenImage(pImage, uOpenFlags);
+
+out:
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetComment */
+static int vhdGetComment(void *pBackendData, char *pszComment,
+                         size_t cbComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetComment */
+static int vhdSetComment(void *pBackendData, const char *pszComment)
+{
+    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else
+            rc = VERR_NOT_SUPPORTED;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
+static int vhdGetUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        *pUuid = pImage->ImageUuid;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
+static int vhdSetUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+        {
+            pImage->ImageUuid = *pUuid;
+            /* Update the footer copy. It will get written to disk when the image is closed. */
+            memcpy(&pImage->vhdFooterCopy.UniqueID, pUuid, 16);
+            /* Update checksum. */
+            pImage->vhdFooterCopy.Checksum = 0;
+            pImage->vhdFooterCopy.Checksum = RT_H2BE_U32(vhdChecksum(&pImage->vhdFooterCopy, sizeof(VHDFooter)));
+
+            /* Need to update the dynamic disk header to update the disk footer copy at the beginning. */
+            if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED))
+                pImage->fDynHdrNeedsUpdate = true;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
+static int vhdGetModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
+static int vhdSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
+static int vhdGetParentUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        *pUuid = pImage->ParentUuid;
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
+static int vhdSetParentUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc = VINF_SUCCESS;
+
+    AssertPtr(pImage);
+
+    if (pImage && pImage->pStorage)
+    {
+        if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED))
+        {
+            pImage->ParentUuid = *pUuid;
+            pImage->fDynHdrNeedsUpdate = true;
+        }
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
+static int vhdGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = VERR_NOT_SUPPORTED;
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
+static int vhdSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
+{
+    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+    int rc;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+    {
+        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
+            rc = VERR_NOT_SUPPORTED;
+        else
+            rc = VERR_VD_IMAGE_READ_ONLY;
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnDump */
+static void vhdDump(void *pBackendData)
+{
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%u\n",
+                         pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
+                         pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
+                         VHD_SECTOR_SIZE);
+        vdIfErrorMessage(pImage->pIfError, "Header: uuidCreation={%RTuuid}\n", &pImage->ImageUuid);
+        vdIfErrorMessage(pImage->pIfError, "Header: uuidParent={%RTuuid}\n", &pImage->ParentUuid);
+    }
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetTimestamp */
+static int vhdGetTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp)
+{
+    int rc = VINF_SUCCESS;
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        rc = vdIfIoIntFileGetModificationTime(pImage->pIfIo, pImage->pszFilename, pTimeStamp);
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentTimeStamp */
+static int vhdGetParentTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp)
+{
+    int rc = VINF_SUCCESS;
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+
+    if (pImage)
+        vhdTime2RtTime(pTimeStamp, pImage->u32ParentTimeStamp);
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentTimeStamp */
+static int vhdSetParentTimeStamp(void *pBackendData, PCRTTIMESPEC pTimeStamp)
+{
+    int rc = VINF_SUCCESS;
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else
+        {
+            pImage->u32ParentTimeStamp = vhdRtTime2VhdTime(pTimeStamp);
+            pImage->fDynHdrNeedsUpdate = true;
+        }
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnGetParentFilename */
+static int vhdGetParentFilename(void *pBackendData, char **ppszParentFilename)
+{
+    int rc = VINF_SUCCESS;
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+        *ppszParentFilename = RTStrDup(pImage->pszParentFilename);
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+/** @copydoc VBOXHDDBACKEND::pfnSetParentFilename */
+static int vhdSetParentFilename(void *pBackendData, const char *pszParentFilename)
+{
+    int rc = VINF_SUCCESS;
+    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+
+    AssertPtr(pImage);
+    if (pImage)
+    {
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
+            rc = VERR_VD_IMAGE_READ_ONLY;
+        else
+        {
+            if (pImage->pszParentFilename)
+                RTStrFree(pImage->pszParentFilename);
+            pImage->pszParentFilename = RTStrDup(pszParentFilename);
+            if (!pImage->pszParentFilename)
+                rc = VERR_NO_MEMORY;
+            else
+                pImage->fDynHdrNeedsUpdate = true;
+        }
+    }
+    else
+        rc = VERR_VD_NOT_OPENED;
+
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
 }
 
@@ -3056,5 +2789,5 @@
         /* Update header information in base image file. */
         pImage->fDynHdrNeedsUpdate = true;
-        vhdFlush(pImage);
+        vhdFlushImage(pImage);
     }
     /* Same size doesn't change the image at all. */
@@ -3438,4 +3171,6 @@
     /* pfnFlush */
     vhdFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     vhdGetVersion,
@@ -3490,10 +3225,4 @@
     /* pfnSetParentFilename */
     vhdSetParentFilename,
-    /* pfnAsyncRead */
-    vhdAsyncRead,
-    /* pfnAsyncWrite */
-    vhdAsyncWrite,
-    /* pfnAsyncFlush */
-    vhdAsyncFlush,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -3504,8 +3233,4 @@
     /* pfnResize */
     vhdResize,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     vhdRepair
Index: trunk/src/VBox/Storage/VHDX.cpp
===================================================================
--- trunk/src/VBox/Storage/VHDX.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/VHDX.cpp	(revision 44252)
@@ -1864,8 +1864,9 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnRead */
-static int vhdxRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                   size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
+static int vhdxRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
+                    PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
     int rc = VINF_SUCCESS;
@@ -1896,5 +1897,5 @@
             case VHDX_BAT_ENTRY_PAYLOAD_BLOCK_UNMAPPED:
             {
-                memset(pvBuf, 0, cbToRead);
+                vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
                 break;
             }
@@ -1902,6 +1903,6 @@
             {
                 uint64_t offFile = VHDX_BAT_ENTRY_GET_FILE_OFFSET(uBatEntry) + offRead;
-                rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offFile,
-                                           pvBuf, cbToRead);
+                rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, offFile,
+                                           pIoCtx, cbToRead);
                 break;
             }
@@ -1921,10 +1922,10 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int vhdxWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                    size_t cbToWrite, size_t *pcbWriteProcess,
-                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
-                 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
+static int vhdxWrite(void *pBackendData, uint64_t uOffset,  size_t cbToWrite,
+                     PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                     size_t *pcbPostRead, unsigned fWrite)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
     PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
     int rc;
@@ -1947,7 +1948,7 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int vhdxFlush(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+static int vhdxFlush(void *pBackendData, PVDIOCTX pIoCtx)
+{
+    LogFlowFunc(("pBackendData=%#p pIoCtx=%#p\n", pBackendData, pIoCtx));
     PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
     int rc;
@@ -2427,4 +2428,6 @@
     /* pfnFlush */
     vhdxFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     vhdxGetVersion,
@@ -2479,10 +2482,4 @@
     /* pfnSetParentFilename */
     NULL,
-    /* pfnAsyncRead */
-    NULL,
-    /* pfnAsyncWrite */
-    NULL,
-    /* pfnAsyncFlush */
-    NULL,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -2493,8 +2490,4 @@
     /* pfnResize */
     NULL,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
Index: trunk/src/VBox/Storage/VMDK.cpp
===================================================================
--- trunk/src/VBox/Storage/VMDK.cpp	(revision 44251)
+++ trunk/src/VBox/Storage/VMDK.cpp	(revision 44252)
@@ -233,6 +233,4 @@
     /** File open flags for consistency checking. */
     unsigned         fOpen;
-    /** Flag whether this file has been opened for async I/O. */
-    bool             fAsyncIO;
     /** Handle for sync/async file abstraction.*/
     PVDIOSTORAGE     pStorage;
@@ -530,9 +528,10 @@
 
 static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
-static int vmdkFlushImage(PVMDKIMAGE pImage);
+static int vmdkFlushImage(PVMDKIMAGE pImage, PVDIOCTX pIoCtx);
 static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment);
 static int vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
 
-static int vmdkAllocGrainAsyncComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq);
+static int vmdkAllocGrainComplete(void *pBackendData, PVDIOCTX pIoCtx,
+                                  void *pvUser, int rcReq);
 
 /**
@@ -541,5 +540,5 @@
  */
 static int vmdkFileOpen(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile,
-                        const char *pszFilename, uint32_t fOpen, bool fAsyncIO)
+                        const char *pszFilename, uint32_t fOpen)
 {
     int rc = VINF_SUCCESS;
@@ -577,5 +576,4 @@
     }
     pVmdkFile->fOpen = fOpen;
-    pVmdkFile->fAsyncIO = fAsyncIO;
 
     rc = vdIfIoIntFileOpen(pImage->pIfIo, pszFilename, fOpen,
@@ -680,81 +678,73 @@
                                     uint64_t *puLBA, uint32_t *pcbMarkerData)
 {
-    if (pExtent->pFile->fAsyncIO)
-    {
-        AssertMsgFailed(("TODO\n"));
-        return VERR_NOT_SUPPORTED;
-    }
-    else
-    {
-        int rc;
-        PRTZIPDECOMP pZip = NULL;
-        VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
-        size_t cbCompSize, cbActuallyRead;
-
-        if (!pcvMarker)
-        {
-            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                       uOffset, pMarker, RT_OFFSETOF(VMDKMARKER, uType));
-            if (RT_FAILURE(rc))
-                return rc;
-        }
-        else
-        {
-            memcpy(pMarker, pcvMarker, RT_OFFSETOF(VMDKMARKER, uType));
-            /* pcvMarker endianness has already been partially transformed, fix it */
-            pMarker->uSector = RT_H2LE_U64(pMarker->uSector);
-            pMarker->cbSize = RT_H2LE_U32(pMarker->cbSize);
-        }
-
-        cbCompSize = RT_LE2H_U32(pMarker->cbSize);
-        if (cbCompSize == 0)
-        {
-            AssertMsgFailed(("VMDK: corrupted marker\n"));
-            return VERR_VD_VMDK_INVALID_FORMAT;
-        }
-
-        /* Sanity check - the expansion ratio should be much less than 2. */
-        Assert(cbCompSize < 2 * cbToRead);
-        if (cbCompSize >= 2 * cbToRead)
-            return VERR_VD_VMDK_INVALID_FORMAT;
-
-        /* Compressed grain marker. Data follows immediately. */
+    int rc;
+    PRTZIPDECOMP pZip = NULL;
+    VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
+    size_t cbCompSize, cbActuallyRead;
+
+    if (!pcvMarker)
+    {
         rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                   uOffset + RT_OFFSETOF(VMDKMARKER, uType),
-                                    (uint8_t *)pExtent->pvCompGrain
-                                  + RT_OFFSETOF(VMDKMARKER, uType),
-                                   RT_ALIGN_Z(  cbCompSize
-                                              + RT_OFFSETOF(VMDKMARKER, uType),
-                                              512)
-                                   - RT_OFFSETOF(VMDKMARKER, uType));
-
-        if (puLBA)
-            *puLBA = RT_LE2H_U64(pMarker->uSector);
-        if (pcbMarkerData)
-            *pcbMarkerData = RT_ALIGN(  cbCompSize
-                                      + RT_OFFSETOF(VMDKMARKER, uType),
-                                      512);
-
-        VMDKCOMPRESSIO InflateState;
-        InflateState.pImage = pImage;
-        InflateState.iOffset = -1;
-        InflateState.cbCompGrain = cbCompSize + RT_OFFSETOF(VMDKMARKER, uType);
-        InflateState.pvCompGrain = pExtent->pvCompGrain;
-
-        rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper);
+                                   uOffset, pMarker, RT_OFFSETOF(VMDKMARKER, uType));
         if (RT_FAILURE(rc))
             return rc;
-        rc = RTZipDecompress(pZip, pvBuf, cbToRead, &cbActuallyRead);
-        RTZipDecompDestroy(pZip);
-        if (RT_FAILURE(rc))
-        {
-            if (rc == VERR_ZIP_CORRUPTED)
-                rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: Compressed image is corrupted '%s'"), pExtent->pszFullname);
-            return rc;
-        }
-        if (cbActuallyRead != cbToRead)
-            rc = VERR_VD_VMDK_INVALID_FORMAT;
+    }
+    else
+    {
+        memcpy(pMarker, pcvMarker, RT_OFFSETOF(VMDKMARKER, uType));
+        /* pcvMarker endianness has already been partially transformed, fix it */
+        pMarker->uSector = RT_H2LE_U64(pMarker->uSector);
+        pMarker->cbSize = RT_H2LE_U32(pMarker->cbSize);
+    }
+
+    cbCompSize = RT_LE2H_U32(pMarker->cbSize);
+    if (cbCompSize == 0)
+    {
+        AssertMsgFailed(("VMDK: corrupted marker\n"));
+        return VERR_VD_VMDK_INVALID_FORMAT;
+    }
+
+    /* Sanity check - the expansion ratio should be much less than 2. */
+    Assert(cbCompSize < 2 * cbToRead);
+    if (cbCompSize >= 2 * cbToRead)
+        return VERR_VD_VMDK_INVALID_FORMAT;
+
+    /* Compressed grain marker. Data follows immediately. */
+    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
+                               uOffset + RT_OFFSETOF(VMDKMARKER, uType),
+                                (uint8_t *)pExtent->pvCompGrain
+                              + RT_OFFSETOF(VMDKMARKER, uType),
+                               RT_ALIGN_Z(  cbCompSize
+                                          + RT_OFFSETOF(VMDKMARKER, uType),
+                                          512)
+                               - RT_OFFSETOF(VMDKMARKER, uType));
+
+    if (puLBA)
+        *puLBA = RT_LE2H_U64(pMarker->uSector);
+    if (pcbMarkerData)
+        *pcbMarkerData = RT_ALIGN(  cbCompSize
+                                  + RT_OFFSETOF(VMDKMARKER, uType),
+                                  512);
+
+    VMDKCOMPRESSIO InflateState;
+    InflateState.pImage = pImage;
+    InflateState.iOffset = -1;
+    InflateState.cbCompGrain = cbCompSize + RT_OFFSETOF(VMDKMARKER, uType);
+    InflateState.pvCompGrain = pExtent->pvCompGrain;
+
+    rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper);
+    if (RT_FAILURE(rc))
         return rc;
-    }
+    rc = RTZipDecompress(pZip, pvBuf, cbToRead, &cbActuallyRead);
+    RTZipDecompDestroy(pZip);
+    if (RT_FAILURE(rc))
+    {
+        if (rc == VERR_ZIP_CORRUPTED)
+            rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: Compressed image is corrupted '%s'"), pExtent->pszFullname);
+        return rc;
+    }
+    if (cbActuallyRead != cbToRead)
+        rc = VERR_VD_VMDK_INVALID_FORMAT;
+    return rc;
 }
 
@@ -789,58 +779,50 @@
                                     uint32_t *pcbMarkerData)
 {
-    if (pExtent->pFile->fAsyncIO)
-    {
-        AssertMsgFailed(("TODO\n"));
-        return VERR_NOT_SUPPORTED;
-    }
-    else
-    {
-        int rc;
-        PRTZIPCOMP pZip = NULL;
-        VMDKCOMPRESSIO DeflateState;
-
-        DeflateState.pImage = pImage;
-        DeflateState.iOffset = -1;
-        DeflateState.cbCompGrain = pExtent->cbCompGrain;
-        DeflateState.pvCompGrain = pExtent->pvCompGrain;
-
-        rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper,
-                             RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT);
+    int rc;
+    PRTZIPCOMP pZip = NULL;
+    VMDKCOMPRESSIO DeflateState;
+
+    DeflateState.pImage = pImage;
+    DeflateState.iOffset = -1;
+    DeflateState.cbCompGrain = pExtent->cbCompGrain;
+    DeflateState.pvCompGrain = pExtent->pvCompGrain;
+
+    rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper,
+                         RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT);
+    if (RT_FAILURE(rc))
+        return rc;
+    rc = RTZipCompress(pZip, pvBuf, cbToWrite);
+    if (RT_SUCCESS(rc))
+        rc = RTZipCompFinish(pZip);
+    RTZipCompDestroy(pZip);
+    if (RT_SUCCESS(rc))
+    {
+        Assert(   DeflateState.iOffset > 0
+               && (size_t)DeflateState.iOffset <= DeflateState.cbCompGrain);
+
+        /* pad with zeroes to get to a full sector size */
+        uint32_t uSize = DeflateState.iOffset;
+        if (uSize % 512)
+        {
+            uint32_t uSizeAlign = RT_ALIGN(uSize, 512);
+            memset((uint8_t *)pExtent->pvCompGrain + uSize, '\0',
+                   uSizeAlign - uSize);
+            uSize = uSizeAlign;
+        }
+
+        if (pcbMarkerData)
+            *pcbMarkerData = uSize;
+
+        /* Compressed grain marker. Data follows immediately. */
+        VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
+        pMarker->uSector = RT_H2LE_U64(uLBA);
+        pMarker->cbSize = RT_H2LE_U32(  DeflateState.iOffset
+                                      - RT_OFFSETOF(VMDKMARKER, uType));
+        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
+                                    uOffset, pMarker, uSize);
         if (RT_FAILURE(rc))
             return rc;
-        rc = RTZipCompress(pZip, pvBuf, cbToWrite);
-        if (RT_SUCCESS(rc))
-            rc = RTZipCompFinish(pZip);
-        RTZipCompDestroy(pZip);
-        if (RT_SUCCESS(rc))
-        {
-            Assert(   DeflateState.iOffset > 0
-                   && (size_t)DeflateState.iOffset <= DeflateState.cbCompGrain);
-
-            /* pad with zeroes to get to a full sector size */
-            uint32_t uSize = DeflateState.iOffset;
-            if (uSize % 512)
-            {
-                uint32_t uSizeAlign = RT_ALIGN(uSize, 512);
-                memset((uint8_t *)pExtent->pvCompGrain + uSize, '\0',
-                       uSizeAlign - uSize);
-                uSize = uSizeAlign;
-            }
-
-            if (pcbMarkerData)
-                *pcbMarkerData = uSize;
-
-            /* Compressed grain marker. Data follows immediately. */
-            VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
-            pMarker->uSector = RT_H2LE_U64(uLBA);
-            pMarker->cbSize = RT_H2LE_U32(  DeflateState.iOffset
-                                          - RT_OFFSETOF(VMDKMARKER, uType));
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                        uOffset, pMarker, uSize);
-            if (RT_FAILURE(rc))
-                return rc;
-        }
-        return rc;
-    }
+    }
+    return rc;
 }
 
@@ -2430,5 +2412,5 @@
  * Internal: write/update the descriptor part of the image.
  */
-static int vmdkWriteDescriptor(PVMDKIMAGE pImage)
+static int vmdkWriteDescriptor(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
 {
     int rc = VINF_SUCCESS;
@@ -2436,59 +2418,5 @@
     uint64_t uOffset;
     PVMDKFILE pDescFile;
-    void *pvDescriptor;
-    size_t cbDescriptor;
-
-    if (pImage->pDescData)
-    {
-        /* Separate descriptor file. */
-        uOffset = 0;
-        cbLimit = 0;
-        pDescFile = pImage->pFile;
-    }
-    else
-    {
-        /* Embedded descriptor file. */
-        uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector);
-        cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
-        pDescFile = pImage->pExtents[0].pFile;
-    }
-    /* Bail out if there is no file to write to. */
-    if (pDescFile == NULL)
-        return VERR_INVALID_PARAMETER;
-
-    rc = vmdkDescriptorPrepare(pImage, cbLimit, &pvDescriptor, &cbDescriptor);
-    if (RT_SUCCESS(rc))
-    {
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pDescFile->pStorage, uOffset,
-                                    pvDescriptor, cbLimit ? cbLimit : cbDescriptor);
-        if (RT_FAILURE(rc))
-            rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
-
-        if (RT_SUCCESS(rc) && !cbLimit)
-        {
-            rc = vdIfIoIntFileSetSize(pImage->pIfIo, pDescFile->pStorage, cbDescriptor);
-            if (RT_FAILURE(rc))
-                rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
-        }
-
-        if (RT_SUCCESS(rc))
-            pImage->Descriptor.fDirty = false;
-
-        RTMemFree(pvDescriptor);
-    }
-
-    return rc;
-}
-
-/**
- * Internal: write/update the descriptor part of the image - async version.
- */
-static int vmdkWriteDescriptorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
-{
-    int rc = VINF_SUCCESS;
-    uint64_t cbLimit;
-    uint64_t uOffset;
-    PVMDKFILE pDescFile;
-    void *pvDescriptor;
+    void *pvDescriptor = NULL;
     size_t cbDescriptor;
 
@@ -2533,5 +2461,6 @@
         pImage->Descriptor.fDirty = false;
 
-    RTMemFree(pvDescriptor);
+    if (pvDescriptor)
+        RTMemFree(pvDescriptor);
     return rc;
 
@@ -2781,5 +2710,5 @@
  */
 static int vmdkWriteMetaSparseExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                                     uint64_t uOffset)
+                                     uint64_t uOffset, PVDIOCTX pIoCtx)
 {
     SparseExtentHeader Header;
@@ -2832,67 +2761,4 @@
     Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
 
-    int rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                    uOffset, &Header, sizeof(Header));
-    AssertRC(rc);
-    if (RT_FAILURE(rc))
-        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname);
-    return rc;
-}
-
-/**
- * Internal: write/update the metadata for a sparse extent - async version.
- */
-static int vmdkWriteMetaSparseExtentAsync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                                          uint64_t uOffset, PVDIOCTX pIoCtx)
-{
-    SparseExtentHeader Header;
-
-    memset(&Header, '\0', sizeof(Header));
-    Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
-    Header.version = RT_H2LE_U32(pExtent->uVersion);
-    Header.flags = RT_H2LE_U32(RT_BIT(0));
-    if (pExtent->pRGD)
-        Header.flags |= RT_H2LE_U32(RT_BIT(1));
-    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
-        Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17));
-    Header.capacity = RT_H2LE_U64(pExtent->cSectors);
-    Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
-    Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector);
-    Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
-    Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
-    if (pExtent->fFooter && uOffset == 0)
-    {
-        if (pExtent->pRGD)
-        {
-            Assert(pExtent->uSectorRGD);
-            Header.rgdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
-            Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
-        }
-        else
-        {
-            Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
-        }
-    }
-    else
-    {
-        if (pExtent->pRGD)
-        {
-            Assert(pExtent->uSectorRGD);
-            Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
-            Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
-        }
-        else
-        {
-            Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
-        }
-    }
-    Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
-    Header.uncleanShutdown = pExtent->fUncleanShutdown;
-    Header.singleEndLineChar = '\n';
-    Header.nonEndLineChar = ' ';
-    Header.doubleEndLineChar1 = '\r';
-    Header.doubleEndLineChar2 = '\n';
-    Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
-
     int rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pExtent->pFile->pStorage,
                                     uOffset, &Header, sizeof(Header),
@@ -3116,6 +2982,5 @@
 
     rc = vmdkFileOpen(pImage, &pFile, pImage->pszFilename,
-                      VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */),
-                      false /* fAsyncIO */);
+                      VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));
     if (RT_FAILURE(rc))
     {
@@ -3357,6 +3222,5 @@
                     rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                                       VDOpenFlagsToFileOpenFlags(uOpenFlags,
-                                                                 false /* fCreate */),
-                                      false /* fAsyncIO */);
+                                                                 false /* fCreate */));
                     if (RT_FAILURE(rc))
                     {
@@ -3385,6 +3249,5 @@
                     rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                                       VDOpenFlagsToFileOpenFlags(uOpenFlags,
-                                                                 false /* fCreate */),
-                                      true /* fAsyncIO */);
+                                                                 false /* fCreate */));
                     if (RT_FAILURE(rc))
                     {
@@ -3423,5 +3286,5 @@
 
     /* Update the image metadata now in case has changed. */
-    rc = vmdkFlushImage(pImage);
+    rc = vmdkFlushImage(pImage, NULL);
     if (RT_FAILURE(rc))
         goto out;
@@ -3488,6 +3351,5 @@
         rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
                           VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
-                                                     true /* fCreate */),
-                          false /* fAsyncIO */);
+                                                     true /* fCreate */));
         if (RT_FAILURE(rc))
             return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
@@ -3513,6 +3375,5 @@
         rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                           VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
-                                                     false /* fCreate */),
-                          false /* fAsyncIO */);
+                                                     false /* fCreate */));
         if (RT_FAILURE(rc))
             return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
@@ -3551,6 +3412,5 @@
         rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
                           VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
-                                                     true /* fCreate */),
-                          false /* fAsyncIO */);
+                                                     true /* fCreate */));
         if (RT_FAILURE(rc))
             return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
@@ -3623,6 +3483,5 @@
                 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                                   VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
-                                                             true /* fCreate */),
-                                  false /* fAsyncIO */);
+                                                             true /* fCreate */));
                 if (RT_FAILURE(rc))
                     return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
@@ -3659,6 +3518,5 @@
                     rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                                       VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
-                                                                 false /* fCreate */),
-                                      false /* fAsyncIO */);
+                                                                 false /* fCreate */));
                     if (RT_FAILURE(rc))
                         return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
@@ -3733,6 +3591,5 @@
         rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
                           VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
-                                                     true /* fCreate */),
-                          false /* fAsyncIO */);
+                                                     true /* fCreate */));
         if (RT_FAILURE(rc))
             return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename);
@@ -3804,6 +3661,5 @@
         rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                           VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
-                                                     true /* fCreate */),
-                          false /* fAsyncIO */);
+                                                     true /* fCreate */));
         if (RT_FAILURE(rc))
             return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
@@ -4003,6 +3859,5 @@
                         VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
                                                    true /* fCreate */)
-                      & ~RTFILE_O_READ,
-                      false /* fAsyncIO */);
+                      & ~RTFILE_O_READ);
     if (RT_FAILURE(rc))
         return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
@@ -4209,5 +4064,5 @@
         pImage->pExtents[0].cDescriptorSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(  pImage->Descriptor.aLines[pImage->Descriptor.cLines]
                                                                               - pImage->Descriptor.aLines[0], 512));
-        rc = vmdkWriteMetaSparseExtent(pImage, &pImage->pExtents[0], 0);
+        rc = vmdkWriteMetaSparseExtent(pImage, &pImage->pExtents[0], 0, NULL);
         if (RT_FAILURE(rc))
         {
@@ -4216,5 +4071,5 @@
         }
 
-        rc = vmdkWriteDescriptor(pImage);
+        rc = vmdkWriteDescriptor(pImage, NULL);
         if (RT_FAILURE(rc))
         {
@@ -4224,5 +4079,5 @@
     }
     else
-        rc = vmdkFlushImage(pImage);
+        rc = vmdkFlushImage(pImage, NULL);
 
 out:
@@ -4449,5 +4304,5 @@
 
                 uFileOffset += 512;
-                rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
+                rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset, NULL);
                 AssertRC(rc);
 
@@ -4461,5 +4316,5 @@
         }
         else
-            vmdkFlushImage(pImage);
+            vmdkFlushImage(pImage, NULL);
 
         if (pImage->pExtents != NULL)
@@ -4494,5 +4349,5 @@
  * Internal. Flush image data (and metadata) to disk.
  */
-static int vmdkFlushImage(PVMDKIMAGE pImage)
+static int vmdkFlushImage(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
 {
     PVMDKEXTENT pExtent;
@@ -4502,5 +4357,5 @@
     if (pImage->Descriptor.fDirty)
     {
-        rc = vmdkWriteDescriptor(pImage);
+        rc = vmdkWriteDescriptor(pImage, pIoCtx);
         if (RT_FAILURE(rc))
             goto out;
@@ -4517,5 +4372,5 @@
                     if (!pExtent->fFooter)
                     {
-                        rc = vmdkWriteMetaSparseExtent(pImage, pExtent, 0);
+                        rc = vmdkWriteMetaSparseExtent(pImage, pExtent, 0, pIoCtx);
                         if (RT_FAILURE(rc))
                             goto out;
@@ -4530,5 +4385,5 @@
                         uFileOffset = RT_ALIGN_64(uFileOffset, 512);
                         rc = vmdkWriteMetaSparseExtent(pImage, pExtent,
-                                                       uFileOffset);
+                                                       uFileOffset, pIoCtx);
                         if (RT_FAILURE(rc))
                             goto out;
@@ -4563,5 +4418,6 @@
                     && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
                     && !(pExtent->pszBasename[0] == RTPATH_SLASH))
-                    rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pExtent->pFile->pStorage);
+                    rc = vdIfIoIntFileFlush(pImage->pIfIo, pExtent->pFile->pStorage, pIoCtx,
+                                            NULL, NULL);
                 break;
             case VMDKETYPE_ZERO:
@@ -4621,6 +4477,7 @@
  * number in the extent.
  */
-static int vmdkGetSector(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                         uint64_t uSector, uint64_t *puExtentSector)
+static int vmdkGetSector(PVMDKIMAGE pImage, PVDIOCTX pIoCtx,
+                         PVMDKEXTENT pExtent, uint64_t uSector,
+                         uint64_t *puExtentSector)
 {
     PVMDKGTCACHE pCache = pImage->pGTCache;
@@ -4642,57 +4499,4 @@
         return VINF_SUCCESS;
     }
-
-    uGDIndex = uSector / pExtent->cSectorsPerGDE;
-    if (uGDIndex >= pExtent->cGDEntries)
-        return VERR_OUT_OF_RANGE;
-    uGTSector = pExtent->pGD[uGDIndex];
-    if (!uGTSector)
-    {
-        /* There is no grain table referenced by this grain directory
-         * entry. So there is absolutely no data in this area. */
-        *puExtentSector = 0;
-        return VINF_SUCCESS;
-    }
-
-    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
-    uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
-    pGTCacheEntry = &pCache->aGTCache[uGTHash];
-    if (    pGTCacheEntry->uExtent != pExtent->uExtent
-        ||  pGTCacheEntry->uGTBlock != uGTBlock)
-    {
-        /* Cache miss, fetch data from disk. */
-        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                   VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                                   aGTDataTmp, sizeof(aGTDataTmp));
-        if (RT_FAILURE(rc))
-            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
-        pGTCacheEntry->uExtent = pExtent->uExtent;
-        pGTCacheEntry->uGTBlock = uGTBlock;
-        for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
-            pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
-    }
-    uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
-    uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
-    if (uGrainSector)
-        *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
-    else
-        *puExtentSector = 0;
-    return VINF_SUCCESS;
-}
-
-/**
- * Internal. Get sector number in the extent file from the relative sector
- * number in the extent - version for async access.
- */
-static int vmdkGetSectorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx,
-                              PVMDKEXTENT pExtent, uint64_t uSector,
-                              uint64_t *puExtentSector)
-{
-    PVMDKGTCACHE pCache = pImage->pGTCache;
-    uint64_t uGDIndex, uGTSector, uGTBlock;
-    uint32_t uGTHash, uGTBlockIndex;
-    PVMDKGTCACHEENTRY pGTCacheEntry;
-    uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
-    int rc;
 
     uGDIndex = uSector / pExtent->cSectorsPerGDE;
@@ -4738,225 +4542,9 @@
 
 /**
- * Internal. Allocates a new grain table (if necessary), writes the grain
- * and updates the grain table. The cache is also updated by this operation.
- * This is separate from vmdkGetSector, because that should be as fast as
- * possible. Most code from vmdkGetSector also appears here.
- */
-static int vmdkAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                          uint64_t uSector, const void *pvBuf,
-                          uint64_t cbWrite)
-{
-    PVMDKGTCACHE pCache = pImage->pGTCache;
-    uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
-    uint64_t uFileOffset;
-    uint32_t uGTHash, uGTBlockIndex;
-    PVMDKGTCACHEENTRY pGTCacheEntry;
-    uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
-    int rc;
-
-    uGDIndex = uSector / pExtent->cSectorsPerGDE;
-    if (uGDIndex >= pExtent->cGDEntries)
-        return VERR_OUT_OF_RANGE;
-    uGTSector = pExtent->pGD[uGDIndex];
-    if (pExtent->pRGD)
-        uRGTSector = pExtent->pRGD[uGDIndex];
-    else
-        uRGTSector = 0; /**< avoid compiler warning */
-    if (!uGTSector)
-    {
-        /* There is no grain table referenced by this grain directory
-         * entry. So there is absolutely no data in this area. Allocate
-         * a new grain table and put the reference to it in the GDs. */
-        uFileOffset = pExtent->uAppendPosition;
-        if (!uFileOffset)
-            return VERR_INTERNAL_ERROR;
-        Assert(!(uFileOffset % 512));
-        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
-        uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
-
-        pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
-
-        /* Normally the grain table is preallocated for hosted sparse extents
-         * that support more than 32 bit sector numbers. So this shouldn't
-         * ever happen on a valid extent. */
-        if (uGTSector > UINT32_MAX)
-            return VERR_VD_VMDK_INVALID_HEADER;
-
-        /* Write grain table by writing the required number of grain table
-         * cache chunks. Avoids dynamic memory allocation, but is a bit
-         * slower. But as this is a pretty infrequently occurring case it
-         * should be acceptable. */
-        memset(aGTDataTmp, '\0', sizeof(aGTDataTmp));
-        for (unsigned i = 0;
-             i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
-             i++)
-        {
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                        VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
-                                        aGTDataTmp, sizeof(aGTDataTmp));
-            if (RT_FAILURE(rc))
-                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
-        }
-        pExtent->uAppendPosition = RT_ALIGN_64(  pExtent->uAppendPosition
-                                               + pExtent->cGTEntries * sizeof(uint32_t),
-                                               512);
-
-        if (pExtent->pRGD)
-        {
-            AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
-            uFileOffset = pExtent->uAppendPosition;
-            if (!uFileOffset)
-                return VERR_INTERNAL_ERROR;
-            Assert(!(uFileOffset % 512));
-            uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
-
-            pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
-
-            /* Normally the redundant grain table is preallocated for hosted
-             * sparse extents that support more than 32 bit sector numbers. So
-             * this shouldn't ever happen on a valid extent. */
-            if (uRGTSector > UINT32_MAX)
-                return VERR_VD_VMDK_INVALID_HEADER;
-
-            /* Write backup grain table by writing the required number of grain
-             * table cache chunks. Avoids dynamic memory allocation, but is a
-             * bit slower. But as this is a pretty infrequently occurring case
-             * it should be acceptable. */
-            for (unsigned i = 0;
-                 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
-                 i++)
-            {
-                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                            VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
-                                            aGTDataTmp, sizeof(aGTDataTmp));
-                if (RT_FAILURE(rc))
-                    return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
-            }
-
-            pExtent->uAppendPosition =   pExtent->uAppendPosition
-                                       + pExtent->cGTEntries * sizeof(uint32_t);
-        }
-
-        /* Update the grain directory on disk (doing it before writing the
-         * grain table will result in a garbled extent if the operation is
-         * aborted for some reason. Otherwise the worst that can happen is
-         * some unused sectors in the extent. */
-        uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                    VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
-                                    &uGTSectorLE, sizeof(uGTSectorLE));
-        if (RT_FAILURE(rc))
-            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
-        if (pExtent->pRGD)
-        {
-            uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                        VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
-                                        &uRGTSectorLE, sizeof(uRGTSectorLE));
-            if (RT_FAILURE(rc))
-                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
-        }
-
-        /* As the final step update the in-memory copy of the GDs. */
-        pExtent->pGD[uGDIndex] = uGTSector;
-        if (pExtent->pRGD)
-            pExtent->pRGD[uGDIndex] = uRGTSector;
-    }
-
-    uFileOffset = pExtent->uAppendPosition;
-    if (!uFileOffset)
-        return VERR_INTERNAL_ERROR;
-    Assert(!(uFileOffset % 512));
-
-    /* Write the data. Always a full grain, or we're in big trouble. */
-    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
-    {
-        if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
-            return vdIfError(pImage->pIfError, VERR_INTERNAL_ERROR, RT_SRC_POS, N_("VMDK: not enough data for a compressed data block in '%s'"), pExtent->pszFullname);
-
-        /* Invalidate cache, just in case some code incorrectly allows mixing
-         * of reads and writes. Normally shouldn't be needed. */
-        pExtent->uGrainSectorAbs = 0;
-
-        /* Write compressed data block and the markers. */
-        uint32_t cbGrain = 0;
-        rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset,
-                                 pvBuf, cbWrite, uSector, &cbGrain);
-        if (RT_FAILURE(rc))
-        {
-            AssertRC(rc);
-            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated compressed data block in '%s'"), pExtent->pszFullname);
-        }
-        pExtent->uLastGrainAccess = uSector / pExtent->cSectorsPerGrain;
-        pExtent->uAppendPosition += cbGrain;
-    }
-    else
-    {
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                    uFileOffset, pvBuf, cbWrite);
-        if (RT_FAILURE(rc))
-            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
-        pExtent->uAppendPosition += cbWrite;
-    }
-
-    /* Update the grain table (and the cache). */
-    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
-    uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
-    pGTCacheEntry = &pCache->aGTCache[uGTHash];
-    if (    pGTCacheEntry->uExtent != pExtent->uExtent
-        ||  pGTCacheEntry->uGTBlock != uGTBlock)
-    {
-        /* Cache miss, fetch data from disk. */
-        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                   VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                                   aGTDataTmp, sizeof(aGTDataTmp));
-        if (RT_FAILURE(rc))
-            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
-        pGTCacheEntry->uExtent = pExtent->uExtent;
-        pGTCacheEntry->uGTBlock = uGTBlock;
-        for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
-            pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
-    }
-    else
-    {
-        /* Cache hit. Convert grain table block back to disk format, otherwise
-         * the code below will write garbage for all but the updated entry. */
-        for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
-            aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
-    }
-    uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
-    aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(uFileOffset));
-    pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(uFileOffset);
-    /* Update grain table on disk. */
-    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                                aGTDataTmp, sizeof(aGTDataTmp));
-    if (RT_FAILURE(rc))
-        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
-    if (pExtent->pRGD)
-    {
-        /* Update backup grain table on disk. */
-        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
-                                    VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                                    aGTDataTmp, sizeof(aGTDataTmp));
-        if (RT_FAILURE(rc))
-            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
-    }
-#ifdef VBOX_WITH_VMDK_ESX
-    if (RT_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
-    {
-        pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
-        pExtent->fMetaDirty = true;
-    }
-#endif /* VBOX_WITH_VMDK_ESX */
-    return rc;
-}
-
-/**
  * Internal. Writes the grain and also if necessary the grain tables.
  * Uses the grain table cache as a true grain table.
  */
 static int vmdkStreamAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                                uint64_t uSector, const void *pvBuf,
+                                uint64_t uSector, PVDIOCTX pIoCtx,
                                 uint64_t cbWrite)
 {
@@ -4965,5 +4553,5 @@
     uint32_t cbGrain = 0;
     uint32_t uCacheLine, uCacheEntry;
-    const void *pData = pvBuf;
+    const void *pData;
     int rc;
 
@@ -4996,5 +4584,5 @@
      * to allocate something, we also need to detect the situation ourself. */
     if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
-        && ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbWrite * 8) == -1)
+        && vdIfIoIntIoCtxIsZero(pImage->pIfIo, pIoCtx, cbWrite, true /* fAdvance */))
         return VINF_SUCCESS;
 
@@ -5033,9 +4621,20 @@
     if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
     {
-        memcpy(pExtent->pvGrain, pvBuf, cbWrite);
+        vdIfIoIntIoCtxCopyFrom(pImage->pIfIo, pIoCtx, pExtent->pvGrain, cbWrite);
         memset((char *)pExtent->pvGrain + cbWrite, '\0',
                VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite);
         pData = pExtent->pvGrain;
     }
+    else
+    {
+        RTSGSEG Segment;
+        unsigned cSegments = 1;
+        size_t cbSeg = 0;
+
+        cbSeg = vdIfIoIntIoCtxSegArrayCreate(pImage->pIfIo, pIoCtx, &Segment,
+                                             &cSegments, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
+        Assert(cbSeg == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
+        pData = Segment.pvSeg;
+    }
     rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset, pData,
                              VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
@@ -5054,9 +4653,8 @@
 
 /**
- * Internal: Updates the grain table during a async grain allocation.
+ * Internal: Updates the grain table during grain allocation.
  */
-static int vmdkAllocGrainAsyncGTUpdate(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                                       PVDIOCTX pIoCtx,
-                                       PVMDKGRAINALLOCASYNC pGrainAlloc)
+static int vmdkAllocGrainGTUpdate(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, PVDIOCTX pIoCtx,
+                                  PVMDKGRAINALLOCASYNC pGrainAlloc)
 {
     int rc = VINF_SUCCESS;
@@ -5088,5 +4686,5 @@
                                    VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
                                    aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
-                                   &pMetaXfer, vmdkAllocGrainAsyncComplete, pGrainAlloc);
+                                   &pMetaXfer, vmdkAllocGrainComplete, pGrainAlloc);
         if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
         {
@@ -5120,5 +4718,5 @@
                                 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
                                 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
-                                vmdkAllocGrainAsyncComplete, pGrainAlloc);
+                                vmdkAllocGrainComplete, pGrainAlloc);
     if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
         pGrainAlloc->cIoXfersPending++;
@@ -5131,5 +4729,5 @@
                                     VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
                                     aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
-                                    vmdkAllocGrainAsyncComplete, pGrainAlloc);
+                                    vmdkAllocGrainComplete, pGrainAlloc);
         if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
             pGrainAlloc->cIoXfersPending++;
@@ -5153,5 +4751,5 @@
  * Internal - complete the grain allocation by updating disk grain table if required.
  */
-static int vmdkAllocGrainAsyncComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
+static int vmdkAllocGrainComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
 {
     int rc = VINF_SUCCESS;
@@ -5165,6 +4763,5 @@
     pGrainAlloc->cIoXfersPending--;
     if (!pGrainAlloc->cIoXfersPending && pGrainAlloc->fGTUpdateNeeded)
-        rc = vmdkAllocGrainAsyncGTUpdate(pImage, pGrainAlloc->pExtent,
-                                         pIoCtx, pGrainAlloc);
+        rc = vmdkAllocGrainGTUpdate(pImage, pGrainAlloc->pExtent, pIoCtx, pGrainAlloc);
 
     if (!pGrainAlloc->cIoXfersPending)
@@ -5179,9 +4776,8 @@
 
 /**
- * Internal. Allocates a new grain table (if necessary) - async version.
+ * Internal. Allocates a new grain table (if necessary).
  */
-static int vmdkAllocGrainAsync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                               PVDIOCTX pIoCtx, uint64_t uSector,
-                               uint64_t cbWrite)
+static int vmdkAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, PVDIOCTX pIoCtx,
+                          uint64_t uSector, uint64_t cbWrite)
 {
     PVMDKGTCACHE pCache = pImage->pGTCache;
@@ -5193,6 +4789,4 @@
     LogFlowFunc(("pCache=%#p pExtent=%#p pIoCtx=%#p uSector=%llu cbWrite=%llu\n",
                  pCache, pExtent, pIoCtx, uSector, cbWrite));
-
-    AssertReturn(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), VERR_NOT_SUPPORTED);
 
     pGrainAlloc = (PVMDKGRAINALLOCASYNC)RTMemAllocZ(sizeof(VMDKGRAINALLOCASYNC));
@@ -5248,5 +4842,5 @@
                                     VMDK_SECTOR2BYTE(uGTSector),
                                     paGTDataTmp, cbGTDataTmp, pIoCtx,
-                                    vmdkAllocGrainAsyncComplete, pGrainAlloc);
+                                    vmdkAllocGrainComplete, pGrainAlloc);
         if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
             pGrainAlloc->cIoXfersPending++;
@@ -5283,5 +4877,5 @@
                                         VMDK_SECTOR2BYTE(uRGTSector),
                                         paGTDataTmp, cbGTDataTmp, pIoCtx,
-                                        vmdkAllocGrainAsyncComplete, pGrainAlloc);
+                                        vmdkAllocGrainComplete, pGrainAlloc);
             if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
                 pGrainAlloc->cIoXfersPending++;
@@ -5305,5 +4899,5 @@
                                     VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
                                     &uGTSectorLE, sizeof(uGTSectorLE), pIoCtx,
-                                    vmdkAllocGrainAsyncComplete, pGrainAlloc);
+                                    vmdkAllocGrainComplete, pGrainAlloc);
         if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
             pGrainAlloc->cIoXfersPending++;
@@ -5316,5 +4910,5 @@
                                         VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uGTSectorLE),
                                         &uRGTSectorLE, sizeof(uRGTSectorLE), pIoCtx,
-                                        vmdkAllocGrainAsyncComplete, pGrainAlloc);
+                                        vmdkAllocGrainComplete, pGrainAlloc);
             if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
                 pGrainAlloc->cIoXfersPending++;
@@ -5340,16 +4934,52 @@
     pGrainAlloc->uGrainOffset = uFileOffset;
 
-    /* Write the data. Always a full grain, or we're in big trouble. */
-    rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pExtent->pFile->pStorage,
-                                uFileOffset, pIoCtx, cbWrite,
-                                vmdkAllocGrainAsyncComplete, pGrainAlloc);
-    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
-        pGrainAlloc->cIoXfersPending++;
-    else if (RT_FAILURE(rc))
-        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
-
-    pExtent->uAppendPosition += cbWrite;
-
-    rc = vmdkAllocGrainAsyncGTUpdate(pImage, pExtent, pIoCtx, pGrainAlloc);
+    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
+    {
+        AssertMsgReturn(vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx),
+                        ("Accesses to stream optimized images must be synchronous\n"),
+                        VERR_INVALID_STATE);
+
+        if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
+            return vdIfError(pImage->pIfError, VERR_INTERNAL_ERROR, RT_SRC_POS, N_("VMDK: not enough data for a compressed data block in '%s'"), pExtent->pszFullname);
+
+        /* Invalidate cache, just in case some code incorrectly allows mixing
+         * of reads and writes. Normally shouldn't be needed. */
+        pExtent->uGrainSectorAbs = 0;
+
+        /* Write compressed data block and the markers. */
+        uint32_t cbGrain = 0;
+        size_t cbSeg = 0;
+        RTSGSEG Segment;
+        unsigned cSegments = 1;
+
+        cbSeg = vdIfIoIntIoCtxSegArrayCreate(pImage->pIfIo, pIoCtx, &Segment,
+                                             &cSegments, cbWrite);
+        Assert(cbSeg == cbWrite);
+
+        rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset,
+                                 Segment.pvSeg, cbWrite, uSector, &cbGrain);
+        if (RT_FAILURE(rc))
+        {
+            AssertRC(rc);
+            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated compressed data block in '%s'"), pExtent->pszFullname);
+        }
+        pExtent->uLastGrainAccess = uSector / pExtent->cSectorsPerGrain;
+        pExtent->uAppendPosition += cbGrain;
+    }
+    else
+    {
+        /* Write the data. Always a full grain, or we're in big trouble. */
+        rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pExtent->pFile->pStorage,
+                                    uFileOffset, pIoCtx, cbWrite,
+                                    vmdkAllocGrainComplete, pGrainAlloc);
+        if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+            pGrainAlloc->cIoXfersPending++;
+        else if (RT_FAILURE(rc))
+            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
+
+        pExtent->uAppendPosition += cbWrite;
+    }
+
+    rc = vmdkAllocGrainGTUpdate(pImage, pExtent, pIoCtx, pGrainAlloc);
 
     if (!pGrainAlloc->cIoXfersPending)
@@ -5369,11 +4999,15 @@
  */
 static int vmdkStreamReadSequential(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
-                                    uint64_t uSector, void *pvBuf,
+                                    uint64_t uSector, PVDIOCTX pIoCtx,
                                     uint64_t cbRead)
 {
     int rc;
 
-    LogFlowFunc(("pImage=%#p pExtent=%#p uSector=%llu pvBuf=%#p cbRead=%llu\n",
-                 pImage, pExtent, uSector, pvBuf, cbRead));
+    LogFlowFunc(("pImage=%#p pExtent=%#p uSector=%llu pIoCtx=%#p cbRead=%llu\n",
+                 pImage, pExtent, uSector, pIoCtx, cbRead));
+
+    AssertMsgReturn(vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx),
+                    ("Async I/O not supported for sequential stream optimized images\n"),
+                    VERR_INVALID_STATE);
 
     /* Do not allow to go back. */
@@ -5509,7 +5143,7 @@
 
     uint32_t uSectorInGrain = uSector % pExtent->cSectorsPerGrain;
-    memcpy(pvBuf,
-           (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain),
-           cbRead);
+    vdIfIoIntIoCtxCopyTo(pImage->pIfIo, pIoCtx,
+                         (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain),
+                         cbRead);
     LogFlowFunc(("returns VINF_SUCCESS\n"));
     return VINF_SUCCESS;
@@ -5871,5 +5505,5 @@
     pImage->Descriptor.fDirty = true;
     /* Flush the descriptor now, in case it is embedded. */
-    vmdkFlushImage(pImage);
+    vmdkFlushImage(pImage, NULL);
 
     /* Close and rename/move extents. */
@@ -5944,6 +5578,5 @@
         rrc = vmdkFileOpen(pImage, &pFile, pszOldDescName,
                            VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_NORMAL,
-                                                      false /* fCreate */),
-                           false /* fAsyncIO */);
+                                                      false /* fCreate */));
         AssertRC(rrc);
         if (fEmbeddedDesc)
@@ -5961,5 +5594,5 @@
         }
         pImage->Descriptor = DescriptorCopy;
-        vmdkWriteDescriptor(pImage);
+        vmdkWriteDescriptor(pImage, NULL);
         vmdkFileClose(pImage, &pFile, false);
         /* Get rid of the stuff we implanted. */
@@ -6027,8 +5660,9 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnRead */
-static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
-                    size_t cbToRead, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
+static int vmdkRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
+                    PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     PVMDKEXTENT pExtent;
@@ -6070,6 +5704,5 @@
         case VMDKETYPE_ESX_SPARSE:
 #endif /* VBOX_WITH_VMDK_ESX */
-            rc = vmdkGetSector(pImage, pExtent, uSectorExtentRel,
-                               &uSectorExtentAbs);
+            rc = vmdkGetSector(pImage, pIoCtx, pExtent, uSectorExtentRel, &uSectorExtentAbs);
             if (RT_FAILURE(rc))
                 goto out;
@@ -6086,5 +5719,5 @@
                     rc = vmdkStreamReadSequential(pImage, pExtent,
                                                   uSectorExtentRel,
-                                                  pvBuf, cbToRead);
+                                                  pIoCtx, cbToRead);
             }
             else
@@ -6092,4 +5725,7 @@
                 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
                 {
+                    AssertMsg(vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx),
+                              ("Async I/O is not supported for stream optimized VMDK's\n"));
+
                     uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
                     uSectorExtentAbs -= uSectorInGrain;
@@ -6112,22 +5748,28 @@
                         Assert(uLBA == uSectorExtentRel);
                     }
-                    memcpy(pvBuf, (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), cbToRead);
+                    vdIfIoIntIoCtxCopyTo(pImage->pIfIo, pIoCtx,
+                                           (uint8_t *)pExtent->pvGrain
+                                         + VMDK_SECTOR2BYTE(uSectorInGrain),
+                                         cbToRead);
                 }
                 else
-                {
-                    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
+                    rc = vdIfIoIntFileReadUser(pImage->pIfIo, pExtent->pFile->pStorage,
                                                VMDK_SECTOR2BYTE(uSectorExtentAbs),
-                                               pvBuf, cbToRead);
-                }
+                                               pIoCtx, cbToRead);
             }
             break;
         case VMDKETYPE_VMFS:
         case VMDKETYPE_FLAT:
-            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
+            rc = vdIfIoIntFileReadUser(pImage->pIfIo, pExtent->pFile->pStorage,
                                        VMDK_SECTOR2BYTE(uSectorExtentRel),
-                                       pvBuf, cbToRead);
+                                       pIoCtx, cbToRead);
             break;
         case VMDKETYPE_ZERO:
-            memset(pvBuf, '\0', cbToRead);
+            size_t cbSet;
+
+            cbSet = vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
+            Assert(cbSet == cbToRead);
+
+            rc = VINF_SUCCESS;
             break;
     }
@@ -6141,9 +5783,10 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
-                     size_t cbToWrite, size_t *pcbWriteProcess,
-                     size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
+static int vmdkWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
+                     PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+                     size_t *pcbPostRead, unsigned fWrite)
+{
+    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
+                 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     PVMDKEXTENT pExtent;
@@ -6197,6 +5840,5 @@
         case VMDKETYPE_ESX_SPARSE:
 #endif /* VBOX_WITH_VMDK_ESX */
-            rc = vmdkGetSector(pImage, pExtent, uSectorExtentRel,
-                               &uSectorExtentAbs);
+            rc = vmdkGetSector(pImage, pIoCtx, pExtent, uSectorExtentRel, &uSectorExtentAbs);
             if (RT_FAILURE(rc))
                 goto out;
@@ -6216,11 +5858,10 @@
                     {
                         /* Full block write to a previously unallocated block.
-                         * Check if the caller wants feedback. */
+                         * Check if the caller wants to avoid the automatic alloc. */
                         if (!(fWrite & VD_WRITE_NO_ALLOC))
                         {
-                            /* Allocate GT and store the grain. */
-                            rc = vmdkAllocGrain(pImage, pExtent,
-                                                uSectorExtentRel,
-                                                pvBuf, cbToWrite);
+                            /* Allocate GT and find out where to store the grain. */
+                            rc = vmdkAllocGrain(pImage, pExtent, pIoCtx,
+                                                uSectorExtentRel, cbToWrite);
                         }
                         else
@@ -6242,5 +5883,5 @@
                     rc = vmdkStreamAllocGrain(pImage, pExtent,
                                               uSectorExtentRel,
-                                              pvBuf, cbToWrite);
+                                              pIoCtx, cbToWrite);
                 }
             }
@@ -6258,7 +5899,8 @@
                 else
                 {
-                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
+                    Assert(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED));
+                    rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pExtent->pFile->pStorage,
                                                 VMDK_SECTOR2BYTE(uSectorExtentAbs),
-                                                pvBuf, cbToWrite);
+                                                pIoCtx, cbToWrite, NULL, NULL);
                 }
             }
@@ -6268,7 +5910,7 @@
             /* Clip write range to remain in this extent. */
             cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
-            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
+            rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pExtent->pFile->pStorage,
                                         VMDK_SECTOR2BYTE(uSectorExtentRel),
-                                        pvBuf, cbToWrite);
+                                        pIoCtx, cbToWrite, NULL, NULL);
             break;
         case VMDKETYPE_ZERO:
@@ -6287,17 +5929,9 @@
 
 /** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int vmdkFlush(void *pBackendData)
-{
-    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+static int vmdkFlush(void *pBackendData, PVDIOCTX pIoCtx)
+{
     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
-    int rc = VINF_SUCCESS;
-
-    AssertPtr(pImage);
-
-    if (!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
-        rc = vmdkFlushImage(pImage);
-
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
+
+    return vmdkFlushImage(pImage, pIoCtx);
 }
 
@@ -6876,305 +6510,4 @@
 }
 
-/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
-static int vmdkAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
-                         PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
-                 pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
-    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
-    PVMDKEXTENT pExtent;
-    uint64_t uSectorExtentRel;
-    uint64_t uSectorExtentAbs;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbRead % 512 == 0);
-
-    if (   uOffset + cbRead > pImage->cbSize
-        || cbRead == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
-                        &pExtent, &uSectorExtentRel);
-    if (RT_FAILURE(rc))
-        goto out;
-
-    /* Check access permissions as defined in the extent descriptor. */
-    if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
-    {
-        rc = VERR_VD_VMDK_INVALID_STATE;
-        goto out;
-    }
-
-    /* Clip read range to remain in this extent. */
-    cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
-
-    /* Handle the read according to the current extent type. */
-    switch (pExtent->enmType)
-    {
-        case VMDKETYPE_HOSTED_SPARSE:
-#ifdef VBOX_WITH_VMDK_ESX
-        case VMDKETYPE_ESX_SPARSE:
-#endif /* VBOX_WITH_VMDK_ESX */
-            rc = vmdkGetSectorAsync(pImage, pIoCtx, pExtent,
-                                    uSectorExtentRel, &uSectorExtentAbs);
-            if (RT_FAILURE(rc))
-                goto out;
-            /* Clip read range to at most the rest of the grain. */
-            cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
-            Assert(!(cbRead % 512));
-            if (uSectorExtentAbs == 0)
-                rc = VERR_VD_BLOCK_FREE;
-            else
-            {
-                AssertMsg(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), ("Async I/O is not supported for stream optimized VMDK's\n"));
-                rc = vdIfIoIntFileReadUser(pImage->pIfIo, pExtent->pFile->pStorage,
-                                           VMDK_SECTOR2BYTE(uSectorExtentAbs),
-                                           pIoCtx, cbRead);
-            }
-            break;
-        case VMDKETYPE_VMFS:
-        case VMDKETYPE_FLAT:
-            rc = vdIfIoIntFileReadUser(pImage->pIfIo, pExtent->pFile->pStorage,
-                                       VMDK_SECTOR2BYTE(uSectorExtentRel),
-                                       pIoCtx, cbRead);
-            break;
-        case VMDKETYPE_ZERO:
-            size_t cbSet;
-
-            cbSet = vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbRead);
-            Assert(cbSet == cbRead);
-
-            rc = VINF_SUCCESS;
-            break;
-    }
-    if (pcbActuallyRead)
-        *pcbActuallyRead = cbRead;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
-static int vmdkAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
-                          PVDIOCTX pIoCtx,
-                          size_t *pcbWriteProcess, size_t *pcbPreRead,
-                          size_t *pcbPostRead, unsigned fWrite)
-{
-    LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
-                 pBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
-    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
-    PVMDKEXTENT pExtent;
-    uint64_t uSectorExtentRel;
-    uint64_t uSectorExtentAbs;
-    int rc;
-
-    AssertPtr(pImage);
-    Assert(uOffset % 512 == 0);
-    Assert(cbWrite % 512 == 0);
-
-    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
-    {
-        rc = VERR_VD_IMAGE_READ_ONLY;
-        goto out;
-    }
-
-    if (cbWrite == 0)
-    {
-        rc = VERR_INVALID_PARAMETER;
-        goto out;
-    }
-
-    /* No size check here, will do that later when the extent is located.
-     * There are sparse images out there which according to the spec are
-     * invalid, because the total size is not a multiple of the grain size.
-     * Also for sparse images which are stitched together in odd ways (not at
-     * grain boundaries, and with the nominal size not being a multiple of the
-     * grain size), this would prevent writing to the last grain. */
-
-    rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
-                        &pExtent, &uSectorExtentRel);
-    if (RT_FAILURE(rc))
-        goto out;
-
-    /* Check access permissions as defined in the extent descriptor. */
-    if (pExtent->enmAccess != VMDKACCESS_READWRITE)
-    {
-        rc = VERR_VD_VMDK_INVALID_STATE;
-        goto out;
-    }
-
-    /* Handle the write according to the current extent type. */
-    switch (pExtent->enmType)
-    {
-        case VMDKETYPE_HOSTED_SPARSE:
-#ifdef VBOX_WITH_VMDK_ESX
-        case VMDKETYPE_ESX_SPARSE:
-#endif /* VBOX_WITH_VMDK_ESX */
-            rc = vmdkGetSectorAsync(pImage, pIoCtx, pExtent, uSectorExtentRel,
-                                    &uSectorExtentAbs);
-            if (RT_FAILURE(rc))
-                goto out;
-            /* Clip write range to at most the rest of the grain. */
-            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
-            if (    pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
-                &&  uSectorExtentRel < (uint64_t)pExtent->uLastGrainAccess * pExtent->cSectorsPerGrain)
-            {
-                rc = VERR_VD_VMDK_INVALID_WRITE;
-                goto out;
-            }
-            if (uSectorExtentAbs == 0)
-            {
-                if (cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
-                {
-                    /* Full block write to a previously unallocated block.
-                     * Check if the caller wants to avoid the automatic alloc. */
-                    if (!(fWrite & VD_WRITE_NO_ALLOC))
-                    {
-                        /* Allocate GT and find out where to store the grain. */
-                        rc = vmdkAllocGrainAsync(pImage, pExtent, pIoCtx,
-                                                 uSectorExtentRel, cbWrite);
-                    }
-                    else
-                        rc = VERR_VD_BLOCK_FREE;
-                    *pcbPreRead = 0;
-                    *pcbPostRead = 0;
-                }
-                else
-                {
-                    /* Clip write range to remain in this extent. */
-                    cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
-                    *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
-                    *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite - *pcbPreRead;
-                    rc = VERR_VD_BLOCK_FREE;
-                }
-            }
-            else
-            {
-                Assert(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED));
-                rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pExtent->pFile->pStorage,
-                                            VMDK_SECTOR2BYTE(uSectorExtentAbs),
-                                            pIoCtx, cbWrite, NULL, NULL);
-            }
-            break;
-        case VMDKETYPE_VMFS:
-        case VMDKETYPE_FLAT:
-            /* Clip write range to remain in this extent. */
-            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
-            rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pExtent->pFile->pStorage,
-                                        VMDK_SECTOR2BYTE(uSectorExtentRel),
-                                        pIoCtx, cbWrite, NULL, NULL);
-            break;
-        case VMDKETYPE_ZERO:
-            /* Clip write range to remain in this extent. */
-            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
-            break;
-    }
-
-    if (pcbWriteProcess)
-        *pcbWriteProcess = cbWrite;
-
-out:
-    LogFlowFunc(("returns %Rrc\n", rc));
-    return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
-static int vmdkAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
-{
-    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
-    PVMDKEXTENT pExtent;
-    int rc = VINF_SUCCESS;
-
-    /* Update descriptor if changed. */
-    /** @todo: The descriptor is never updated because
-     * it remains unchanged during normal operation (only vmdkRename updates it).
-     * So this part is actually not tested so far and requires testing as soon
-     * as the descriptor might change during async I/O.
-     */
-    if (pImage->Descriptor.fDirty)
-    {
-        rc = vmdkWriteDescriptorAsync(pImage, pIoCtx);
-        if (   RT_FAILURE(rc)
-            && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
-            goto out;
-    }
-
-    for (unsigned i = 0; i < pImage->cExtents; i++)
-    {
-        pExtent = &pImage->pExtents[i];
-        if (pExtent->pFile != NULL && pExtent->fMetaDirty)
-        {
-            switch (pExtent->enmType)
-            {
-                case VMDKETYPE_HOSTED_SPARSE:
-#ifdef VBOX_WITH_VMDK_ESX
-                case VMDKETYPE_ESX_SPARSE:
-#endif /* VBOX_WITH_VMDK_ESX */
-                    rc = vmdkWriteMetaSparseExtentAsync(pImage, pExtent, 0, pIoCtx);
-                    if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
-                        goto out;
-                    if (pExtent->fFooter)
-                    {
-                        uint64_t uFileOffset = pExtent->uAppendPosition;
-                        if (!uFileOffset)
-                        {
-                            rc = VERR_INTERNAL_ERROR;
-                            goto out;
-                        }
-                        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
-                        rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
-                        if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
-                            goto out;
-                    }
-                    break;
-                case VMDKETYPE_VMFS:
-                case VMDKETYPE_FLAT:
-                    /* Nothing to do. */
-                    break;
-                case VMDKETYPE_ZERO:
-                default:
-                    AssertMsgFailed(("extent with type %d marked as dirty\n",
-                                     pExtent->enmType));
-                    break;
-            }
-        }
-        switch (pExtent->enmType)
-        {
-            case VMDKETYPE_HOSTED_SPARSE:
-#ifdef VBOX_WITH_VMDK_ESX
-            case VMDKETYPE_ESX_SPARSE:
-#endif /* VBOX_WITH_VMDK_ESX */
-            case VMDKETYPE_VMFS:
-            case VMDKETYPE_FLAT:
-                /*
-                 * Don't ignore block devices like in the sync case
-                 * (they have an absolute path).
-                 * We might have unwritten data in the writeback cache and
-                 * the async I/O manager will handle these requests properly
-                 * even if the block device doesn't support these requests.
-                 */
-                if (   pExtent->pFile != NULL
-                    && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
-                    rc = vdIfIoIntFileFlush(pImage->pIfIo, pExtent->pFile->pStorage,
-                                            pIoCtx, NULL, NULL);
-                break;
-            case VMDKETYPE_ZERO:
-                /* No need to do anything for this extent. */
-                break;
-            default:
-                AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
-                break;
-        }
-    }
-
-out:
-    return rc;
-}
 
 
@@ -7211,4 +6544,6 @@
     /* pfnFlush */
     vmdkFlush,
+    /* pfnDiscard */
+    NULL,
     /* pfnGetVersion */
     vmdkGetVersion,
@@ -7263,10 +6598,4 @@
     /* pfnSetParentFilename */
     NULL,
-    /* pfnAsyncRead */
-    vmdkAsyncRead,
-    /* pfnAsyncWrite */
-    vmdkAsyncWrite,
-    /* pfnAsyncFlush */
-    vmdkAsyncFlush,
     /* pfnComposeLocation */
     genericFileComposeLocation,
@@ -7277,8 +6606,4 @@
     /* pfnResize */
     NULL,
-    /* pfnDiscard */
-    NULL,
-    /* pfnAsyncDiscard */
-    NULL,
     /* pfnRepair */
     NULL
