Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 22883)
+++ /trunk/include/VBox/err.h	(revision 22884)
@@ -587,4 +587,10 @@
 /** The VM was paused while saving, don't resume execution. */
 #define VINF_SSM_LIVE_PAUSED                    1859
+/** The operation was cancelled. */
+#define VERR_SSM_CANCELLED                      (-1860)
+/** Nothing that can be cancelled.  */
+#define VERR_SSM_NO_PENDING_OPERATION           (-1861)
+/** The operation has already been cancelled. */
+#define VERR_SSM_ALREADY_CANCELLED              (-1862)
 /** @} */
 
Index: /trunk/include/VBox/ssm.h
===================================================================
--- /trunk/include/VBox/ssm.h	(revision 22883)
+++ /trunk/include/VBox/ssm.h	(revision 22884)
@@ -623,40 +623,41 @@
 
 
-VMMR3DECL(int) SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore,
-    PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote,
-    PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
-    PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone);
-VMMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
-    PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
-    PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
-    PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone);
-VMMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
-    PFNSSMINTLIVEPREP pfnLivePrep, PFNSSMINTLIVEEXEC pfnLiveExec, PFNSSMINTLIVEVOTE pfnLiveVote,
-    PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone,
-    PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone);
-VMMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
-    PFNSSMEXTLIVEPREP pfnLivePrep, PFNSSMEXTLIVEEXEC pfnLiveExec, PFNSSMEXTLIVEVOTE pfnLiveVote,
-    PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone,
-    PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser);
-VMMR3_INT_DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance);
-VMMR3_INT_DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance);
-VMMR3DECL(int)      SSMR3DeregisterInternal(PVM pVM, const char *pszName);
-VMMR3DECL(int)      SSMR3DeregisterExternal(PVM pVM, const char *pszName);
-VMMR3DECL(int)      SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser);
-VMMR3_INT_DECL(int) SSMR3LiveToFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter,
-                                    PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM);
-VMMR3_INT_DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM);
-VMMR3_INT_DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM);
-VMMR3_INT_DECL(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);
-VMMR3DECL(int)      SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM);
-VMMR3DECL(int)      SSMR3Close(PSSMHANDLE pSSM);
-VMMR3DECL(int)      SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion);
-VMMR3DECL(int)      SSMR3HandleGetStatus(PSSMHANDLE pSSM);
-VMMR3DECL(int)      SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus);
-VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM);
-VMMR3DECL(uint64_t) SSMR3HandleGetUnitOffset(PSSMHANDLE pSSM);
-VMMR3_INT_DECL(int) SSMR3SetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr);
+VMMR3_INT_DECL(void)    SSMR3Term(PVM pVM);
+VMMR3DECL(int)          SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore,
+                                            PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote,
+                                            PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
+                                            PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone);
+VMMR3DECL(int)          SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
+                                            PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
+                                            PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
+                                            PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone);
+VMMR3DECL(int)          SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
+                                              PFNSSMINTLIVEPREP pfnLivePrep, PFNSSMINTLIVEEXEC pfnLiveExec, PFNSSMINTLIVEVOTE pfnLiveVote,
+                                              PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone,
+                                              PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone);
+VMMR3DECL(int)          SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
+                                              PFNSSMEXTLIVEPREP pfnLivePrep, PFNSSMEXTLIVEEXEC pfnLiveExec, PFNSSMEXTLIVEVOTE pfnLiveVote,
+                                              PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone,
+                                              PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser);
+VMMR3_INT_DECL(int)     SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance);
+VMMR3_INT_DECL(int)     SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance);
+VMMR3DECL(int)          SSMR3DeregisterInternal(PVM pVM, const char *pszName);
+VMMR3DECL(int)          SSMR3DeregisterExternal(PVM pVM, const char *pszName);
+VMMR3DECL(int)          SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser);
+VMMR3_INT_DECL(int)     SSMR3LiveToFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter,
+                                        PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM);
+VMMR3_INT_DECL(int)     SSMR3LiveDoStep1(PSSMHANDLE pSSM);
+VMMR3_INT_DECL(int)     SSMR3LiveDoStep2(PSSMHANDLE pSSM);
+VMMR3_INT_DECL(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);
+VMMR3DECL(int)          SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM);
+VMMR3DECL(int)          SSMR3Close(PSSMHANDLE pSSM);
+VMMR3DECL(int)          SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion);
+VMMR3DECL(int)          SSMR3HandleGetStatus(PSSMHANDLE pSSM);
+VMMR3DECL(int)          SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus);
+VMMR3DECL(SSMAFTER)     SSMR3HandleGetAfter(PSSMHANDLE pSSM);
+VMMR3DECL(uint64_t)     SSMR3HandleGetUnitOffset(PSSMHANDLE pSSM);
+VMMR3_INT_DECL(int)     SSMR3SetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr);
 
 
Index: /trunk/src/VBox/VMM/SSM.cpp
===================================================================
--- /trunk/src/VBox/VMM/SSM.cpp	(revision 22883)
+++ /trunk/src/VBox/VMM/SSM.cpp	(revision 22884)
@@ -260,4 +260,10 @@
 #define SSM_LOG_BYTES                           16
 
+/** SSMHANDLE::fCancelled value indicating that the operation has been
+ *  cancelled. */
+#define SSMHANDLE_CANCELLED                     UINT32_C(0xdeadbeef)
+/** SSMHANDLE::fCancelled value indicating no cancellation. */
+#define SSMHANDLE_OK                            UINT32_C(0x77777777)
+
 
 /** Macro for checking the u32CRC field of a structure.
@@ -296,4 +302,19 @@
                     || pSSM->enmOp == SSMSTATE_OPEN_READ,\
                     ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
+
+/** Checks for cancellation and returns if pending.
+ * Sets SSMHANDLE::rc to VERR_SSM_CANCELLED (if it still indicates success) and
+ * then returns SSMHANDLE::rc. (Debug logging only.) */
+#define SSM_CHECK_CANCELLED_RET(pSSM) \
+    do \
+    { \
+        if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED)) \
+        { \
+            LogFlow(("%Rfn: Cancelled -> VERR_SSM_CANCELLED\n", __PRETTY_FUNCTION__)); \
+            if (RT_SUCCESS((pSSM)->rc)) \
+                (pSSM)->rc = VERR_SSM_CANCELLED; \
+            return (pSSM)->rc; \
+        } \
+    } while (0)
 
 
@@ -403,40 +424,42 @@
 {
     /** Stream/buffer manager. */
-    SSMSTRM         Strm;
+    SSMSTRM                 Strm;
 
     /** The VM handle. */
-    PVM             pVM;
+    PVM                     pVM;
     /** The current operation. */
-    SSMSTATE        enmOp;
+    SSMSTATE                enmOp;
     /** What to do after save completes. (move the enum) */
-    SSMAFTER        enmAfter;
+    SSMAFTER                enmAfter;
+    /** Flag indicating that the operation has been cancelled. */
+    uint32_t volatile       fCancelled;
     /** The current rc of the save operation. */
-    int             rc;
+    int32_t                 rc;
     /** Number of compressed bytes left in the current data unit (V1). */
-    uint64_t        cbUnitLeftV1;
+    uint64_t                cbUnitLeftV1;
     /** The current uncompressed offset into the data unit. */
-    uint64_t        offUnit;
+    uint64_t                offUnit;
 
     /** Pointer to the progress callback function. */
-    PFNVMPROGRESS   pfnProgress;
+    PFNVMPROGRESS           pfnProgress;
     /** User specified arguemnt to the callback function. */
-    void           *pvUser;
+    void                   *pvUser;
     /** Next completion percentage. (corresponds to offEstProgress) */
-    unsigned        uPercent;
+    unsigned                uPercent;
     /** The position of the next progress callback in the estimated file. */
-    uint64_t        offEstProgress;
+    uint64_t                offEstProgress;
     /** The estimated total byte count.
      * (Only valid after the prep.) */
-    uint64_t        cbEstTotal;
+    uint64_t                cbEstTotal;
     /** Current position in the estimated file. */
-    uint64_t        offEst;
+    uint64_t                offEst;
     /** End of current unit in the estimated file. */
-    uint64_t        offEstUnitEnd;
+    uint64_t                offEstUnitEnd;
     /** the amount of % we reserve for the 'prepare' phase */
-    unsigned        uPercentPrepare;
+    unsigned                uPercentPrepare;
     /** the amount of % we reserve for the 'done' stage */
-    unsigned        uPercentDone;
+    unsigned                uPercentDone;
     /** The filename, NULL if remote stream. */
-    const char     *pszFilename;
+    const char             *pszFilename;
 
     union
@@ -801,4 +824,19 @@
 
 /**
+ * Cleans up resources allocated by SSM on VM termination.
+ *
+ * @param   pVM                 The VM handle.
+ */
+VMMR3_INT_DECL(void) SSMR3Term(PVM pVM)
+{
+    if (pVM->ssm.s.fInitialized)
+    {
+        pVM->ssm.s.fInitialized = false;
+        RTCritSectDelete(&pVM->ssm.s.CancelCritSect);
+    }
+}
+
+
+/**
  * Performs lazy initialization of the SSM.
  *
@@ -817,4 +855,11 @@
                                    NULL /*pfnSavePrep*/, ssmR3SelfSaveExec, NULL /*pfnSaveDone*/,
                                    NULL /*pfnSavePrep*/, ssmR3SelfLoadExec, NULL /*pfnSaveDone*/);
+
+    /*
+     * Initialize the cancellation critsect now.
+     */
+    if (RT_SUCCESS(rc))
+        rc = RTCritSectInit(&pVM->ssm.s.CancelCritSect);
+
     pVM->ssm.s.fInitialized = RT_SUCCESS(rc);
     return rc;
@@ -2574,4 +2619,34 @@
                              / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare);
     }
+}
+
+
+/**
+ * Makes the SSM operation cancellable or not (via SSMR3Cancel).
+ *
+ * @param   pVM             The VM handle.
+ * @param   pSSM            The saved state handle. (SSMHANDLE::rc may be set.)
+ * @param   fCancellable    The new state.
+ */
+static void ssmR3SetCancellable(PVM pVM, PSSMHANDLE pSSM, bool fCancellable)
+{
+    RTCritSectEnter(&pVM->ssm.s.CancelCritSect);
+    if (fCancellable)
+    {
+        Assert(!pVM->ssm.s.pSSM);
+        pVM->ssm.s.pSSM = pSSM;
+    }
+    else
+    {
+        if (pVM->ssm.s.pSSM == pSSM)
+            pVM->ssm.s.pSSM = NULL;
+
+        uint32_t fCancelled = ASMAtomicUoReadU32(&pSSM->fCancelled);
+        if (    fCancelled == SSMHANDLE_CANCELLED
+            &&  RT_SUCCESS(pSSM->rc))
+            pSSM->rc = VERR_SSM_CANCELLED;
+    }
+
+    RTCritSectLeave(&pVM->ssm.s.CancelCritSect);
 }
 
@@ -2943,4 +3018,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     uint8_t u8 = fBool; /* enforce 1 byte size */
     return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
@@ -2958,4 +3034,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
 }
@@ -2972,4 +3049,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &i8, sizeof(i8));
 }
@@ -2986,4 +3064,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u16, sizeof(u16));
 }
@@ -3000,4 +3079,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &i16, sizeof(i16));
 }
@@ -3014,4 +3094,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u32, sizeof(u32));
 }
@@ -3028,4 +3109,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &i32, sizeof(i32));
 }
@@ -3042,4 +3124,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u64, sizeof(u64));
 }
@@ -3056,4 +3139,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &i64, sizeof(i64));
 }
@@ -3070,4 +3154,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u128, sizeof(u128));
 }
@@ -3084,4 +3169,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &i128, sizeof(i128));
 }
@@ -3098,4 +3184,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u, sizeof(u));
 }
@@ -3112,4 +3199,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &i, sizeof(i));
 }
@@ -3128,4 +3216,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u, sizeof(u));
 }
@@ -3142,4 +3231,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &u, sizeof(u));
 }
@@ -3156,4 +3246,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
 }
@@ -3170,4 +3261,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
 }
@@ -3184,4 +3276,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
 }
@@ -3198,4 +3291,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
 }
@@ -3212,4 +3306,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &RCPtr, sizeof(RCPtr));
 }
@@ -3226,4 +3321,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
 }
@@ -3240,4 +3336,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &IOPort, sizeof(IOPort));
 }
@@ -3254,4 +3351,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, &Sel, sizeof(Sel));
 }
@@ -3269,4 +3367,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataWrite(pSSM, pv, cb);
 }
@@ -3283,4 +3382,5 @@
 {
     SSM_ASSERT_WRITEABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
 
     size_t cch = strlen(psz);
@@ -3311,6 +3411,7 @@
 
     /*
-     * Close the stream and delete the file on failure.
-     */
+     * Make it non-cancellable, close the stream and delete the file on failure.
+     */
+    ssmR3SetCancellable(pVM, pSSM, false);
     int rc = ssmR3StrmClose(&pSSM->Strm);
     if (RT_SUCCESS(rc))
@@ -3343,4 +3444,5 @@
      * Trash the handle before freeing it.
      */
+    ASMAtomicWriteU32(&pSSM->fCancelled, 0);
     pSSM->pVM = NULL;
     pSSM->enmAfter = SSMAFTER_INVALID;
@@ -3595,4 +3697,14 @@
         }
         pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
+
+        /*
+         * Check for cancellation.
+         */
+        if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
+        {
+            LogRel(("SSM: Cancelled!\n"));
+            AssertRC(pSSM->rc);
+            return pSSM->rc = VERR_SSM_CANCELLED;
+        }
 
         /*
@@ -3888,4 +4000,5 @@
     pSSM->enmOp                 = SSMSTATE_INVALID;
     pSSM->enmAfter              = enmAfter;
+    pSSM->fCancelled            = SSMHANDLE_OK;
     pSSM->rc                    = VINF_SUCCESS;
     pSSM->cbUnitLeftV1          = 0;
@@ -3963,5 +4076,9 @@
     rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM);
     if (RT_SUCCESS(rc))
+    {
+        ssmR3SetCancellable(pVM, pSSM, true);
         ssmR3SaveDoCommon(pVM, pSSM);
+    }
+
     return ssmR3SaveDoClose(pVM, pSSM);
 }
@@ -4059,4 +4176,14 @@
             continue;
         pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
+
+        /*
+         * Check for cancellation.
+         */
+        if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
+        {
+            LogRel(("SSM: Cancelled!\n"));
+            AssertRC(pSSM->rc);
+            return pSSM->rc = VERR_SSM_CANCELLED;
+        }
 
         /*
@@ -4401,4 +4528,5 @@
              */
             pSSM->enmOp = SSMSTATE_LIVE_STEP1;
+            ssmR3SetCancellable(pVM, pSSM, true);
             *ppSSM = pSSM;
             return VINF_SUCCESS;
@@ -5194,4 +5322,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     uint8_t u8; /* see SSMR3PutBool */
     int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8));
@@ -5215,4 +5344,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pu8, sizeof(*pu8));
 }
@@ -5229,4 +5359,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pi8, sizeof(*pi8));
 }
@@ -5243,4 +5374,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pu16, sizeof(*pu16));
 }
@@ -5257,4 +5389,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pi16, sizeof(*pi16));
 }
@@ -5271,4 +5404,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pu32, sizeof(*pu32));
 }
@@ -5285,4 +5419,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pi32, sizeof(*pi32));
 }
@@ -5299,4 +5434,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pu64, sizeof(*pu64));
 }
@@ -5313,4 +5449,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pi64, sizeof(*pi64));
 }
@@ -5327,4 +5464,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pu128, sizeof(*pu128));
 }
@@ -5341,4 +5479,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pi128, sizeof(*pi128));
 }
@@ -5355,4 +5494,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pu, sizeof(*pu));
 }
@@ -5369,4 +5509,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pi, sizeof(*pi));
 }
@@ -5413,4 +5554,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
 }
@@ -5427,4 +5569,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
 }
@@ -5441,4 +5584,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
 
     /*
@@ -5518,4 +5662,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
 
     /*
@@ -5573,4 +5718,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pRCPtr, sizeof(*pRCPtr));
 }
@@ -5587,4 +5733,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pIOPort, sizeof(*pIOPort));
 }
@@ -5601,4 +5748,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pSel, sizeof(*pSel));
 }
@@ -5616,4 +5764,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     return ssmR3DataRead(pSSM, pv, cb);
 }
@@ -5646,4 +5795,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
 
     /* read size prefix. */
@@ -5676,4 +5826,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     while (cb > 0)
     {
@@ -5703,4 +5854,5 @@
 {
     SSM_ASSERT_READABLE_RET(pSSM);
+    SSM_CHECK_CANCELLED_RET(pSSM);
     if (pSSM->u.Read.uFmtVerMajor >= 2)
     {
@@ -6168,20 +6320,21 @@
      * Initialize the handle.
      */
-    pSSM->pVM              = pVM;
-    pSSM->enmOp            = SSMSTATE_INVALID;
-    pSSM->enmAfter         = SSMAFTER_INVALID;
-    pSSM->rc               = VINF_SUCCESS;
-    pSSM->cbUnitLeftV1     = 0;
-    pSSM->offUnit          = UINT64_MAX;
-    pSSM->pfnProgress      = NULL;
-    pSSM->pvUser           = NULL;
-    pSSM->uPercent         = 0;
-    pSSM->offEstProgress   = 0;
-    pSSM->cbEstTotal       = 0;
-    pSSM->offEst           = 0;
-    pSSM->offEstUnitEnd    = 0;
-    pSSM->uPercentPrepare  = 5;
-    pSSM->uPercentDone     = 2;
-    pSSM->pszFilename      = pszFilename;
+    pSSM->pVM               = pVM;
+    pSSM->enmOp             = SSMSTATE_INVALID;
+    pSSM->enmAfter          = SSMAFTER_INVALID;
+    pSSM->fCancelled        = SSMHANDLE_OK;
+    pSSM->rc                = VINF_SUCCESS;
+    pSSM->cbUnitLeftV1      = 0;
+    pSSM->offUnit           = UINT64_MAX;
+    pSSM->pfnProgress       = NULL;
+    pSSM->pvUser            = NULL;
+    pSSM->uPercent          = 0;
+    pSSM->offEstProgress    = 0;
+    pSSM->cbEstTotal        = 0;
+    pSSM->offEst            = 0;
+    pSSM->offEstUnitEnd     = 0;
+    pSSM->uPercentPrepare   = 5;
+    pSSM->uPercentDone      = 2;
+    pSSM->pszFilename       = pszFilename;
 
     pSSM->u.Read.pZipDecompV1   = NULL;
@@ -6415,4 +6568,16 @@
         {
             LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
+            break;
+        }
+
+        /*
+         * Check for cancellation.
+         */
+        if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
+        {
+            LogRel(("SSM: Cancelled!n"));
+            rc = pSSM->rc;
+            if (RT_SUCCESS(pSSM->rc))
+                pSSM->rc = rc = VERR_SSM_CANCELLED;
             break;
         }
@@ -6554,4 +6719,15 @@
             ssmR3DataReadFinishV2(pSSM);
         }
+
+        /*
+         * Check for cancellation.
+         */
+        if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
+        {
+            LogRel(("SSM: Cancelled!\n"));
+            if (RT_SUCCESS(pSSM->rc))
+                pSSM->rc = VERR_SSM_CANCELLED;
+            return pSSM->rc;
+        }
     }
     /* won't get here */
@@ -6597,4 +6773,5 @@
     {
         ssmR3StrmStartIoThread(&Handle.Strm);
+        ssmR3SetCancellable(pVM, &Handle, true);
 
         Handle.enmAfter     = enmAfter;
@@ -6714,4 +6891,5 @@
                     if (RT_SUCCESS(Handle.rc))
                         Handle.rc = rc;
+                    break;
                 }
             }
@@ -6723,4 +6901,5 @@
             pfnProgress(pVM, 99, pvUser);
 
+        ssmR3SetCancellable(pVM, &Handle, false);
         ssmR3StrmClose(&Handle.Strm);
     }
@@ -6838,4 +7017,5 @@
     AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
     AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
+    Assert(pSSM->fCancelled == SSMHANDLE_OK);
 
     /*
@@ -7136,27 +7316,28 @@
  * to SSM.
  *
+ * @returns VBox status code of the handle, or VERR_INVALID_PARAMETER.
+ * @param   pSSM            SSM operation handle.
+ * @param   iStatus         Failure status code. This MUST be a VERR_*.
+ */
+VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
+{
+    Assert(pSSM->enmOp != SSMSTATE_LIVE_VOTE);
+    if (RT_FAILURE(iStatus))
+    {
+        int rc = pSSM->rc;
+        if (RT_SUCCESS(rc))
+            pSSM->rc = rc = iStatus;
+        return rc;
+    }
+    AssertMsgFailed(("iStatus=%d %Rrc\n", iStatus, iStatus));
+    return VERR_INVALID_PARAMETER;
+}
+
+
+/**
+ * Get what to do after this operation.
+ *
  * @returns SSMAFTER enum value.
  * @param   pSSM            SSM operation handle.
- * @param   iStatus         Failure status code. This MUST be a VERR_*.
- */
-VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
-{
-    Assert(pSSM->enmOp != SSMSTATE_LIVE_VOTE);
-    if (RT_FAILURE(iStatus))
-    {
-        if (RT_SUCCESS(pSSM->rc))
-            pSSM->rc = iStatus;
-        return pSSM->rc = iStatus;
-    }
-    AssertMsgFailed(("iStatus=%d %Rrc\n", iStatus, iStatus));
-    return VERR_INVALID_PARAMETER;
-}
-
-
-/**
- * Get what to do after this operation.
- *
- * @returns SSMAFTER enum value.
- * @param   pSSM            SSM operation handle.
  */
 VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM)
@@ -7178,2 +7359,48 @@
 }
 
+
+/**
+ * Asynchronously cancels the current SSM operation ASAP.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_SSM_NO_PENDING_OPERATION if nothing around that can be
+ *          cancelled.
+ * @retval  VERR_SSM_ALREADY_CANCELLED if the operation as already been
+ *          cancelled.
+ *
+ * @param   pVM                 The VM handle.
+ *
+ * @thread  Any.
+ */
+VMMR3DECL(int) SSMR3Cancel(PVM pVM)
+{
+    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+
+    int rc = RTCritSectEnter(&pVM->ssm.s.CancelCritSect);
+    AssertRCReturn(rc, rc);
+
+    PSSMHANDLE pSSM = pVM->ssm.s.pSSM;
+    if (pSSM)
+    {
+        uint32_t u32Old;
+        if (ASMAtomicCmpXchgExU32(&pSSM->fCancelled, SSMHANDLE_CANCELLED, SSMHANDLE_OK, &u32Old))
+        {
+            LogRel(("SSM: Cancelled pending operation\n"));
+            rc = VINF_SUCCESS;
+        }
+        else if (u32Old == SSMHANDLE_CANCELLED)
+            rc = VERR_SSM_ALREADY_CANCELLED;
+        else
+        {
+            AssertLogRelMsgFailed(("fCancelled=%RX32 enmOp=%d\n", u32Old, pSSM->enmOp));
+            rc = VERR_INTERNAL_ERROR_2;
+        }
+    }
+    else
+        rc = VERR_SSM_NO_PENDING_OPERATION;
+
+    RTCritSectLeave(&pVM->ssm.s.CancelCritSect);
+    return rc;
+}
+
Index: /trunk/src/VBox/VMM/SSMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/SSMInternal.h	(revision 22883)
+++ /trunk/src/VBox/VMM/SSMInternal.h	(revision 22884)
@@ -26,4 +26,5 @@
 #include <VBox/types.h>
 #include <VBox/ssm.h>
+#include <iprt/critsect.h>
 
 RT_C_DECLS_BEGIN
@@ -266,4 +267,9 @@
     /** For lazy init. */
     bool                    fInitialized;
+    /** Critical section for serializing cancellation. */
+    RTCRITSECT              CancelCritSect;
+    /** The handle of the current save or load operation.
+     * This is used by SSMR3Cancel.  */
+    PSSMHANDLE volatile     pSSM;
 } SSM;
 /** Pointer to SSM VM instance data. */
