Index: /trunk/include/iprt/list.h
===================================================================
--- /trunk/include/iprt/list.h	(revision 52357)
+++ /trunk/include/iprt/list.h	(revision 52358)
@@ -403,4 +403,28 @@
 }
 
+/**
+ * List concatenation.
+ *
+ * @returns nothing.
+ * @param   pListDst            The destination list.
+ * @param   pListSrc            The source list to concatenate.
+ */
+DECLINLINE(void) RTListConcatenate(PRTLISTANCHOR pListDst, PRTLISTANCHOR pListSrc)
+{
+    if (!RTListIsEmpty(pListSrc))
+    {
+        PRTLISTNODE pFirst = pListSrc->pNext;
+        PRTLISTNODE pLast = pListSrc->pPrev;
+
+        pListDst->pPrev->pNext = pFirst;
+        pFirst->pPrev          = pListDst->pPrev;
+        pLast->pNext           = pListDst;
+        pListDst->pPrev        = pLast;
+
+        /* Finally remove the elements from the source list */
+        RTListInit(pListSrc);
+    }
+}
+
 RT_C_DECLS_END
 
Index: /trunk/src/VBox/Storage/VD.cpp
===================================================================
--- /trunk/src/VBox/Storage/VD.cpp	(revision 52357)
+++ /trunk/src/VBox/Storage/VD.cpp	(revision 52358)
@@ -579,4 +579,10 @@
     /** Size of the data stored with this entry. */
     size_t           cbMeta;
+    /** Shadow buffer which is used in case a write is still active and other
+     * writes update the shadow buffer. */
+    uint8_t         *pbDataShw;
+    /** List of I/O contexts updating the shadow buffer while there is a write
+     * in progress. */
+    RTLISTNODE       ListIoCtxShwWrites;
     /** Data stored - variable size. */
     uint8_t          abData[1];
@@ -1545,5 +1551,7 @@
         pMetaXfer->pIoStorage   = pIoStorage;
         pMetaXfer->cRefs        = 0;
+        pMetaXfer->pbDataShw    = NULL;
         RTListInit(&pMetaXfer->ListIoCtxWaiting);
+        RTListInit(&pMetaXfer->ListIoCtxShwWrites);
     }
     return pMetaXfer;
@@ -4013,4 +4021,37 @@
 }
 
+static void vdIoCtxContinueDeferredList(PVDIOSTORAGE pIoStorage, PRTLISTANCHOR pListWaiting,
+                                        PFNVDXFERCOMPLETED pfnComplete, void *pvUser, int rcReq)
+{
+    LogFlowFunc(("pIoStorage=%#p pListWaiting=%#p pfnComplete=%#p pvUser=%#p rcReq=%Rrc\n",
+                 pIoStorage, pListWaiting, pfnComplete, pvUser, rcReq));
+
+    /* Go through the waiting list and continue the I/O contexts. */
+    while (!RTListIsEmpty(pListWaiting))
+    {
+        int rc = VINF_SUCCESS;
+        bool fContinue = true;
+        PVDIOCTXDEFERRED pDeferred = RTListGetFirst(pListWaiting, VDIOCTXDEFERRED, NodeDeferred);
+        PVDIOCTX pIoCtx = pDeferred->pIoCtx;
+        RTListNodeRemove(&pDeferred->NodeDeferred);
+
+        RTMemFree(pDeferred);
+        ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
+
+        if (pfnComplete)
+            rc = pfnComplete(pIoStorage->pVDIo->pBackendData, pIoCtx, pvUser, rcReq);
+
+        LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc));
+
+        if (RT_SUCCESS(rc))
+        {
+            rc = vdIoCtxContinue(pIoCtx, rcReq);
+            AssertRC(rc);
+        }
+        else
+            Assert(rc == VERR_VD_ASYNC_IO_IN_PROGRESS);
+    }
+}
+
 /**
  * Internal - Called when a meta transfer completed.
@@ -4029,5 +4070,4 @@
 
     fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH;
-    VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
 
     if (!fFlush)
@@ -4041,4 +4081,13 @@
             bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL;
             Assert(fRemoved);
+            /* If this was a write check if there is a shadow buffer with updated data. */
+            if (pMetaXfer->pbDataShw)
+            {
+                Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_WRITE);
+                Assert(!RTListIsEmpty(&pMetaXfer->ListIoCtxShwWrites));
+                RTListConcatenate(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxShwWrites);
+                RTMemFree(pMetaXfer->pbDataShw);
+                pMetaXfer->pbDataShw = NULL;
+            }
             RTMemFree(pMetaXfer);
         }
@@ -4052,32 +4101,56 @@
         RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting);
 
-    /* Go through the waiting list and continue the I/O contexts. */
-    while (!RTListIsEmpty(&ListIoCtxWaiting))
-    {
-        int rc = VINF_SUCCESS;
-        bool fContinue = true;
-        PVDIOCTXDEFERRED pDeferred = RTListGetFirst(&ListIoCtxWaiting, VDIOCTXDEFERRED, NodeDeferred);
-        PVDIOCTX pIoCtx = pDeferred->pIoCtx;
-        RTListNodeRemove(&pDeferred->NodeDeferred);
-
-        RTMemFree(pDeferred);
-        ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
-
-        if (pfnComplete)
-            rc = pfnComplete(pIoStorage->pVDIo->pBackendData, pIoCtx, pvUser, rcReq);
-
-        LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc));
-
-        if (RT_SUCCESS(rc))
-        {
-            rc = vdIoCtxContinue(pIoCtx, rcReq);
-            AssertRC(rc);
+    VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
+    vdIoCtxContinueDeferredList(pIoStorage, &ListIoCtxWaiting, pfnComplete, pvUser, rcReq);
+
+    /*
+     * If there is a shadow buffer and the previous write was successful update with the
+     * new data and trigger a new write.
+     */
+    if (   pMetaXfer->pbDataShw
+        && RT_SUCCESS(rcReq)
+        && VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE)
+    {
+        LogFlowFunc(("pMetaXfer=%#p Updating from shadow buffer and triggering new write\n", pMetaXfer));
+        memcpy(pMetaXfer->abData, pMetaXfer->pbDataShw, pMetaXfer->cbMeta);
+        RTMemFree(pMetaXfer->pbDataShw);
+        pMetaXfer->pbDataShw = NULL;
+        Assert(!RTListIsEmpty(&pMetaXfer->ListIoCtxShwWrites));
+
+        /* Setup a new I/O write. */
+        PVDIOTASK pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvUser, pMetaXfer);
+        if (RT_LIKELY(pIoTask))
+        {
+            void *pvTask = NULL;
+            RTSGSEG Seg;
+
+            Seg.cbSeg = pMetaXfer->cbMeta;
+            Seg.pvSeg = pMetaXfer->abData;
+
+            VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
+            rcReq = pIoStorage->pVDIo->pInterfaceIo->pfnWriteAsync(pIoStorage->pVDIo->pInterfaceIo->Core.pvUser,
+                                                                   pIoStorage->pStorage,
+                                                                   pMetaXfer->Core.Key, &Seg, 1,
+                                                                   pMetaXfer->cbMeta, pIoTask,
+                                                                   &pvTask);
+            if (   RT_SUCCESS(rcReq)
+                || rcReq != VERR_VD_ASYNC_IO_IN_PROGRESS)
+            {
+                VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
+                vdIoTaskFree(pDisk, pIoTask);
+            }
+            else
+                RTListMove(&pMetaXfer->ListIoCtxWaiting, &pMetaXfer->ListIoCtxShwWrites);
         }
         else
-            Assert(rc == VERR_VD_ASYNC_IO_IN_PROGRESS);
+            rcReq = VERR_NO_MEMORY;
+
+        /* Cleanup if there was an error or the request completed already. */
+        if (rcReq != VERR_VD_ASYNC_IO_IN_PROGRESS)
+            vdIoCtxContinueDeferredList(pIoStorage, &pMetaXfer->ListIoCtxShwWrites, pfnComplete, pvUser, rcReq);
     }
 
     /* Remove if not used anymore. */
-    if (RT_SUCCESS(rcReq) && !fFlush)
+    if (!fFlush)
     {
         pMetaXfer->cRefs--;
@@ -4683,5 +4756,8 @@
                 Assert(pMetaXfer->cbMeta >= cbRead);
                 Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset);
-                memcpy(pvBuf, pMetaXfer->abData, cbRead);
+                if (pMetaXfer->pbDataShw)
+                    memcpy(pvBuf, pMetaXfer->pbDataShw, cbRead);
+                else
+                    memcpy(pvBuf, pMetaXfer->abData, cbRead);
                 *ppMetaXfer = pMetaXfer;
             }
@@ -4745,58 +4821,103 @@
         }
 
-        Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE);
-
-        pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer);
-        if (!pIoTask)
-        {
-            RTMemFree(pMetaXfer);
-            return VERR_NO_MEMORY;
-        }
-
-        memcpy(pMetaXfer->abData, pvBuf, cbWrite);
-        Seg.cbSeg = cbWrite;
-        Seg.pvSeg = pMetaXfer->abData;
-
-        ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
-
-        VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
-        rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser,
-                                                pIoStorage->pStorage,
-                                                uOffset, &Seg, 1, cbWrite, pIoTask,
-                                                &pvTask);
-        if (RT_SUCCESS(rc))
-        {
-            VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
-            ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
-            vdIoTaskFree(pDisk, pIoTask);
-            if (fInTree && !pMetaXfer->cRefs)
+        if (VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE)
+        {
+            pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer);
+            if (!pIoTask)
             {
-                LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
-                bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL;
-                AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n"));
+                RTMemFree(pMetaXfer);
+                return VERR_NO_MEMORY;
+            }
+
+            memcpy(pMetaXfer->abData, pvBuf, cbWrite);
+            Seg.cbSeg = cbWrite;
+            Seg.pvSeg = pMetaXfer->abData;
+
+            ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
+
+            VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
+            rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser,
+                                                    pIoStorage->pStorage,
+                                                    uOffset, &Seg, 1, cbWrite, pIoTask,
+                                                    &pvTask);
+            if (RT_SUCCESS(rc))
+            {
+                VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
+                ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
+                vdIoTaskFree(pDisk, pIoTask);
+                if (fInTree && !pMetaXfer->cRefs)
+                {
+                    LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
+                    bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL;
+                    AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n"));
+                    RTMemFree(pMetaXfer);
+                    pMetaXfer = NULL;
+                }
+            }
+            else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+            {
+                PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
+                AssertPtr(pDeferred);
+
+                RTListInit(&pDeferred->NodeDeferred);
+                pDeferred->pIoCtx = pIoCtx;
+
+                if (!fInTree)
+                {
+                    bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
+                    Assert(fInserted);
+                }
+
+                RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
+            }
+            else
+            {
                 RTMemFree(pMetaXfer);
                 pMetaXfer = NULL;
             }
         }
-        else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
-        {
-            PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
-            AssertPtr(pDeferred);
-
-            RTListInit(&pDeferred->NodeDeferred);
-            pDeferred->pIoCtx = pIoCtx;
-
-            if (!fInTree)
+        else
+        {
+            /* I/O is in progress, update shadow buffer and add to waiting list. */
+            Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_WRITE);
+            if (!pMetaXfer->pbDataShw)
             {
-                bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
-                Assert(fInserted);
+                /* Allocate shadow buffer and set initial state. */
+                LogFlowFunc(("pMetaXfer=%#p Creating shadow buffer\n", pMetaXfer));
+                pMetaXfer->pbDataShw = (uint8_t *)RTMemAlloc(pMetaXfer->cbMeta);
+                if (RT_LIKELY(pMetaXfer->pbDataShw))
+                    memcpy(pMetaXfer->pbDataShw, pMetaXfer->abData, pMetaXfer->cbMeta);
+                else
+                    rc = VERR_NO_MEMORY;
             }
 
-            RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
-        }
-        else
-        {
-            RTMemFree(pMetaXfer);
-            pMetaXfer = NULL;
+            if (RT_SUCCESS(rc))
+            {
+                /* Update with written data and append to waiting list. */
+                PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
+                if (pDeferred)
+                {
+                    LogFlowFunc(("pMetaXfer=%#p Updating shadow buffer\n", pMetaXfer));
+
+                    RTListInit(&pDeferred->NodeDeferred);
+                    pDeferred->pIoCtx = pIoCtx;
+                    ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
+                    memcpy(pMetaXfer->pbDataShw, pvBuf, cbWrite);
+                    RTListAppend(&pMetaXfer->ListIoCtxShwWrites, &pDeferred->NodeDeferred);
+                }
+                else
+                {
+                    /*
+                     * Free shadow buffer if there is no one depending on it, i.e.
+                     * we just allocated it.
+                     */
+                    if (RTListIsEmpty(&pMetaXfer->ListIoCtxShwWrites))
+                    {
+                        RTMemFree(pMetaXfer->pbDataShw);
+                        pMetaXfer->pbDataShw = NULL;
+                    }
+                    rc = VERR_NO_MEMORY;
+                }
+            }
         }
     }
Index: /trunk/src/VBox/Storage/VHD.cpp
===================================================================
--- /trunk/src/VBox/Storage/VHD.cpp	(revision 52357)
+++ /trunk/src/VBox/Storage/VHD.cpp	(revision 52358)
@@ -623,4 +623,5 @@
     if (fFlags == VHDIMAGEEXPAND_ALL_SUCCESS)
     {
+        pImage->pBlockAllocationTable[pExpand->idxBatAllocated] = RT_BE2H_U32(pExpand->idxBlockBe);
         RTMemFree(pExpand);
     }
@@ -1691,5 +1692,5 @@
                  */
                 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
-                                            pImage->uCurrentEndOfFile + pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE,
+                                            pImage->uCurrentEndOfFile + (pImage->cDataBlockBitmapSectors + (cSector % pImage->cSectorsPerDataBlock)) * VHD_SECTOR_SIZE,
                                             pIoCtx, cbWrite,
                                             vhdAsyncExpansionDataComplete,
@@ -1729,5 +1730,4 @@
                  * 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 += pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE + pImage->cbDataBlock;
 
