Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 22791)
+++ /trunk/include/VBox/err.h	(revision 22792)
@@ -567,4 +567,8 @@
 /** Trying to read a 64-bit guest virtual address into a 32-bit variable. */
 #define VERR_SSM_GCPTR_OVERFLOW                 (-1850)
+/** Vote for another pass.  */
+#define VINF_SSM_VOTE_FOR_ANOTHER_PASS          1851
+/** Vote for giving up.  */
+#define VERR_SSM_VOTE_FOR_GIVING_UP             (-1852)
 /** @} */
 
@@ -1002,5 +1006,5 @@
 #define VERR_PDM_DEVICE_NO_RT_ATTACH                (-2853)
 /** The driver doesn't support runtime driver attaching.
- * The PDMDRVREG::pfnAttach callback function is NULL. */ 
+ * The PDMDRVREG::pfnAttach callback function is NULL. */
 #define VERR_PDM_DRIVER_NO_RT_ATTACH                (-2854)
 /** Invalid host interface version. */
Index: /trunk/include/VBox/ssm.h
===================================================================
--- /trunk/include/VBox/ssm.h	(revision 22791)
+++ /trunk/include/VBox/ssm.h	(revision 22792)
@@ -167,5 +167,9 @@
  * being called every time.
  *
- * @returns true if done, false if there is more that needs to be saved first.
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS if done.
+ * @retval  VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed.
+ * @retval  VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up.
+ *
  * @param   pDevIns         Device instance of the device which registered the data unit.
  * @param   pSSM            SSM operation handle.
@@ -288,5 +292,9 @@
  * being called every time.
  *
- * @returns true if done, false if there is more that needs to be saved first.
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS if done.
+ * @retval  VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed.
+ * @retval  VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up.
+ *
  * @param   pDrvIns         Driver instance of the device which registered the
  *                          data unit.
@@ -410,10 +418,14 @@
  * being called every time.
  *
- * @returns true if done, false if there is more that needs to be saved first.
- * @param   pVM             VM Handle.
- * @param   pSSM            SSM operation handle.
- * @thread  Any.
- */
-typedef DECLCALLBACK(bool) FNSSMINTLIVEVOTE(PVM pVM, PSSMHANDLE pSSM);
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS if done.
+ * @retval  VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed.
+ * @retval  VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up.
+ *
+ * @param   pVM             VM Handle.
+ * @param   pSSM            SSM operation handle.
+ * @thread  Any.
+ */
+typedef DECLCALLBACK(int) FNSSMINTLIVEVOTE(PVM pVM, PSSMHANDLE pSSM);
 /** Pointer to a FNSSMINTLIVEVOTE() function. */
 typedef FNSSMINTLIVEVOTE *PFNSSMINTLIVEVOTE;
@@ -632,4 +644,9 @@
 VMMR3DECL(int) SSMR3DeregisterExternal(PVM pVM, const char *pszName);
 VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser);
+VMMR3DECL(int) SSMR3LiveToFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter,
+                               PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM);
+VMMR3DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM);
+VMMR3DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM);
+VMMR3DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM);
 VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser);
 VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt);
Index: /trunk/src/VBox/VMM/SSM.cpp
===================================================================
--- /trunk/src/VBox/VMM/SSM.cpp	(revision 22791)
+++ /trunk/src/VBox/VMM/SSM.cpp	(revision 22792)
@@ -425,4 +425,6 @@
     /** the amount of % we reserve for the 'done' stage */
     unsigned        uPercentDone;
+    /** The filename, NULL if remote stream. */
+    const char     *pszFilename;
 
     union
@@ -2575,5 +2577,8 @@
     int rc = ssmR3DataFlushBuffer(pSSM);
     if (RT_SUCCESS(rc))
+    {
+        pSSM->offUnit = UINT64_MAX;
         return VINF_SUCCESS;
+    }
 
     if (RT_SUCCESS(pSSM->rc))
@@ -3282,4 +3287,152 @@
 
 /**
+ * Worker for SSMR3LiveDone and SSMR3Save that closes the handle and deletes the
+ * saved state file on failure.
+ *
+ * @returns VBox status code (pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The saved state handle.
+ */
+static int ssmR3SaveDoClose(PVM pVM, PSSMHANDLE pSSM)
+{
+    VM_ASSERT_EMT0(pVM);
+
+    /*
+     * Close the stream and delete the file on failure.
+     */
+    int rc = ssmR3StrmClose(&pSSM->Strm);
+    if (RT_SUCCESS(rc))
+        rc = pSSM->rc;
+    if (RT_SUCCESS(rc))
+    {
+        if (pSSM->pfnProgress)
+            pSSM->pfnProgress(pVM, 100, pSSM->pvUser);
+        LogRel(("SSM: Successfully saved the VM state to '%s'\n",
+                pSSM->pszFilename ? pSSM->pszFilename : "<remote-machine>"));
+    }
+    else
+    {
+        if (pSSM->pszFilename)
+        {
+            int rc2 = RTFileDelete(pSSM->pszFilename);
+            AssertRC(rc2);
+            if (RT_SUCCESS(rc2))
+                LogRel(("SSM: Failed to save the VM state to '%s' (file deleted): %Rrc\n",
+                        pSSM->pszFilename, rc));
+            else
+                LogRel(("SSM: Failed to save the VM state to '%s' (file deletion failed, rc2=%Rrc): %Rrc\n",
+                        pSSM->pszFilename, rc2, rc));
+        }
+        else
+            LogRel(("SSM: Failed to save the VM state.\n"));
+    }
+
+    /*
+     * Trash the handle before freeing it.
+     */
+    pSSM->pVM = NULL;
+    pSSM->enmAfter = SSMAFTER_INVALID;
+    pSSM->enmOp = SSMSTATE_INVALID;
+    RTMemFree(pSSM);
+
+    return rc;
+}
+
+
+/**
+ * Closes the SSM handle.
+ *
+ * This must always be called on a handled returned by SSMR3LiveToFile or
+ * SSMR3LiveToRemote.
+ *
+ * @returns VBox status.
+ *
+ * @param   pSSM            The SSM handle returned by SSMR3LiveToFile or
+ *                          SSMR3LiveToRemote.
+ *
+ * @thread  EMT(0).
+ */
+VMMR3DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM)
+{
+    LogFlow(("SSMR3LiveDone: pSSM=%p\n", pSSM));
+
+    /*
+     * Validate input.
+     */
+    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
+    PVM pVM = pSSM->pVM;
+    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+    VM_ASSERT_EMT0(pVM);
+    AssertMsgReturn(   pSSM->enmAfter == SSMAFTER_DESTROY
+                    || pSSM->enmAfter == SSMAFTER_CONTINUE,
+                    ("%d\n", pSSM->enmAfter),
+                    VERR_INVALID_PARAMETER);
+    AssertMsgReturn(    pSSM->enmOp >= SSMSTATE_LIVE_PREP
+                    &&  pSSM->enmOp <= SSMSTATE_SAVE_DONE,
+                    ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
+
+    /*
+     * Join paths with SSMR3Save again.
+     */
+    return ssmR3SaveDoClose(pVM, pSSM);
+}
+
+
+/**
+ * Do the pfnSaveDone run.
+ *
+ * @returns VBox status code (pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The saved state handle.
+ */
+static int ssmR3SaveDoDoneRun(PVM pVM, PSSMHANDLE pSSM)
+{
+    VM_ASSERT_EMT0(pVM);
+
+    /*
+     * Do the done run.
+     */
+    pSSM->enmOp = SSMSTATE_SAVE_DONE;
+    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
+    {
+        if (    pUnit->u.Common.pfnSaveDone
+            &&  (   pUnit->fCalled
+                 || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec)))
+        {
+            int rcOld = pSSM->rc;
+            int rc;
+            switch (pUnit->enmType)
+            {
+                case SSMUNITTYPE_DEV:
+                    rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, pSSM);
+                    break;
+                case SSMUNITTYPE_DRV:
+                    rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, pSSM);
+                    break;
+                case SSMUNITTYPE_INTERNAL:
+                    rc = pUnit->u.Internal.pfnSaveDone(pVM, pSSM);
+                    break;
+                case SSMUNITTYPE_EXTERNAL:
+                    rc = pUnit->u.External.pfnSaveDone(pSSM, pUnit->u.External.pvUser);
+                    break;
+                default:
+                    rc = VERR_INTERNAL_ERROR;
+                    break;
+            }
+            if (RT_SUCCESS(rc) && pSSM->rc != rcOld)
+                rc = pSSM->rc;
+            if (RT_FAILURE(rc))
+            {
+                LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
+                if (RT_SUCCESS(pSSM->rc))
+                    pSSM->rc = rc;
+            }
+        }
+    }
+    return pSSM->rc;
+}
+
+
+/**
  * Writes the directory.
  *
@@ -3291,4 +3444,6 @@
 static int ssmR3WriteDirectory(PVM pVM, PSSMHANDLE pSSM, uint32_t *pcEntries)
 {
+    VM_ASSERT_EMT0(pVM);
+
     /*
      * Grab some temporary memory for the dictionary.
@@ -3333,4 +3488,424 @@
 
 /**
+ * Finalize the saved state stream, i.e. add the end unit, directory
+ * and footer.
+ *
+ * @returns VBox status code (pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The saved state handle.
+ */
+static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM)
+{
+    VM_ASSERT_EMT0(pVM);
+    Assert(RT_SUCCESS(pSSM->rc));
+
+    /*
+     * Write the end unit.
+     */
+    SSMFILEUNITHDRV2 UnitHdr;
+    memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic));
+    UnitHdr.offStream       = ssmR3StrmTell(&pSSM->Strm);
+    UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
+    UnitHdr.u32CRC          = 0;
+    UnitHdr.u32Version      = 0;
+    UnitHdr.u32Instance     = 0;
+    UnitHdr.u32Phase        = SSM_PHASE_FINAL;
+    UnitHdr.fFlags          = 0;
+    UnitHdr.cbName          = 0;
+    UnitHdr.u32CRC          = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0]));
+    Log(("SSM: Unit at %#9llx: END UNIT\n", UnitHdr.offStream));
+    int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0]));
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("SSM: Failed writing the end unit: %Rrc\n", rc));
+        return pSSM->rc = rc;
+    }
+
+    /*
+     * Write the directory for the final units and then the footer.
+     */
+    SSMFILEFTR Footer;
+    rc = ssmR3WriteDirectory(pVM, pSSM, &Footer.cDirEntries);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("SSM: Failed writing the directory: %Rrc\n", rc));
+        return pSSM->rc = rc;
+    }
+
+    memcpy(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic));
+    Footer.offStream    = ssmR3StrmTell(&pSSM->Strm);
+    Footer.u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
+    Footer.u32Reserved  = 0;
+    Footer.u32CRC       = 0;
+    Footer.u32CRC       = RTCrc32(&Footer, sizeof(Footer));
+    Log(("SSM: Footer at %#9llx: \n", Footer.offStream));
+    rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer));
+    if (RT_SUCCESS(rc))
+        rc = ssmR3StrmSetEnd(&pSSM->Strm);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("SSM: Failed writing the footer: %Rrc\n", rc));
+        return pSSM->rc = rc;
+    }
+
+    LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n",
+            Footer.offStream, Footer.offStream, Footer.cDirEntries));
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Do the pfnSaveExec run.
+ *
+ * @returns VBox status code (pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The saved state handle.
+ */
+static int ssmR3SaveDoExecRun(PVM pVM, PSSMHANDLE pSSM)
+{
+    VM_ASSERT_EMT0(pVM);
+    Assert(RT_SUCCESS(pSSM->rc));
+
+    pSSM->enmOp = SSMSTATE_SAVE_EXEC;
+    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
+    {
+        /*
+         * Not all unit have a callback. Skip those which don't and
+         * make sure to keep the progress indicator up to date.
+         */
+        pSSM->offEstUnitEnd += pUnit->cbGuess;
+        if (!pUnit->u.Common.pfnSaveExec)
+        {
+            pUnit->fCalled = true;
+            if (pUnit->cbGuess)
+                ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
+            continue;
+        }
+        pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
+
+        /*
+         * Write data unit header
+         */
+        SSMFILEUNITHDRV2 UnitHdr;
+        memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
+        UnitHdr.offStream       = pUnit->offStream;
+        UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
+        UnitHdr.u32CRC          = 0;
+        UnitHdr.u32Version      = pUnit->u32Version;
+        UnitHdr.u32Instance     = pUnit->u32Instance;
+        UnitHdr.u32Phase        = SSM_PHASE_FINAL;
+        UnitHdr.fFlags          = 0;
+        UnitHdr.cbName          = (uint32_t)pUnit->cchName + 1;
+        memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName);
+        UnitHdr.u32CRC          = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
+        Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
+             UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Phase, UnitHdr.u32Version));
+        int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
+        if (RT_FAILURE(rc))
+        {
+            LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
+            return pSSM->rc = rc;
+        }
+
+        /*
+         * Call the execute handler.
+         */
+        ssmR3DataWriteBegin(pSSM);
+        switch (pUnit->enmType)
+        {
+            case SSMUNITTYPE_DEV:
+                rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, pSSM);
+                break;
+            case SSMUNITTYPE_DRV:
+                rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, pSSM);
+                break;
+            case SSMUNITTYPE_INTERNAL:
+                rc = pUnit->u.Internal.pfnSaveExec(pVM, pSSM);
+                break;
+            case SSMUNITTYPE_EXTERNAL:
+                pUnit->u.External.pfnSaveExec(pSSM, pUnit->u.External.pvUser);
+                rc = pSSM->rc;
+                break;
+            default:
+                rc = VERR_INTERNAL_ERROR;
+                break;
+        }
+        pUnit->fCalled = true;
+        if (RT_SUCCESS(rc))
+            rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
+        if (RT_FAILURE(rc))
+        {
+            LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s'/#%u.\n", rc, pUnit->szName, pUnit->u32Instance));
+            if (RT_SUCCESS(pSSM->rc))
+                pSSM->rc = rc;
+            return rc;
+        }
+
+        /*
+         * Write the termination record and flush the compression stream.
+         */
+        SSMRECTERM TermRec;
+        TermRec.u8TypeAndFlags   = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
+        TermRec.cbRec            = sizeof(TermRec) - 2;
+        if (pSSM->Strm.fChecksummed)
+        {
+            TermRec.fFlags       = SSMRECTERM_FLAGS_CRC32;
+            TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
+        }
+        else
+        {
+            TermRec.fFlags       = 0;
+            TermRec.u32StreamCRC = 0;
+        }
+        TermRec.cbUnit           = pSSM->offUnit + sizeof(TermRec);
+        rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
+        if (RT_SUCCESS(rc))
+            rc = ssmR3DataWriteFinish(pSSM);
+        if (RT_FAILURE(rc))
+        {
+            LogRel(("SSM: Failed ending compression stream. rc=%Rrc\n", rc));
+            return pSSM->rc = rc;
+        }
+
+        /*
+         * Advance the progress indicator to the end of the current unit.
+         */
+        ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
+    } /* for each unit */
+
+
+    /* (progress should be pending 99% now) */
+    AssertMsg(pSSM->uPercent == (101 - pSSM->uPercentDone), ("%d\n", pSSM->uPercent));
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Do the pfnSavePrep run.
+ *
+ * @returns VBox status code (pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The saved state handle.
+ */
+static int ssmR3SaveDoPrepRun(PVM pVM, PSSMHANDLE pSSM)
+{
+    VM_ASSERT_EMT0(pVM);
+    Assert(RT_SUCCESS(pSSM->rc));
+
+    /*
+     * Do the prepare run.
+     */
+    pSSM->enmOp = SSMSTATE_SAVE_PREP;
+    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
+    {
+        if (pUnit->u.Common.pfnSavePrep)
+        {
+            int rc;
+            switch (pUnit->enmType)
+            {
+                case SSMUNITTYPE_DEV:
+                    rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, pSSM);
+                    break;
+                case SSMUNITTYPE_DRV:
+                    rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, pSSM);
+                    break;
+                case SSMUNITTYPE_INTERNAL:
+                    rc = pUnit->u.Internal.pfnSavePrep(pVM, pSSM);
+                    break;
+                case SSMUNITTYPE_EXTERNAL:
+                    rc = pUnit->u.External.pfnSavePrep(pSSM, pUnit->u.External.pvUser);
+                    break;
+                default:
+                    rc = VERR_INTERNAL_ERROR;
+                    break;
+            }
+            pUnit->fCalled = true;
+            if (RT_SUCCESS(rc))
+                rc = pSSM->rc;
+            if (RT_FAILURE(rc))
+            {
+                LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
+                if (RT_SUCCESS(pSSM->rc))
+                    pSSM->rc = rc;
+                return rc;
+            }
+        }
+
+        pSSM->cbEstTotal += pUnit->cbGuess;
+    }
+
+    /*
+     * Work the progress indicator if we got one.
+     */
+    if (pSSM->pfnProgress)
+        pSSM->pfnProgress(pVM, pSSM->uPercentPrepare-1, pSSM->pvUser);
+    pSSM->uPercent = pSSM->uPercentPrepare;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Common worker for SSMR3Save and SSMR3Migrate.
+ *
+ * @returns VBox status code (no need to check pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The state handle.
+ *
+ * @thread  EMT(0)
+ */
+static int ssmR3SaveDoCommon(PVM pVM, PSSMHANDLE pSSM)
+{
+    VM_ASSERT_EMT0(pVM);
+
+    /*
+     * Do the work.
+     */
+    int rc = ssmR3SaveDoPrepRun(pVM, pSSM);
+    if (RT_SUCCESS(rc))
+    {
+        rc = ssmR3SaveDoExecRun(pVM, pSSM);
+        if (RT_SUCCESS(rc))
+            rc = ssmR3SaveDoFinalization(pVM, pSSM);
+    }
+    Assert(pSSM->rc == rc);
+    int rc2 = ssmR3SaveDoDoneRun(pVM, pSSM);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+
+/**
+ * Saves the rest of the state on EMT0.
+ *
+ * @returns VBox status.
+ *
+ * @param   pSSM            The SSM handle returned by SSMR3LiveToFile or
+ *                          SSMR3LiveToRemote.
+ *
+ * @thread  Non-EMT thread. Will involve the EMT at the end of the operation.
+ */
+VMMR3DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM)
+{
+    LogFlow(("SSMR3LiveDoStep2: pSSM=%p\n", pSSM));
+
+    /*
+     * Validate input.
+     */
+    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
+    PVM pVM = pSSM->pVM;
+    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+    VM_ASSERT_EMT0(pVM);
+    AssertMsgReturn(   pSSM->enmAfter == SSMAFTER_DESTROY
+                    || pSSM->enmAfter == SSMAFTER_CONTINUE,
+                    ("%d\n", pSSM->enmAfter),
+                    VERR_INVALID_PARAMETER);
+    AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_PREP, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
+
+    /*
+     * Join paths with VMMR3Save.
+     */
+    return ssmR3SaveDoCommon(pVM, pSSM);
+}
+
+
+/**
+ * Writes the file header and clear the per-unit data.
+ *
+ * @returns VBox status code.
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The SSM handle.
+ */
+static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM)
+{
+    /*
+     * Write the header.
+     */
+    SSMFILEHDR FileHdr;
+    memcpy(&FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(FileHdr.szMagic));
+    FileHdr.u16VerMajor  = VBOX_VERSION_MAJOR;
+    FileHdr.u16VerMinor  = VBOX_VERSION_MINOR;
+    FileHdr.u32VerBuild  = VBOX_VERSION_BUILD;
+    FileHdr.u32SvnRev    = VMMGetSvnRev(),
+    FileHdr.cHostBits    = HC_ARCH_BITS;
+    FileHdr.cbGCPhys     = sizeof(RTGCPHYS);
+    FileHdr.cbGCPtr      = sizeof(RTGCPTR);
+    FileHdr.u8Reserved   = 0;
+    FileHdr.cUnits       = pVM->ssm.s.cUnits;
+    FileHdr.fFlags       = SSMFILEHDR_FLAGS_STREAM_CRC32;
+    FileHdr.cbMaxDecompr = RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer);
+    FileHdr.u32CRC       = 0;
+    FileHdr.u32CRC       = RTCrc32(&FileHdr, sizeof(FileHdr));
+    int rc = ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr));
+    if (RT_SUCCESS(rc))
+        return rc;
+
+    /*
+     * Clear the per unit flags and offsets.
+     */
+    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
+    {
+        pUnit->fCalled   = false;
+        pUnit->offStream = RTFOFF_MIN;
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Creates a new saved state file.
+ *
+ * @returns VBox status code.
+ * @param   pVM                 The VM handle.
+ * @param   pszFilename         The name of the file.
+ * @param   enmAfter            What to do afterwards.
+ * @param   pfnProgress         The progress callback.
+ * @param   pvUser              The progress callback user argument.
+ * @param   ppSSM               Where to return the pointer to the saved state
+ *                              handle upon successful return.  Free it using
+ *                              RTMemFree after closing the stream.
+ */
+static int ssmR3SaveDoCreateFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter,
+                                 PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM)
+{
+    PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
+    if (!pSSM)
+        return VERR_NO_MEMORY;
+
+    pSSM->pVM                   = pVM;
+    pSSM->enmOp                 = SSMSTATE_INVALID;
+    pSSM->enmAfter              = enmAfter;
+    pSSM->rc                    = VINF_SUCCESS;
+    pSSM->cbUnitLeftV1          = 0;
+    pSSM->offUnit               = UINT64_MAX;
+    pSSM->pfnProgress           = pfnProgress;
+    pSSM->pvUser                = pvUser;
+    pSSM->uPercent              = 0;
+    pSSM->offEstProgress        = 0;
+    pSSM->cbEstTotal            = 0;
+    pSSM->offEst                = 0;
+    pSSM->offEstUnitEnd         = 0;
+    pSSM->uPercentPrepare       = 0;
+    pSSM->uPercentDone          = 0;
+    pSSM->pszFilename           = pszFilename;
+    pSSM->u.Write.offDataBuffer = 0;
+
+    int rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, true /*fWrite*/, true /*fChecksummed*/, 8 /*cBuffers*/);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n",  pszFilename, rc));
+        RTMemFree(pSSM);
+        return rc;
+    }
+
+    *ppSSM = pSSM;
+    return VINF_SUCCESS;
+}
+
+
+/**
  * Start VM save operation.
  *
@@ -3348,5 +3923,5 @@
 {
     LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
-    VM_ASSERT_EMT(pVM);
+    VM_ASSERT_EMT0(pVM);
 
     /*
@@ -3354,338 +3929,284 @@
      */
     AssertMsgReturn(   enmAfter == SSMAFTER_DESTROY
-                    || enmAfter == SSMAFTER_CONTINUE
-                    || enmAfter == SSMAFTER_MIGRATE,
+                    || enmAfter == SSMAFTER_CONTINUE,
                     ("%d\n", enmAfter),
                     VERR_INVALID_PARAMETER);
 
     /*
-     * Create the handle and try open the file.
+     * Create the saved state file and handle.
      *
      * Note that there might be quite some work to do after executing the saving,
-     * so we reserve 20% for the 'Done' period.  The checksumming and closing of
-     * the saved state file might take a long time.
-     */
-    SSMHANDLE Handle;
-    RT_ZERO(Handle);
-    Handle.pVM              = pVM;
-    Handle.enmOp            = SSMSTATE_INVALID;
-    Handle.enmAfter         = enmAfter;
-    Handle.rc               = VINF_SUCCESS;
-    Handle.cbUnitLeftV1     = 0;
-    Handle.offUnit          = UINT64_MAX;
-    Handle.pfnProgress      = pfnProgress;
-    Handle.pvUser           = pvUser;
-    Handle.uPercent         = 0;
-    Handle.offEstProgress   = 0;
-    Handle.cbEstTotal       = 0;
-    Handle.offEst           = 0;
-    Handle.offEstUnitEnd    = 0;
-    Handle.uPercentPrepare  = 20;
-    Handle.uPercentDone     = 2;
-    Handle.u.Write.offDataBuffer    = 0;
-
-    int rc = ssmR3StrmOpenFile(&Handle.Strm, pszFilename, true /*fWrite*/, true /*fChecksummed*/, 8 /*cBuffers*/);
+     * so we reserve 20% for the 'Done' period.
+     */
+    PSSMHANDLE pSSM;
+    int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, enmAfter, pfnProgress, pvUser, &pSSM);
     if (RT_FAILURE(rc))
-    {
-        LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n",  pszFilename, rc));
         return rc;
-    }
-
+    pSSM->uPercentPrepare = 20;
+    pSSM->uPercentDone    = 2;
+
+    /*
+     * Write the saved state stream header and join paths with
+     * the other save methods for the rest of the job.
+     */
     Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
-    ssmR3StrmStartIoThread(&Handle.Strm);
-
-    /*
-     * Write header.
-     */
-    union
-    {
-        SSMFILEHDR          FileHdr;
-        SSMFILEUNITHDRV2    UnitHdr;
-        SSMFILEFTR          Footer;
-    } u;
-
-    memcpy(&u.FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(u.FileHdr.szMagic));
-    u.FileHdr.u16VerMajor  = VBOX_VERSION_MAJOR;
-    u.FileHdr.u16VerMinor  = VBOX_VERSION_MINOR;
-    u.FileHdr.u32VerBuild  = VBOX_VERSION_BUILD;
-    u.FileHdr.u32SvnRev    = VMMGetSvnRev(),
-    u.FileHdr.cHostBits    = HC_ARCH_BITS;
-    u.FileHdr.cbGCPhys     = sizeof(RTGCPHYS);
-    u.FileHdr.cbGCPtr      = sizeof(RTGCPTR);
-    u.FileHdr.u8Reserved   = 0;
-    u.FileHdr.cUnits       = pVM->ssm.s.cUnits;
-    u.FileHdr.fFlags       = SSMFILEHDR_FLAGS_STREAM_CRC32;
-    u.FileHdr.cbMaxDecompr = RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer);
-    u.FileHdr.u32CRC       = 0;
-    u.FileHdr.u32CRC       = RTCrc32(&u.FileHdr, sizeof(u.FileHdr));
-    rc = ssmR3StrmWrite(&Handle.Strm, &u.FileHdr, sizeof(u.FileHdr));
+    ssmR3StrmStartIoThread(&pSSM->Strm);
+    rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM);
     if (RT_SUCCESS(rc))
-    {
-        /*
-         * Clear the per unit flags and offsets.
-         */
-        PSSMUNIT pUnit;
-        for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
-        {
-            pUnit->fCalled   = false;
-            pUnit->offStream = RTFOFF_MIN;
-        }
-
-        /*
-         * Do the prepare run.
-         */
-        Handle.rc = VINF_SUCCESS;
-        Handle.enmOp = SSMSTATE_SAVE_PREP;
-        for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
-        {
-            if (pUnit->u.Common.pfnSavePrep)
+        ssmR3SaveDoCommon(pVM, pSSM);
+    return ssmR3SaveDoClose(pVM, pSSM);
+}
+
+
+/**
+ * Calls pfnLiveVote for all units.
+ *
+ * @returns VBox status code (no need to check pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The saved state handle.
+ */
+static int ssmR3DoLiveVoteRun(PVM pVM, PSSMHANDLE pSSM)
+{
+    /*
+     * Do the prepare run.
+     */
+    AssertRCReturn(pSSM->rc, pSSM->rc);
+    pSSM->rc = VINF_SUCCESS;
+    pSSM->enmOp = SSMSTATE_LIVE_VOTE;
+    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
+    {
+        if (pUnit->u.Common.pfnLiveVote)
+        {
+            int rc;
+            switch (pUnit->enmType)
             {
-                switch (pUnit->enmType)
+                case SSMUNITTYPE_DEV:
+                    rc = pUnit->u.Dev.pfnLiveVote(pUnit->u.Dev.pDevIns, pSSM);
+                    break;
+                case SSMUNITTYPE_DRV:
+                    rc = pUnit->u.Drv.pfnLiveVote(pUnit->u.Drv.pDrvIns, pSSM);
+                    break;
+                case SSMUNITTYPE_INTERNAL:
+                    rc = pUnit->u.Internal.pfnLiveVote(pVM, pSSM);
+                    break;
+                case SSMUNITTYPE_EXTERNAL:
+                    rc = pUnit->u.External.pfnLiveVote(pSSM, pUnit->u.External.pvUser);
+                    break;
+                default:
+                    rc = VERR_INTERNAL_ERROR;
+                    break;
+            }
+            Assert(pSSM->rc == VINF_SUCCESS);
+
+            pUnit->fCalled = true;
+            if (rc != VINF_SUCCESS)
+            {
+                if (rc == VINF_SSM_VOTE_FOR_ANOTHER_PASS)
                 {
-                    case SSMUNITTYPE_DEV:
-                        rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, &Handle);
-                        break;
-                    case SSMUNITTYPE_DRV:
-                        rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, &Handle);
-                        break;
-                    case SSMUNITTYPE_INTERNAL:
-                        rc = pUnit->u.Internal.pfnSavePrep(pVM, &Handle);
-                        break;
-                    case SSMUNITTYPE_EXTERNAL:
-                        rc = pUnit->u.External.pfnSavePrep(&Handle, pUnit->u.External.pvUser);
-                        break;
+                    Log(("ssmR3DoLiveVoteRun: '%s'/#%u -> VINF_SSM_VOTE_FOR_ANOTHER_PASS\n", pUnit, pUnit->u32Instance));
+                    return VINF_SSM_VOTE_FOR_ANOTHER_PASS;
                 }
-                pUnit->fCalled = true;
-                if (RT_FAILURE(rc))
-                {
-                    LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
+                Log(("ssmR3DoLiveVoteRun: '%s'/#%u -> %Rrc!!\n", pUnit, pUnit->u32Instance, rc));
+                AssertMsgReturn(RT_FAILURE(rc), ("%Rrc; '%s'\n", rc, pUnit->szName), pSSM->rc = VERR_IPE_UNEXPECTED_INFO_STATUS);
+                return rc;
+            }
+        }
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Continue a live state saving operation on the worker thread.
+ *
+ * The
+ *
+ * @returns VBox status.
+ *
+ * @param   pSSM            The SSM handle returned by SSMR3LiveToFile or
+ *                          SSMR3LiveToRemote.
+ *
+ * @thread  Non-EMT thread. Will involve the EMT at the end of the operation.
+ */
+VMMR3DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM)
+{
+    LogFlow(("SSMR3LiveDoStep1: pSSM=%p\n", pSSM));
+
+    /*
+     * Validate input.
+     */
+    AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
+    PVM pVM = pSSM->pVM;
+    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+    VM_ASSERT_OTHER_THREAD(pVM);
+    AssertMsgReturn(   pSSM->enmAfter == SSMAFTER_DESTROY
+                    || pSSM->enmAfter == SSMAFTER_CONTINUE,
+                    ("%d\n", pSSM->enmAfter),
+                    VERR_INVALID_PARAMETER);
+    AssertMsgReturn(pSSM->enmOp == SSMSTATE_LIVE_EXEC, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
+
+    /*
+     * ...
+     */
+
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Calls pfnLivePrep for all units.
+ *
+ * @returns VBox status code (no need to check pSSM->rc).
+ * @param   pVM                 The VM handle.
+ * @param   pSSM                The saved state handle.
+ */
+static int ssmR3DoLivePrepRun(PVM pVM, PSSMHANDLE pSSM)
+{
+    /*
+     * Do the prepare run.
+     */
+    pSSM->rc = VINF_SUCCESS;
+    pSSM->enmOp = SSMSTATE_SAVE_PREP;
+    for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
+    {
+        if (pUnit->u.Common.pfnLivePrep)
+        {
+            int rc;
+            switch (pUnit->enmType)
+            {
+                case SSMUNITTYPE_DEV:
+                    rc = pUnit->u.Dev.pfnLivePrep(pUnit->u.Dev.pDevIns, pSSM);
                     break;
-                }
+                case SSMUNITTYPE_DRV:
+                    rc = pUnit->u.Drv.pfnLivePrep(pUnit->u.Drv.pDrvIns, pSSM);
+                    break;
+                case SSMUNITTYPE_INTERNAL:
+                    rc = pUnit->u.Internal.pfnLivePrep(pVM, pSSM);
+                    break;
+                case SSMUNITTYPE_EXTERNAL:
+                    rc = pUnit->u.External.pfnLivePrep(pSSM, pUnit->u.External.pvUser);
+                    break;
+                default:
+                    rc = VERR_INTERNAL_ERROR;
+                    break;
             }
-
-            Handle.cbEstTotal += pUnit->cbGuess;
-        }
-
-        /* Progress. */
-        if (pfnProgress)
-            pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
-        Handle.uPercent = Handle.uPercentPrepare;
-
-        /*
-         * Do the execute run.
-         */
+            pUnit->fCalled = true;
+            if (RT_SUCCESS(rc))
+                rc = pSSM->rc;
+            if (RT_FAILURE(rc))
+            {
+                LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
+                if (RT_SUCCESS(pSSM->rc))
+                    pSSM->rc = rc;
+                return rc;
+            }
+        }
+
+        pSSM->cbEstTotal += pUnit->cbGuess;
+    }
+
+    /*
+     * Work the progress indicator if we got one.
+     */
+    if (pSSM->pfnProgress)
+        pSSM->pfnProgress(pVM, 2, pSSM->pvUser);
+    pSSM->uPercent = 2;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Start saving the live state to a file.
+ *
+ * The live saving sequence is something like this:
+ *
+ *      -# SSMR3LiveToFile is called on EMT0.  It returns a saved state
+ *         handle.
+ *      -# SSMR3LiveDoStep1 is called on a non-EMT.  This will save the major
+ *         parts of the state while the VM may still be running.
+ *      -# The VM is suspended.
+ *      -# SSMR3LiveDoStep2 is called on EMT0 to save the remainder of the state
+ *         in the normal way.
+ *      -# The client does any necessary reconfiguration of harddisks and
+ *         similar.
+ *      -# SSMR3LiveDone is called on EMT0 to close the handle.
+ *      -# The VM is resumed or powered off and destroyed.
+ *
+ * SSMR3LiveDone should be called even if SSMR3LiveDoStep1 or SSMR3LiveDoStep2
+ * fails.
+ *
+ * @returns VBox status.
+ *
+ * @param   pVM             The VM handle.
+ * @param   pszFilename     Name of the file to save the state in.  This string
+ *                          must remain valid until SSMR3LiveDone is called.
+ * @param   enmAfter        What is planned after a successful save operation.
+ * @param   pfnProgress     Progress callback. Optional.
+ * @param   pvUser          User argument for the progress callback.
+ *
+ * @thread  EMT0
+ */
+VMMR3DECL(int) SSMR3LiveToFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter,
+                               PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM)
+{
+    LogFlow(("SSMR3LiveToFile: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
+    VM_ASSERT_EMT0(pVM);
+
+    /*
+     * Validate input.
+     */
+    AssertMsgReturn(   enmAfter == SSMAFTER_DESTROY
+                    || enmAfter == SSMAFTER_CONTINUE,
+                    ("%d\n", enmAfter),
+                    VERR_INVALID_PARAMETER);
+
+    /*
+     * Create the saved state file and handle.
+     *
+     * Note that there might be quite some work to do after executing the saving,
+     * so we reserve 20% for the 'Done' period.
+     */
+    PSSMHANDLE pSSM;
+    int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, enmAfter, pfnProgress, pvUser, &pSSM);
+    if (RT_FAILURE(rc))
+        return rc;
+    pSSM->uPercentPrepare = 20; /** @todo fix these. */
+    pSSM->uPercentDone    = 2;
+
+    /*
+     * Write the saved state stream header and do the prep run for live saving.
+     */
+    Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
+    ssmR3StrmStartIoThread(&pSSM->Strm);
+    rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM);
+    if (RT_SUCCESS(rc))
+    {
+/** @todo If it turns out we don't need to do ssmR3DoLivePrepRun on EMT0,
+ *        simply move the code to SSMR3LiveDoStep1. */
+        rc = ssmR3DoLivePrepRun(pVM, pSSM);
         if (RT_SUCCESS(rc))
         {
-            Handle.enmOp = SSMSTATE_SAVE_EXEC;
-            for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
-            {
-                /*
-                 * Estimate.
-                 */
-                ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
-                Handle.offEstUnitEnd += pUnit->cbGuess;
-
-                /*
-                 * Does this unit have a callback? If, not skip it.
-                 */
-                if (!pUnit->u.Common.pfnSaveExec)
-                {
-                    pUnit->fCalled = true;
-                    continue;
-                }
-                pUnit->offStream = ssmR3StrmTell(&Handle.Strm);
-
-                /*
-                 * Write data unit header
-                 */
-                memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(u.UnitHdr.szMagic));
-                u.UnitHdr.offStream       = pUnit->offStream;
-                u.UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&Handle.Strm);
-                u.UnitHdr.u32CRC          = 0;
-                u.UnitHdr.u32Version      = pUnit->u32Version;
-                u.UnitHdr.u32Instance     = pUnit->u32Instance;
-                u.UnitHdr.u32Phase        = SSM_PHASE_FINAL;
-                u.UnitHdr.fFlags          = 0;
-                u.UnitHdr.cbName          = (uint32_t)pUnit->cchName + 1;
-                memcpy(&u.UnitHdr.szName[0], &pUnit->szName[0], u.UnitHdr.cbName);
-                u.UnitHdr.u32CRC          = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[u.UnitHdr.cbName]));
-                Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
-                     u.UnitHdr.offStream, u.UnitHdr.szName, u.UnitHdr.u32Instance, u.UnitHdr.u32Phase, u.UnitHdr.u32Version));
-                rc = ssmR3StrmWrite(&Handle.Strm, &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[u.UnitHdr.cbName]));
-                if (RT_SUCCESS(rc))
-                {
-                    /*
-                     * Call the execute handler.
-                     */
-                    ssmR3DataWriteBegin(&Handle);
-                    switch (pUnit->enmType)
-                    {
-                        case SSMUNITTYPE_DEV:
-                            rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, &Handle);
-                            break;
-                        case SSMUNITTYPE_DRV:
-                            rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, &Handle);
-                            break;
-                        case SSMUNITTYPE_INTERNAL:
-                            rc = pUnit->u.Internal.pfnSaveExec(pVM, &Handle);
-                            break;
-                        case SSMUNITTYPE_EXTERNAL:
-                            pUnit->u.External.pfnSaveExec(&Handle, pUnit->u.External.pvUser);
-                            rc = Handle.rc;
-                            break;
-                    }
-                    pUnit->fCalled = true;
-                    if (RT_SUCCESS(rc))
-                        rc = ssmR3DataFlushBuffer(&Handle); /* will return SSMHANDLE::rc if its set */
-                    if (RT_SUCCESS(rc))
-                    {
-                        /*
-                         * Write the termination record and flush the compression stream.
-                         */
-                        SSMRECTERM TermRec;
-                        TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
-                        TermRec.cbRec       = sizeof(TermRec) - 2;
-                        if (Handle.Strm.fChecksummed)
-                        {
-                            TermRec.fFlags       = SSMRECTERM_FLAGS_CRC32;
-                            TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&Handle.Strm), &TermRec, 2));
-                        }
-                        else
-                        {
-                            TermRec.fFlags       = 0;
-                            TermRec.u32StreamCRC = 0;
-                        }
-                        TermRec.cbUnit      = Handle.offUnit + sizeof(TermRec);
-                        rc = ssmR3DataWriteRaw(&Handle, &TermRec, sizeof(TermRec));
-                        if (RT_SUCCESS(rc))
-                            rc = ssmR3DataWriteFinish(&Handle);
-                        if (RT_SUCCESS(rc))
-                            Handle.offUnit     = UINT64_MAX;
-                        else
-                        {
-                            LogRel(("SSM: Failed ending compression stream. rc=%Rrc\n", rc));
-                            break;
-                        }
-                    }
-                    else
-                    {
-                        LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
-                        break;
-                    }
-                }
-                if (RT_FAILURE(rc))
-                {
-                    LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
-                    break;
-                }
-            } /* for each unit */
-
-            /* finish the progress. */
-            if (RT_SUCCESS(rc))
-                ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
-        }
-        /* (progress should be pending 99% now) */
-        AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
-
-        /*
-         * Finalize the file if successfully saved.
-         */
-        if (RT_SUCCESS(rc))
-        {
-            /* Write the end unit. */
-            memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(u.UnitHdr.szMagic));
-            u.UnitHdr.offStream       = ssmR3StrmTell(&Handle.Strm);
-            u.UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&Handle.Strm);
-            u.UnitHdr.u32CRC          = 0;
-            u.UnitHdr.u32Version      = 0;
-            u.UnitHdr.u32Instance     = 0;
-            u.UnitHdr.u32Phase        = SSM_PHASE_FINAL;
-            u.UnitHdr.fFlags          = 0;
-            u.UnitHdr.cbName          = 0;
-            u.UnitHdr.u32CRC          = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0]));
-            Log(("SSM: Unit at %#9llx: END UNIT\n", u.UnitHdr.offStream));
-            rc = ssmR3StrmWrite(&Handle.Strm,  &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0]));
-            if (RT_SUCCESS(rc))
-            {
-                /* Write the directory for the final units and then the footer. */
-                rc = ssmR3WriteDirectory(pVM, &Handle, &u.Footer.cDirEntries);
-                if (RT_SUCCESS(rc))
-                {
-                    memcpy(u.Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(u.Footer.szMagic));
-                    u.Footer.offStream    = ssmR3StrmTell(&Handle.Strm);
-                    u.Footer.u32StreamCRC = ssmR3StrmFinalCRC(&Handle.Strm);
-                    u.Footer.u32Reserved  = 0;
-                    u.Footer.u32CRC       = 0;
-                    u.Footer.u32CRC       = RTCrc32(&u.Footer, sizeof(u.Footer));
-                    Log(("SSM: Footer at %#9llx: \n", u.Footer.offStream));
-                    rc = ssmR3StrmWrite(&Handle.Strm, &u.Footer, sizeof(u.Footer));
-                    if (RT_SUCCESS(rc))
-                        rc = ssmR3StrmSetEnd(&Handle.Strm);
-                }
-            }
-            if (RT_FAILURE(rc))
-                LogRel(("SSM: Failed to finalize state file! rc=%Rrc\n", rc));
-        }
-
-        /*
-         * Do the done run.
-         */
-        Handle.rc = rc;
-        Handle.enmOp = SSMSTATE_SAVE_DONE;
-        for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
-        {
-            if (    pUnit->u.Common.pfnSaveDone
-                &&  (   pUnit->fCalled
-                     || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec)))
-            {
-                switch (pUnit->enmType)
-                {
-                    case SSMUNITTYPE_DEV:
-                        rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, &Handle);
-                        break;
-                    case SSMUNITTYPE_DRV:
-                        rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, &Handle);
-                        break;
-                    case SSMUNITTYPE_INTERNAL:
-                        rc = pUnit->u.Internal.pfnSaveDone(pVM, &Handle);
-                        break;
-                    case SSMUNITTYPE_EXTERNAL:
-                        rc = pUnit->u.External.pfnSaveDone(&Handle, pUnit->u.External.pvUser);
-                        break;
-                }
-                if (RT_FAILURE(rc))
-                {
-                    LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
-                    if (RT_SUCCESS(Handle.rc))
-                        Handle.rc = rc;
-                }
-            }
-        }
-        rc = Handle.rc;
-
-        /*
-         * Close the file and return if we've succeeded.
-         */
-        if (RT_SUCCESS(rc))
-            rc = ssmR3StrmClose(&Handle.Strm);
-        if (RT_SUCCESS(rc))
-        {
-            if (pfnProgress)
-                pfnProgress(pVM, 100, pvUser);
-            LogRel(("SSM: Successfully saved the VM state to '%s'\n"
-                    "SSM: Footer at %#llx (%lld), %u directory entries.\n",
-                    pszFilename, u.Footer.offStream, u.Footer.offStream, u.Footer.cDirEntries));
+            /*
+             * Return and let the requstor thread do the pfnLiveExec/Vote part
+             * via SSMR3SaveFinishLive
+             */
+            *ppSSM = pSSM;
             return VINF_SUCCESS;
         }
     }
-
-    /*
-     * Delete the file on failure.
-     */
-    ssmR3StrmClose(&Handle.Strm);
-    int rc2 = RTFileDelete(pszFilename);
+    /* bail out. */
+    int rc2 = ssmR3StrmClose(&pSSM->Strm);
+    RTMemFree(pSSM);
+    rc2 = RTFileDelete(pszFilename);
     AssertRC(rc2);
-
     return rc;
+}
+
+
+VMMR3DECL(int) SSMR3LiveToRemote(PVM pVM, PFNVMPROGRESS pfnProgress, void *pvUser /*,
+                                 invent stream interface and stuff */)
+{
+    return VERR_NOT_IMPLEMENTED;
 }
 
@@ -5453,4 +5974,5 @@
     pSSM->uPercentPrepare  = 5;
     pSSM->uPercentDone     = 2;
+    pSSM->pszFilename      = pszFilename;
 
     pSSM->u.Read.pZipDecompV1   = NULL;
@@ -5612,4 +6134,7 @@
                                 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, SSM_PHASE_FINAL);
                                 break;
+                            default:
+                                rc = VERR_INTERNAL_ERROR;
+                                break;
                         }
 
@@ -5791,4 +6316,7 @@
                     rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, UnitHdr.u32Phase);
                     break;
+                default:
+                    rc = VERR_INTERNAL_ERROR;
+                    break;
             }
             ssmR3DataReadFinishV2(pSSM);
@@ -5841,5 +6369,5 @@
 {
     LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
-    VM_ASSERT_EMT(pVM);
+    VM_ASSERT_EMT0(pVM);
 
     /*
@@ -5908,4 +6436,7 @@
                     case SSMUNITTYPE_EXTERNAL:
                         rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
+                        break;
+                    default:
+                        rc = VERR_INTERNAL_ERROR;
                         break;
                 }
@@ -5964,4 +6495,7 @@
                         rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
                         break;
+                    default:
+                        rc = VERR_INTERNAL_ERROR;
+                        break;
                 }
                 if (RT_FAILURE(rc))
@@ -6399,4 +6933,5 @@
 VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
 {
+    Assert(pSSM->enmOp != SSMSTATE_LIVE_VOTE);
     if (RT_FAILURE(iStatus))
     {
Index: /trunk/src/VBox/VMM/VM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VM.cpp	(revision 22791)
+++ /trunk/src/VBox/VMM/VM.cpp	(revision 22792)
@@ -1473,6 +1473,7 @@
      * Change the state and perform the save.
      */
+    bool fLive = pVM->enmVMState == VMSTATE_RUNNING;
     vmR3SetState(pVM, VMSTATE_SAVING); /** @todo Should probably use a different state for live snapshots and/or live migration. Will fix the state machine later. */
-    int rc = SSMR3Save(pVM, pszFilename, enmAfter, pfnProgress,  pvUser);
+    int rc = SSMR3Save(pVM, pszFilename, enmAfter, pfnProgress, pvUser);
     vmR3SetState(pVM, VMSTATE_SUSPENDED);
 
