Index: trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/VBoxHDD.cpp	(revision 27210)
+++ trunk/src/VBox/Devices/Storage/VBoxHDD.cpp	(revision 27211)
@@ -300,6 +300,6 @@
  * will give us.
  */
-static int vdReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, uint64_t uOffset,
-                        void *pvBuf, size_t cbRead)
+static int vdReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
+                        uint64_t uOffset, void *pvBuf, size_t cbRead)
 {
     int rc;
@@ -313,12 +313,23 @@
          * stale data when different block sizes are used for the images. */
         cbThisRead = cbRead;
-        rc = VERR_VD_BLOCK_FREE;
-        for (PVDIMAGE pCurrImage = pImage;
-             pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE;
-             pCurrImage = pCurrImage->pPrev)
-        {
-            rc = pCurrImage->Backend->pfnRead(pCurrImage->pvBackendData,
-                                              uOffset, pvBuf, cbThisRead,
-                                              &cbThisRead);
+
+        /*
+         * Try to read from the given image.
+         * If the block is not allocated read from override chain if present.
+         */
+        rc = pImage->Backend->pfnRead(pImage->pvBackendData,
+                                      uOffset, pvBuf, cbThisRead,
+                                      &cbThisRead);
+
+        if (rc == VERR_VD_BLOCK_FREE)
+        {
+            for (PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev;
+                 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE;
+                 pCurrImage = pCurrImage->pPrev)
+            {
+                rc = pCurrImage->Backend->pfnRead(pCurrImage->pvBackendData,
+                                                  uOffset, pvBuf, cbThisRead,
+                                                  &cbThisRead);
+            }
         }
 
@@ -345,5 +356,5 @@
 {
     PVDPARENTSTATEDESC pParentState = (PVDPARENTSTATEDESC)pvUser;
-    return vdReadHelper(pParentState->pDisk, pParentState->pImage, uOffset,
+    return vdReadHelper(pParentState->pDisk, pParentState->pImage, NULL, uOffset,
                         pvBuf, cbRead);
 }
@@ -395,4 +406,5 @@
  */
 static int vdWriteHelperStandard(PVBOXHDD pDisk, PVDIMAGE pImage,
+                                 PVDIMAGE pImageParentOverride,
                                  uint64_t uOffset, size_t cbWrite,
                                  size_t cbThisWrite, size_t cbPreRead,
@@ -405,6 +417,6 @@
     if (cbPreRead)
     {
-        rc = vdReadHelper(pDisk, pImage, uOffset - cbPreRead, pvTmp,
-                          cbPreRead);
+        rc = vdReadHelper(pDisk, pImage, pImageParentOverride,
+                          uOffset - cbPreRead, pvTmp, cbPreRead);
         if (RT_FAILURE(rc))
             return rc;
@@ -440,5 +452,5 @@
                    (char *)pvBuf + cbThisWrite, cbWriteCopy);
         if (cbReadImage)
-            rc = vdReadHelper(pDisk, pImage,
+            rc = vdReadHelper(pDisk, pImage, pImageParentOverride,
                               uOffset + cbThisWrite + cbWriteCopy,
                               (char *)pvTmp + cbPreRead + cbThisWrite + cbWriteCopy,
@@ -472,4 +484,5 @@
  */
 static int vdWriteHelperOptimized(PVBOXHDD pDisk, PVDIMAGE pImage,
+                                  PVDIMAGE pImageParentOverride,
                                   uint64_t uOffset, size_t cbWrite,
                                   size_t cbThisWrite, size_t cbPreRead,
@@ -501,5 +514,5 @@
     /* Read the entire data of the block so that we can compare whether it will
      * be modified by the write or not. */
-    rc = vdReadHelper(pDisk, pImage, uOffset - cbPreRead, pvTmp,
+    rc = vdReadHelper(pDisk, pImage, pImageParentOverride, uOffset - cbPreRead, pvTmp,
                       cbPreRead + cbThisWrite + cbPostRead - cbFill);
     if (RT_FAILURE(rc))
@@ -548,6 +561,6 @@
  * write optimizations.
  */
-static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage, uint64_t uOffset,
-                         const void *pvBuf, size_t cbWrite)
+static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
+                         uint64_t uOffset, const void *pvBuf, size_t cbWrite)
 {
     int rc;
@@ -580,5 +593,6 @@
                 /* Optimized write, suppress writing to a so far unallocated
                  * block if the data is in fact not changed. */
-                rc = vdWriteHelperOptimized(pDisk, pImage, uOffset, cbWrite,
+                rc = vdWriteHelperOptimized(pDisk, pImage, pImageParentOverride,
+                                            uOffset, cbWrite,
                                             cbThisWrite, cbPreRead, cbPostRead,
                                             pvBuf, pvTmp);
@@ -590,5 +604,6 @@
                  * backend has some further optimization enabled) cause the
                  * block to be allocated. */
-                rc = vdWriteHelperStandard(pDisk, pImage, uOffset, cbWrite,
+                rc = vdWriteHelperStandard(pDisk, pImage, pImageParentOverride,
+                                           uOffset, cbWrite,
                                            cbThisWrite, cbPreRead, cbPostRead,
                                            pvBuf, pvTmp);
@@ -1839,4 +1854,5 @@
     return rc;
 }
+
 
 /**
@@ -1944,5 +1960,6 @@
                         if (RT_FAILURE(rc))
                             break;
-                        rc = vdWriteHelper(pDisk, pImageTo, uOffset, pvBuf,
+                        rc = vdWriteHelper(pDisk, pImageTo, pImageFrom->pPrev,
+                                           uOffset, pvBuf,
                                            cbThisRead);
                         if (RT_FAILURE(rc))
@@ -1970,4 +1987,28 @@
         else
         {
+            /*
+             * We may need to update the parent uuid of the child coming after the
+             * last image to be merged. We have to reopen it read/write.
+             *
+             * This is done before we do the actual merge to prevent an incosistent
+             * chain if the mode change fails for some reason.
+             */
+            if (pImageFrom->pNext)
+            {
+                PVDIMAGE pImageChild = pImageFrom->pNext;
+
+                /* We need to open the image in read/write mode. */
+                uOpenFlags = pImageChild->Backend->pfnGetOpenFlags(pImageChild->pvBackendData);
+
+                if (uOpenFlags  & VD_OPEN_FLAGS_READONLY)
+                {
+                    uOpenFlags  &= ~VD_OPEN_FLAGS_READONLY;
+                    rc = pImageChild->Backend->pfnSetOpenFlags(pImageChild->pvBackendData,
+                                                               uOpenFlags);
+                    if (RT_FAILURE(rc))
+                        break;
+                }
+            }
+
             /* Merge child state into parent. This means writing all blocks
              * which are allocated in the image up to the source image to the
@@ -1996,5 +2037,5 @@
                     if (RT_FAILURE(rc))
                         break;
-                    rc = vdWriteHelper(pDisk, pImageTo, uOffset, pvBuf,
+                    rc = vdWriteHelper(pDisk, pImageTo, NULL, uOffset, pvBuf,
                                        cbThisRead);
                     if (RT_FAILURE(rc))
@@ -2036,4 +2077,5 @@
         else
         {
+            /* Update the parent uuid of the child of the last merged image. */
             if (pImageFrom->pNext)
             {
@@ -2041,7 +2083,25 @@
                                                    &Uuid);
                 AssertRC(rc);
+
                 rc = pImageFrom->Backend->pfnSetParentUuid(pImageFrom->pNext->pvBackendData,
                                                            &Uuid);
                 AssertRC(rc);
+
+                /* Reopen readonly if neccessary */
+                if (pImageFrom->pNext != pDisk->pLast)
+                {
+                    PVDIMAGE pImageChild = pImageFrom->pNext;
+
+                    uOpenFlags = pImageChild->Backend->pfnGetOpenFlags(pImageChild->pvBackendData);
+                    uOpenFlags |= VD_OPEN_FLAGS_READONLY;
+                    rc = pImageChild->Backend->pfnSetOpenFlags(pImageChild->pvBackendData,
+                                                               uOpenFlags);
+                    /** @todo: What to do if this fails?. Breaking would
+                     * prevent the merged images from being removed 
+                     * from the chain possibly causing inconsistent behavior.
+                     */
+                    if (RT_FAILURE(rc))
+                        break;
+                }
             }
         }
@@ -2308,10 +2368,10 @@
             size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining);
 
-            rc = vdReadHelper(pDiskFrom, pImageFrom, uOffset, pvBuf,
+            rc = vdReadHelper(pDiskFrom, pImageFrom, NULL, uOffset, pvBuf,
                               cbThisRead);
             if (RT_FAILURE(rc))
                 break;
 
-            rc = vdWriteHelper(pDiskTo, pImageTo, uOffset, pvBuf,
+            rc = vdWriteHelper(pDiskTo, pImageTo, NULL, uOffset, pvBuf,
                                cbThisRead);
             if (RT_FAILURE(rc))
@@ -2650,5 +2710,5 @@
         AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
 
-        rc = vdReadHelper(pDisk, pImage, uOffset, pvBuf, cbRead);
+        rc = vdReadHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbRead);
     } while (0);
 
@@ -2697,5 +2757,5 @@
 
         vdSetModifiedFlag(pDisk);
-        rc = vdWriteHelper(pDisk, pImage, uOffset, pvBuf, cbWrite);
+        rc = vdWriteHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite);
     } while (0);
 
