Index: /trunk/include/VBox/vmm/pdmstorageifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmstorageifs.h	(revision 71774)
+++ /trunk/include/VBox/vmm/pdmstorageifs.h	(revision 71775)
@@ -770,4 +770,16 @@
 
     /**
+     * Notifies the driver below that the device received a suspend notification.
+     *
+     * @returns nothing.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     *
+     * @note this is required because the PDM drivers in the storage area usually get their suspend notification
+     *       only after the device finished suspending. For some cases it is useful for the driver to know
+     *       as early as possible that a suspend is in progress to stop issuing deferred requests or other things.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnNotifySuspend, (PPDMIMEDIAEX pInterface));
+
+    /**
      * Sets the size of the allocator specific memory for a I/O request.
      *
Index: /trunk/src/VBox/Devices/Storage/DevAHCI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevAHCI.cpp	(revision 71774)
+++ /trunk/src/VBox/Devices/Storage/DevAHCI.cpp	(revision 71775)
@@ -5412,4 +5412,11 @@
     else
         ASMAtomicWriteBool(&pThis->fSignalIdle, false);
+
+    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
+    {
+        PAHCIPort pThisPort = &pThis->ahciPort[i];
+        if (pThisPort->pDrvMediaEx)
+            pThisPort->pDrvMediaEx->pfnNotifySuspend(pThisPort->pDrvMediaEx);
+    }
 }
 
Index: /trunk/src/VBox/Devices/Storage/DevBusLogic.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevBusLogic.cpp	(revision 71774)
+++ /trunk/src/VBox/Devices/Storage/DevBusLogic.cpp	(revision 71775)
@@ -3857,4 +3857,11 @@
         AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
     }
+
+    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDeviceStates); i++)
+    {
+        PBUSLOGICDEVICE pThisDevice = &pThis->aDeviceStates[i];
+        if (pThisDevice->pDrvMediaEx)
+            pThisDevice->pDrvMediaEx->pfnNotifySuspend(pThisDevice->pDrvMediaEx);
+    }
 }
 
Index: /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp	(revision 71774)
+++ /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp	(revision 71775)
@@ -5137,4 +5137,11 @@
         AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
     }
+
+    for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
+    {
+        PLSILOGICDEVICE pThisDevice = &pThis->paDeviceStates[i];
+        if (pThisDevice->pDrvMediaEx)
+            pThisDevice->pDrvMediaEx->pfnNotifySuspend(pThisDevice->pDrvMediaEx);
+    }
 }
 
Index: /trunk/src/VBox/Devices/Storage/DrvVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 71774)
+++ /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 71775)
@@ -342,4 +342,6 @@
     /** Flag whether this medium should be presented as non rotational. */
     bool                    fNonRotational;
+    /** Flag whether a suspend is in progress right now. */
+    volatile bool           fSuspending;
 #ifdef VBOX_PERIODIC_FLUSH
     /** HACK: Configuration value for number of bytes written after which to flush. */
@@ -3151,6 +3153,9 @@
             RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
             RTListAppend(&pThis->LstIoReqIoBufWait, &pIoReq->NdLstWait);
+            ASMAtomicIncU32(&pThis->cIoReqsWaiting);
+            if (ASMAtomicReadBool(&pThis->fSuspending))
+                pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0],
+                                                             PDMMEDIAEXIOREQSTATE_SUSPENDED);
             RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
-            ASMAtomicIncU32(&pThis->cIoReqsWaiting);
             rc = VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS;
         }
@@ -3412,4 +3417,85 @@
 
 /**
+ * Tries to process any requests waiting for available I/O memory.
+ *
+ * @returns nothing.
+ * @param   pThis     VBox disk container instance data.
+ */
+static void drvvdMediaExIoReqProcessWaiting(PVBOXDISK pThis)
+{
+    uint32_t cIoReqsWaiting = ASMAtomicXchgU32(&pThis->cIoReqsWaiting, 0);
+    if (cIoReqsWaiting > 0)
+    {
+        RTLISTANCHOR LstIoReqProcess;
+        RTLISTANCHOR LstIoReqCanceled;
+        RTListInit(&LstIoReqProcess);
+        RTListInit(&LstIoReqCanceled);
+
+        /* Try to process as many requests as possible. */
+        RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
+        PPDMMEDIAEXIOREQINT pIoReqCur, pIoReqNext;
+
+        RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
+        {
+            LogFlowFunc(("Found I/O request %#p on waiting list, trying to allocate buffer of size %zu bytes\n",
+                         pIoReqCur, pIoReqCur->ReadWrite.cbReq));
+
+            /* Allocate a suitable I/O buffer for this request. */
+            int rc = IOBUFMgrAllocBuf(pThis->hIoBufMgr, &pIoReqCur->ReadWrite.IoBuf, pIoReqCur->ReadWrite.cbReq,
+                                      &pIoReqCur->ReadWrite.cbIoBuf);
+            if (rc == VINF_SUCCESS)
+            {
+                Assert(pIoReqCur->ReadWrite.cbIoBuf > 0);
+
+                cIoReqsWaiting--;
+                RTListNodeRemove(&pIoReqCur->NdLstWait);
+
+                pIoReqCur->ReadWrite.fDirectBuf = false;
+                pIoReqCur->ReadWrite.pSgBuf     = &pIoReqCur->ReadWrite.IoBuf.SgBuf;
+
+                bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pIoReqCur->enmState,
+                                                 VDIOREQSTATE_ACTIVE, VDIOREQSTATE_ALLOCATED);
+                if (RT_UNLIKELY(!fXchg))
+                {
+                    /* Must have been canceled inbetween. */
+                    Assert(pIoReqCur->enmState == VDIOREQSTATE_CANCELED);
+
+                    /* Free the buffer here already again to let other requests get a chance to allocate the memory. */
+                    IOBUFMgrFreeBuf(&pIoReqCur->ReadWrite.IoBuf);
+                    pIoReqCur->ReadWrite.cbIoBuf = 0;
+                    RTListAppend(&LstIoReqCanceled, &pIoReqCur->NdLstWait);
+                }
+                else
+                {
+                    ASMAtomicIncU32(&pThis->cIoReqsActive);
+                    RTListAppend(&LstIoReqProcess, &pIoReqCur->NdLstWait);
+                }
+            }
+            else
+            {
+                Assert(rc == VERR_NO_MEMORY);
+                break;
+            }
+        }
+        RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
+
+        ASMAtomicAddU32(&pThis->cIoReqsWaiting, cIoReqsWaiting);
+
+        /* Process the requests we could allocate memory for and the ones which got canceled outside the lock now. */
+        RTListForEachSafe(&LstIoReqCanceled, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
+        {
+            RTListNodeRemove(&pIoReqCur->NdLstWait);
+            drvvdMediaExIoReqCompleteWorker(pThis, pIoReqCur, VERR_PDM_MEDIAEX_IOREQ_CANCELED, true /* fUpNotify */);
+        }
+
+        RTListForEachSafe(&LstIoReqProcess, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
+        {
+            RTListNodeRemove(&pIoReqCur->NdLstWait);
+            drvvdMediaExIoReqReadWriteProcess(pThis, pIoReqCur, true /* fUpNotify */);
+        }
+    }
+}
+
+/**
  * Frees a I/O memory buffer allocated previously.
  *
@@ -3429,75 +3515,6 @@
         IOBUFMgrFreeBuf(&pIoReq->ReadWrite.IoBuf);
 
-        uint32_t cIoReqsWaiting = ASMAtomicXchgU32(&pThis->cIoReqsWaiting, 0);
-        if (cIoReqsWaiting > 0)
-        {
-            RTLISTANCHOR LstIoReqProcess;
-            RTLISTANCHOR LstIoReqCanceled;
-            RTListInit(&LstIoReqProcess);
-            RTListInit(&LstIoReqCanceled);
-
-            /* Try to process as many requests as possible. */
-            RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
-            PPDMMEDIAEXIOREQINT pIoReqCur, pIoReqNext;
-
-            RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
-            {
-                LogFlowFunc(("Found I/O request %#p on waiting list, trying to allocate buffer of size %zu bytes\n",
-                             pIoReqCur, pIoReqCur->ReadWrite.cbReq));
-
-                /* Allocate a suitable I/O buffer for this request. */
-                int rc = IOBUFMgrAllocBuf(pThis->hIoBufMgr, &pIoReqCur->ReadWrite.IoBuf, pIoReqCur->ReadWrite.cbReq,
-                                          &pIoReqCur->ReadWrite.cbIoBuf);
-                if (rc == VINF_SUCCESS)
-                {
-                    Assert(pIoReqCur->ReadWrite.cbIoBuf > 0);
-
-                    cIoReqsWaiting--;
-                    RTListNodeRemove(&pIoReqCur->NdLstWait);
-
-                    pIoReqCur->ReadWrite.fDirectBuf = false;
-                    pIoReqCur->ReadWrite.pSgBuf     = &pIoReqCur->ReadWrite.IoBuf.SgBuf;
-
-                    bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pIoReqCur->enmState,
-                                                     VDIOREQSTATE_ACTIVE, VDIOREQSTATE_ALLOCATED);
-                    if (RT_UNLIKELY(!fXchg))
-                    {
-                        /* Must have been canceled inbetween. */
-                        Assert(pIoReqCur->enmState == VDIOREQSTATE_CANCELED);
-
-                        /* Free the buffer here already again to let other requests get a chance to allocate the memory. */
-                        IOBUFMgrFreeBuf(&pIoReq->ReadWrite.IoBuf);
-                        pIoReqCur->ReadWrite.cbIoBuf = 0;
-                        RTListAppend(&LstIoReqCanceled, &pIoReqCur->NdLstWait);
-                    }
-                    else
-                    {
-                        ASMAtomicIncU32(&pThis->cIoReqsActive);
-                        RTListAppend(&LstIoReqProcess, &pIoReqCur->NdLstWait);
-                    }
-                }
-                else
-                {
-                    Assert(rc == VERR_NO_MEMORY);
-                    break;
-                }
-            }
-            RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
-
-            ASMAtomicAddU32(&pThis->cIoReqsWaiting, cIoReqsWaiting);
-
-            /* Process the requests we could allocate memory for and the ones which got canceled outside the lock now. */
-            RTListForEachSafe(&LstIoReqCanceled, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
-            {
-                RTListNodeRemove(&pIoReqCur->NdLstWait);
-                drvvdMediaExIoReqCompleteWorker(pThis, pIoReqCur, VERR_PDM_MEDIAEX_IOREQ_CANCELED, true /* fUpNotify */);
-            }
-
-            RTListForEachSafe(&LstIoReqProcess, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
-            {
-                RTListNodeRemove(&pIoReqCur->NdLstWait);
-                drvvdMediaExIoReqReadWriteProcess(pThis, pIoReqCur, true /* fUpNotify */);
-            }
-        }
+        if (!ASMAtomicReadBool(&pThis->fSuspending))
+            drvvdMediaExIoReqProcessWaiting(pThis);
     }
 
@@ -3688,4 +3705,25 @@
 
 /**
+ * @interface_method_impl{PDMIMEDIAEX,pfnNotifySuspend}
+ */
+static DECLCALLBACK(void) drvvdNotifySuspend(PPDMIMEDIAEX pInterface)
+{
+    PVBOXDISK pThis = RT_FROM_MEMBER(pInterface, VBOXDISK, IMediaEx);
+
+    ASMAtomicXchgBool(&pThis->fSuspending, true);
+
+    /* Mark all waiting requests as suspended so they don't get accounted for. */
+    RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
+    PPDMMEDIAEXIOREQINT pIoReqCur, pIoReqNext;
+    RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
+    {
+        pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, pIoReqCur, &pIoReqCur->abAlloc[0],
+                                                     PDMMEDIAEXIOREQSTATE_SUSPENDED);
+    }
+    RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
+}
+
+
+/**
  * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet}
  */
@@ -4098,5 +4136,5 @@
     RTCritSectLeave(&pThis->CritSectIoReqRedo);
 
-    return cIoReqSuspended;
+    return cIoReqSuspended + pThis->cIoReqsWaiting;
 }
 
@@ -4110,11 +4148,25 @@
 
     AssertReturn(!drvvdMediaExIoReqIsVmRunning(pThis), VERR_INVALID_STATE);
-    AssertReturn(!RTListIsEmpty(&pThis->LstIoReqRedo), VERR_NOT_FOUND);
-
-    RTCritSectEnter(&pThis->CritSectIoReqRedo);
-    PPDMMEDIAEXIOREQINT pIoReq = RTListGetFirst(&pThis->LstIoReqRedo, PDMMEDIAEXIOREQINT, NdLstWait);
+    AssertReturn(!(   RTListIsEmpty(&pThis->LstIoReqRedo)
+                   && RTListIsEmpty(&pThis->LstIoReqIoBufWait)), VERR_NOT_FOUND);
+
+    PRTLISTANCHOR pLst;
+    PRTCRITSECT pCritSect;
+    if (!RTListIsEmpty(&pThis->LstIoReqRedo))
+    {
+        pLst = &pThis->LstIoReqRedo;
+        pCritSect = &pThis->CritSectIoReqRedo;
+    }
+    else
+    {
+        pLst = &pThis->LstIoReqIoBufWait;
+        pCritSect = &pThis->CritSectIoReqsIoBufWait;
+    }
+
+    RTCritSectEnter(pCritSect);
+    PPDMMEDIAEXIOREQINT pIoReq = RTListGetFirst(pLst, PDMMEDIAEXIOREQINT, NdLstWait);
     *phIoReq       = pIoReq;
     *ppvIoReqAlloc = &pIoReq->abAlloc[0];
-    RTCritSectLeave(&pThis->CritSectIoReqRedo);
+    RTCritSectLeave(pCritSect);
 
     return VINF_SUCCESS;
@@ -4132,11 +4184,35 @@
     AssertReturn(!drvvdMediaExIoReqIsVmRunning(pThis), VERR_INVALID_STATE);
     AssertPtrReturn(pIoReq, VERR_INVALID_HANDLE);
-    AssertReturn(!RTListNodeIsLast(&pThis->LstIoReqRedo, &pIoReq->NdLstWait), VERR_NOT_FOUND);
-
-    RTCritSectEnter(&pThis->CritSectIoReqRedo);
-    PPDMMEDIAEXIOREQINT pIoReqNext = RTListNodeGetNext(&pIoReq->NdLstWait, PDMMEDIAEXIOREQINT, NdLstWait);
+    AssertReturn(   (   pIoReq->enmState == VDIOREQSTATE_SUSPENDED
+                     && (   !RTListNodeIsLast(&pThis->LstIoReqRedo, &pIoReq->NdLstWait)
+                         || !RTListIsEmpty(&pThis->LstIoReqIoBufWait)))
+                 || (   pIoReq->enmState == VDIOREQSTATE_ALLOCATED
+                     && !RTListNodeIsLast(&pThis->LstIoReqIoBufWait, &pIoReq->NdLstWait)), VERR_NOT_FOUND);
+
+    PPDMMEDIAEXIOREQINT pIoReqNext;
+    if (pIoReq->enmState == VDIOREQSTATE_SUSPENDED)
+    {
+        if (!RTListNodeIsLast(&pThis->LstIoReqRedo, &pIoReq->NdLstWait))
+        {
+            RTCritSectEnter(&pThis->CritSectIoReqRedo);
+            pIoReqNext = RTListNodeGetNext(&pIoReq->NdLstWait, PDMMEDIAEXIOREQINT, NdLstWait);
+            RTCritSectLeave(&pThis->CritSectIoReqRedo);
+        }
+        else
+        {
+            RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
+            pIoReqNext = RTListGetFirst(&pThis->LstIoReqIoBufWait, PDMMEDIAEXIOREQINT, NdLstWait);
+            RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
+        }
+    }
+    else
+    {
+        RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
+        pIoReqNext = RTListNodeGetNext(&pIoReq->NdLstWait, PDMMEDIAEXIOREQINT, NdLstWait);
+        RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
+    }
+
     *phIoReqNext       = pIoReqNext;
     *ppvIoReqAllocNext = &pIoReqNext->abAlloc[0];
-    RTCritSectLeave(&pThis->CritSectIoReqRedo);
 
     return VINF_SUCCESS;
@@ -4153,5 +4229,6 @@
     AssertReturn(!drvvdMediaExIoReqIsVmRunning(pThis), VERR_INVALID_STATE);
     AssertPtrReturn(pIoReq, VERR_INVALID_HANDLE);
-    AssertReturn(pIoReq->enmState == VDIOREQSTATE_SUSPENDED, VERR_INVALID_STATE);
+    AssertReturn(   pIoReq->enmState == VDIOREQSTATE_SUSPENDED
+                 || pIoReq->enmState == VDIOREQSTATE_ALLOCATED, VERR_INVALID_STATE);
 
     SSMR3PutU32(pSSM, DRVVD_IOREQ_SAVED_STATE_VERSION);
@@ -4649,5 +4726,5 @@
 
     drvvdSetWritable(pThis);
-    pThis->fErrorUseRuntime = true;
+    pThis->fSuspending      = false;
 
     if (pThis->pBlkCache)
@@ -4659,6 +4736,16 @@
     if (pThis->pDrvMediaExPort)
     {
+        /* Mark all requests waiting for I/O memory as active again so they get accounted for. */
+        RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
+        PPDMMEDIAEXIOREQINT pIoReq, pIoReqNext;
+        RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReq, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
+        {
+            pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0],
+                                                         PDMMEDIAEXIOREQSTATE_ACTIVE);
+            ASMAtomicIncU32(&pThis->cIoReqsActive);
+        }
+        RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
+
         /* Kick of any request we have to redo. */
-        PPDMMEDIAEXIOREQINT pIoReq, pIoReqNext;
         RTCritSectEnter(&pThis->CritSectIoReqRedo);
         RTListForEachSafe(&pThis->LstIoReqRedo, pIoReq, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
@@ -4719,4 +4806,8 @@
         RTCritSectLeave(&pThis->CritSectIoReqRedo);
     }
+
+    /* Try to process any requests waiting for I/O memory now. */
+    drvvdMediaExIoReqProcessWaiting(pThis);
+    pThis->fErrorUseRuntime = true;
 }
 
@@ -4869,4 +4960,5 @@
     pThis->hIoBufMgr                    = NIL_IOBUFMGR;
     pThis->pRegionList                  = NULL;
+    pThis->fSuspending                  = false;
 
     for (unsigned i = 0; i < RT_ELEMENTS(pThis->aIoReqAllocBins); i++)
@@ -4906,4 +4998,5 @@
     /* IMediaEx */
     pThis->IMediaEx.pfnQueryFeatures            = drvvdQueryFeatures;
+    pThis->IMediaEx.pfnNotifySuspend            = drvvdNotifySuspend;
     pThis->IMediaEx.pfnIoReqAllocSizeSet        = drvvdIoReqAllocSizeSet;
     pThis->IMediaEx.pfnIoReqAlloc               = drvvdIoReqAlloc;
