Index: trunk/src/VBox/Storage/VD.cpp
===================================================================
--- trunk/src/VBox/Storage/VD.cpp	(revision 35319)
+++ trunk/src/VBox/Storage/VD.cpp	(revision 35321)
@@ -274,5 +274,8 @@
     volatile size_t              cbTransfer;
     /** Current image in the chain. */
-    PVDIMAGE                     pImage;
+    PVDIMAGE                     pImageCur;
+    /** Start image to read from. pImageCur is reset to this
+     *  value after it reached the first image in the chain. */
+    PVDIMAGE                     pImageStart;
     /** S/G buffer */
     RTSGBUF                      SgBuf;
@@ -903,4 +906,5 @@
 DECLINLINE(PVDIOCTX) vdIoCtxAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
                                   uint64_t uOffset, size_t cbTransfer,
+                                  PVDIMAGE pImageStart,
                                   PCRTSGBUF pcSgBuf, void *pvAllocation,
                                   PFNVDIOCTXTRANSFER pfnIoCtxTransfer)
@@ -916,4 +920,6 @@
         pIoCtx->uOffset               = uOffset;
         pIoCtx->cbTransfer            = cbTransfer;
+        pIoCtx->pImageStart           = pImageStart;
+        pIoCtx->pImageCur             = pImageStart;
         pIoCtx->cDataTransfersPending = 0;
         pIoCtx->cMetaTransfersPending = 0;
@@ -937,5 +943,5 @@
 DECLINLINE(PVDIOCTX) vdIoCtxRootAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
                                       uint64_t uOffset, size_t cbTransfer,
-                                      PCRTSGBUF pcSgBuf,
+                                      PVDIMAGE pImageStart, PCRTSGBUF pcSgBuf,
                                       PFNVDASYNCTRANSFERCOMPLETE pfnComplete,
                                       void *pvUser1, void *pvUser2,
@@ -943,5 +949,5 @@
                                       PFNVDIOCTXTRANSFER pfnIoCtxTransfer)
 {
-    PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer,
+    PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, pImageStart,
                                    pcSgBuf, pvAllocation, pfnIoCtxTransfer);
 
@@ -960,10 +966,10 @@
 DECLINLINE(PVDIOCTX) vdIoCtxChildAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
                                        uint64_t uOffset, size_t cbTransfer,
-                                       PCRTSGBUF pcSgBuf,
+                                       PVDIMAGE pImageStart, PCRTSGBUF pcSgBuf,
                                        PVDIOCTX pIoCtxParent, size_t cbTransferParent,
                                        size_t cbWriteParent, void *pvAllocation,
                                        PFNVDIOCTXTRANSFER pfnIoCtxTransfer)
 {
-    PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer,
+    PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, pImageStart,
                                    pcSgBuf, pvAllocation, pfnIoCtxTransfer);
 
@@ -1272,5 +1278,5 @@
     do
     {
-        pCurrImage = pIoCtx->pImage;
+        pCurrImage = pIoCtx->pImageCur;
 
         /* Search for image with allocated block. Do not attempt to read more
@@ -1329,5 +1335,5 @@
         pIoCtx->uOffset    = uOffset;
         pIoCtx->cbTransfer = cbToRead;
-        pIoCtx->pImage     = pCurrImage;
+        pIoCtx->pImageCur  = pCurrImage ? pCurrImage : pIoCtx->pImageStart;
     }
 
@@ -1727,8 +1733,36 @@
 }
 
+static int vdWriteHelperOptimizedCommitAsync(PVDIOCTX pIoCtx)
+{
+    int rc = VINF_SUCCESS;
+    PVDIMAGE pImage = pIoCtx->pImageCur;
+    size_t cbPreRead      = pIoCtx->Type.Child.cbPreRead;
+    size_t cbPostRead     = pIoCtx->Type.Child.cbPostRead;
+    size_t cbThisWrite    = pIoCtx->Type.Child.cbTransferParent;
+
+    LogFlowFunc(("pIoCtx=%#p\n", pIoCtx));
+    rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData,
+                                        pIoCtx->uOffset - cbPreRead,
+                                        cbPreRead + cbThisWrite + cbPostRead,
+                                        pIoCtx, NULL, &cbPreRead, &cbPostRead, 0);
+    Assert(rc != VERR_VD_BLOCK_FREE);
+    Assert(rc == VERR_VD_NOT_ENOUGH_METADATA || cbPreRead == 0);
+    Assert(rc == VERR_VD_NOT_ENOUGH_METADATA || cbPostRead == 0);
+    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+        rc = VINF_SUCCESS;
+    else if (rc == VERR_VD_IOCTX_HALT)
+    {
+        pIoCtx->fBlocked = true;
+        rc = VINF_SUCCESS;
+    }
+
+    LogFlowFunc(("returns rc=%Rrc\n", rc));
+    return rc;
+}
+
 static int vdWriteHelperOptimizedCmpAndWriteAsync(PVDIOCTX pIoCtx)
 {
     int rc = VINF_SUCCESS;
-    PVDIMAGE pImage = pIoCtx->pImage;
+    PVDIMAGE pImage = pIoCtx->pImageCur;
     size_t cbThisWrite    = 0;
     size_t cbPreRead      = pIoCtx->Type.Child.cbPreRead;
@@ -1800,18 +1834,5 @@
     /* Write the full block to the virtual disk. */
     RTSgBufReset(&pIoCtx->SgBuf);
-    rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData,
-                                        pIoCtx->uOffset - cbPreRead,
-                                        cbPreRead + cbThisWrite + cbPostRead,
-                                        pIoCtx, NULL, &cbPreRead, &cbPostRead, 0);
-    Assert(rc != VERR_VD_BLOCK_FREE);
-    Assert(cbPreRead == 0);
-    Assert(cbPostRead == 0);
-    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
-        rc = VINF_SUCCESS;
-    else if (rc == VERR_VD_IOCTX_HALT)
-    {
-        pIoCtx->fBlocked = true;
-        rc = VINF_SUCCESS;
-    }
+    pIoCtx->pfnIoCtxTransferNext = vdWriteHelperOptimizedCommitAsync;
 
     return rc;
@@ -1901,5 +1922,5 @@
     size_t cbWrite   = pIoCtx->cbTransfer;
     uint64_t uOffset = pIoCtx->uOffset;
-    PVDIMAGE pImage  = pIoCtx->pImage;
+    PVDIMAGE pImage  = pIoCtx->pImageCur;
     PVBOXHDD pDisk   = pIoCtx->pDisk;
     unsigned fWrite;
@@ -1942,5 +1963,5 @@
 
                 PVDIOCTX pIoCtxWrite = vdIoCtxChildAlloc(pDisk, VDIOCTXTXDIR_WRITE,
-                                                         uOffset, pSeg->cbSeg,
+                                                         uOffset, pSeg->cbSeg, pImage,
                                                          pTmp,
                                                          pIoCtx, cbThisWrite,
@@ -1960,5 +1981,4 @@
                              pIoCtx, pIoCtxWrite));
 
-                pIoCtxWrite->pImage                = pImage;
                 pIoCtxWrite->Type.Child.cbPreRead  = cbPreRead;
                 pIoCtxWrite->Type.Child.cbPostRead = cbPostRead;
@@ -2039,5 +2059,5 @@
     int rc = VINF_SUCCESS;
     PVBOXHDD pDisk = pIoCtx->pDisk;
-    PVDIMAGE pImage = pIoCtx->pImage;
+    PVDIMAGE pImage = pIoCtx->pImageCur;
 
     rc = vdIoCtxLockDisk(pDisk, pIoCtx);
@@ -8003,7 +8023,8 @@
                             uOffset, cbRead, pDisk->cbSize),
                            rc = VERR_INVALID_PARAMETER);
+        AssertPtrBreakStmt(pDisk->pLast, rc = VERR_VD_NOT_OPENED);
 
         pIoCtx = vdIoCtxRootAlloc(pDisk, VDIOCTXTXDIR_READ, uOffset,
-                                  cbRead, pcSgBuf,
+                                  cbRead, pDisk->pLast, pcSgBuf,
                                   pfnComplete, pvUser1, pvUser2,
                                   NULL, vdReadHelperAsync);
@@ -8013,7 +8034,4 @@
             break;
         }
-
-        pIoCtx->pImage = pDisk->pLast;
-        AssertPtrBreakStmt(pIoCtx->pImage, rc = VERR_VD_NOT_OPENED);
 
         rc = vdIoCtxProcess(pIoCtx);
@@ -8076,7 +8094,8 @@
                             uOffset, cbWrite, pDisk->cbSize),
                            rc = VERR_INVALID_PARAMETER);
+        AssertPtrBreakStmt(pDisk->pLast, rc = VERR_VD_NOT_OPENED);
 
         pIoCtx = vdIoCtxRootAlloc(pDisk, VDIOCTXTXDIR_WRITE, uOffset,
-                                  cbWrite, pcSgBuf,
+                                  cbWrite, pDisk->pLast, pcSgBuf,
                                   pfnComplete, pvUser1, pvUser2,
                                   NULL, vdWriteHelperAsync);
@@ -8086,8 +8105,4 @@
             break;
         }
-
-        PVDIMAGE pImage = pDisk->pLast;
-        AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
-        pIoCtx->pImage = pImage;
 
         rc = vdIoCtxProcess(pIoCtx);
@@ -8135,6 +8150,8 @@
         fLockWrite = true;
 
+        AssertPtrBreakStmt(pDisk->pLast, rc = VERR_VD_NOT_OPENED);
+
         pIoCtx = vdIoCtxRootAlloc(pDisk, VDIOCTXTXDIR_FLUSH, 0,
-                                  0, NULL,
+                                  0, pDisk->pLast, NULL,
                                   pfnComplete, pvUser1, pvUser2,
                                   NULL, vdFlushHelperAsync);
@@ -8144,8 +8161,4 @@
             break;
         }
-
-        PVDIMAGE pImage = pDisk->pLast;
-        AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
-        pIoCtx->pImage = pImage;
 
         rc = vdIoCtxProcess(pIoCtx);
