VirtualBox

Changeset 71775 in vbox for trunk/src/VBox/Devices/Storage


Ignore:
Timestamp:
Apr 9, 2018 2:54:57 PM (7 years ago)
Author:
vboxsync
Message:

Devices/Storage: Properly account for requests currently waiting for I/O memory when suspending/resuming to avoid hangs upon suspend (devices would not complete suspending because aiting requests would be marked as active but could not complete)

Location:
trunk/src/VBox/Devices/Storage
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevAHCI.cpp

    r70687 r71775  
    54125412    else
    54135413        ASMAtomicWriteBool(&pThis->fSignalIdle, false);
     5414
     5415    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
     5416    {
     5417        PAHCIPort pThisPort = &pThis->ahciPort[i];
     5418        if (pThisPort->pDrvMediaEx)
     5419            pThisPort->pDrvMediaEx->pfnNotifySuspend(pThisPort->pDrvMediaEx);
     5420    }
    54145421}
    54155422
  • trunk/src/VBox/Devices/Storage/DevBusLogic.cpp

    r69500 r71775  
    38573857        AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
    38583858    }
     3859
     3860    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDeviceStates); i++)
     3861    {
     3862        PBUSLOGICDEVICE pThisDevice = &pThis->aDeviceStates[i];
     3863        if (pThisDevice->pDrvMediaEx)
     3864            pThisDevice->pDrvMediaEx->pfnNotifySuspend(pThisDevice->pDrvMediaEx);
     3865    }
    38593866}
    38603867
  • trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp

    r69500 r71775  
    51375137        AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
    51385138    }
     5139
     5140    for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
     5141    {
     5142        PLSILOGICDEVICE pThisDevice = &pThis->paDeviceStates[i];
     5143        if (pThisDevice->pDrvMediaEx)
     5144            pThisDevice->pDrvMediaEx->pfnNotifySuspend(pThisDevice->pDrvMediaEx);
     5145    }
    51395146}
    51405147
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r70775 r71775  
    342342    /** Flag whether this medium should be presented as non rotational. */
    343343    bool                    fNonRotational;
     344    /** Flag whether a suspend is in progress right now. */
     345    volatile bool           fSuspending;
    344346#ifdef VBOX_PERIODIC_FLUSH
    345347    /** HACK: Configuration value for number of bytes written after which to flush. */
     
    31513153            RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
    31523154            RTListAppend(&pThis->LstIoReqIoBufWait, &pIoReq->NdLstWait);
     3155            ASMAtomicIncU32(&pThis->cIoReqsWaiting);
     3156            if (ASMAtomicReadBool(&pThis->fSuspending))
     3157                pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0],
     3158                                                             PDMMEDIAEXIOREQSTATE_SUSPENDED);
    31533159            RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
    3154             ASMAtomicIncU32(&pThis->cIoReqsWaiting);
    31553160            rc = VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS;
    31563161        }
     
    34123417
    34133418/**
     3419 * Tries to process any requests waiting for available I/O memory.
     3420 *
     3421 * @returns nothing.
     3422 * @param   pThis     VBox disk container instance data.
     3423 */
     3424static void drvvdMediaExIoReqProcessWaiting(PVBOXDISK pThis)
     3425{
     3426    uint32_t cIoReqsWaiting = ASMAtomicXchgU32(&pThis->cIoReqsWaiting, 0);
     3427    if (cIoReqsWaiting > 0)
     3428    {
     3429        RTLISTANCHOR LstIoReqProcess;
     3430        RTLISTANCHOR LstIoReqCanceled;
     3431        RTListInit(&LstIoReqProcess);
     3432        RTListInit(&LstIoReqCanceled);
     3433
     3434        /* Try to process as many requests as possible. */
     3435        RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
     3436        PPDMMEDIAEXIOREQINT pIoReqCur, pIoReqNext;
     3437
     3438        RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
     3439        {
     3440            LogFlowFunc(("Found I/O request %#p on waiting list, trying to allocate buffer of size %zu bytes\n",
     3441                         pIoReqCur, pIoReqCur->ReadWrite.cbReq));
     3442
     3443            /* Allocate a suitable I/O buffer for this request. */
     3444            int rc = IOBUFMgrAllocBuf(pThis->hIoBufMgr, &pIoReqCur->ReadWrite.IoBuf, pIoReqCur->ReadWrite.cbReq,
     3445                                      &pIoReqCur->ReadWrite.cbIoBuf);
     3446            if (rc == VINF_SUCCESS)
     3447            {
     3448                Assert(pIoReqCur->ReadWrite.cbIoBuf > 0);
     3449
     3450                cIoReqsWaiting--;
     3451                RTListNodeRemove(&pIoReqCur->NdLstWait);
     3452
     3453                pIoReqCur->ReadWrite.fDirectBuf = false;
     3454                pIoReqCur->ReadWrite.pSgBuf     = &pIoReqCur->ReadWrite.IoBuf.SgBuf;
     3455
     3456                bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pIoReqCur->enmState,
     3457                                                 VDIOREQSTATE_ACTIVE, VDIOREQSTATE_ALLOCATED);
     3458                if (RT_UNLIKELY(!fXchg))
     3459                {
     3460                    /* Must have been canceled inbetween. */
     3461                    Assert(pIoReqCur->enmState == VDIOREQSTATE_CANCELED);
     3462
     3463                    /* Free the buffer here already again to let other requests get a chance to allocate the memory. */
     3464                    IOBUFMgrFreeBuf(&pIoReqCur->ReadWrite.IoBuf);
     3465                    pIoReqCur->ReadWrite.cbIoBuf = 0;
     3466                    RTListAppend(&LstIoReqCanceled, &pIoReqCur->NdLstWait);
     3467                }
     3468                else
     3469                {
     3470                    ASMAtomicIncU32(&pThis->cIoReqsActive);
     3471                    RTListAppend(&LstIoReqProcess, &pIoReqCur->NdLstWait);
     3472                }
     3473            }
     3474            else
     3475            {
     3476                Assert(rc == VERR_NO_MEMORY);
     3477                break;
     3478            }
     3479        }
     3480        RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
     3481
     3482        ASMAtomicAddU32(&pThis->cIoReqsWaiting, cIoReqsWaiting);
     3483
     3484        /* Process the requests we could allocate memory for and the ones which got canceled outside the lock now. */
     3485        RTListForEachSafe(&LstIoReqCanceled, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
     3486        {
     3487            RTListNodeRemove(&pIoReqCur->NdLstWait);
     3488            drvvdMediaExIoReqCompleteWorker(pThis, pIoReqCur, VERR_PDM_MEDIAEX_IOREQ_CANCELED, true /* fUpNotify */);
     3489        }
     3490
     3491        RTListForEachSafe(&LstIoReqProcess, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
     3492        {
     3493            RTListNodeRemove(&pIoReqCur->NdLstWait);
     3494            drvvdMediaExIoReqReadWriteProcess(pThis, pIoReqCur, true /* fUpNotify */);
     3495        }
     3496    }
     3497}
     3498
     3499/**
    34143500 * Frees a I/O memory buffer allocated previously.
    34153501 *
     
    34293515        IOBUFMgrFreeBuf(&pIoReq->ReadWrite.IoBuf);
    34303516
    3431         uint32_t cIoReqsWaiting = ASMAtomicXchgU32(&pThis->cIoReqsWaiting, 0);
    3432         if (cIoReqsWaiting > 0)
    3433         {
    3434             RTLISTANCHOR LstIoReqProcess;
    3435             RTLISTANCHOR LstIoReqCanceled;
    3436             RTListInit(&LstIoReqProcess);
    3437             RTListInit(&LstIoReqCanceled);
    3438 
    3439             /* Try to process as many requests as possible. */
    3440             RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
    3441             PPDMMEDIAEXIOREQINT pIoReqCur, pIoReqNext;
    3442 
    3443             RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
    3444             {
    3445                 LogFlowFunc(("Found I/O request %#p on waiting list, trying to allocate buffer of size %zu bytes\n",
    3446                              pIoReqCur, pIoReqCur->ReadWrite.cbReq));
    3447 
    3448                 /* Allocate a suitable I/O buffer for this request. */
    3449                 int rc = IOBUFMgrAllocBuf(pThis->hIoBufMgr, &pIoReqCur->ReadWrite.IoBuf, pIoReqCur->ReadWrite.cbReq,
    3450                                           &pIoReqCur->ReadWrite.cbIoBuf);
    3451                 if (rc == VINF_SUCCESS)
    3452                 {
    3453                     Assert(pIoReqCur->ReadWrite.cbIoBuf > 0);
    3454 
    3455                     cIoReqsWaiting--;
    3456                     RTListNodeRemove(&pIoReqCur->NdLstWait);
    3457 
    3458                     pIoReqCur->ReadWrite.fDirectBuf = false;
    3459                     pIoReqCur->ReadWrite.pSgBuf     = &pIoReqCur->ReadWrite.IoBuf.SgBuf;
    3460 
    3461                     bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pIoReqCur->enmState,
    3462                                                      VDIOREQSTATE_ACTIVE, VDIOREQSTATE_ALLOCATED);
    3463                     if (RT_UNLIKELY(!fXchg))
    3464                     {
    3465                         /* Must have been canceled inbetween. */
    3466                         Assert(pIoReqCur->enmState == VDIOREQSTATE_CANCELED);
    3467 
    3468                         /* Free the buffer here already again to let other requests get a chance to allocate the memory. */
    3469                         IOBUFMgrFreeBuf(&pIoReq->ReadWrite.IoBuf);
    3470                         pIoReqCur->ReadWrite.cbIoBuf = 0;
    3471                         RTListAppend(&LstIoReqCanceled, &pIoReqCur->NdLstWait);
    3472                     }
    3473                     else
    3474                     {
    3475                         ASMAtomicIncU32(&pThis->cIoReqsActive);
    3476                         RTListAppend(&LstIoReqProcess, &pIoReqCur->NdLstWait);
    3477                     }
    3478                 }
    3479                 else
    3480                 {
    3481                     Assert(rc == VERR_NO_MEMORY);
    3482                     break;
    3483                 }
    3484             }
    3485             RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
    3486 
    3487             ASMAtomicAddU32(&pThis->cIoReqsWaiting, cIoReqsWaiting);
    3488 
    3489             /* Process the requests we could allocate memory for and the ones which got canceled outside the lock now. */
    3490             RTListForEachSafe(&LstIoReqCanceled, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
    3491             {
    3492                 RTListNodeRemove(&pIoReqCur->NdLstWait);
    3493                 drvvdMediaExIoReqCompleteWorker(pThis, pIoReqCur, VERR_PDM_MEDIAEX_IOREQ_CANCELED, true /* fUpNotify */);
    3494             }
    3495 
    3496             RTListForEachSafe(&LstIoReqProcess, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
    3497             {
    3498                 RTListNodeRemove(&pIoReqCur->NdLstWait);
    3499                 drvvdMediaExIoReqReadWriteProcess(pThis, pIoReqCur, true /* fUpNotify */);
    3500             }
    3501         }
     3517        if (!ASMAtomicReadBool(&pThis->fSuspending))
     3518            drvvdMediaExIoReqProcessWaiting(pThis);
    35023519    }
    35033520
     
    36883705
    36893706/**
     3707 * @interface_method_impl{PDMIMEDIAEX,pfnNotifySuspend}
     3708 */
     3709static DECLCALLBACK(void) drvvdNotifySuspend(PPDMIMEDIAEX pInterface)
     3710{
     3711    PVBOXDISK pThis = RT_FROM_MEMBER(pInterface, VBOXDISK, IMediaEx);
     3712
     3713    ASMAtomicXchgBool(&pThis->fSuspending, true);
     3714
     3715    /* Mark all waiting requests as suspended so they don't get accounted for. */
     3716    RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
     3717    PPDMMEDIAEXIOREQINT pIoReqCur, pIoReqNext;
     3718    RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReqCur, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
     3719    {
     3720        pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, pIoReqCur, &pIoReqCur->abAlloc[0],
     3721                                                     PDMMEDIAEXIOREQSTATE_SUSPENDED);
     3722    }
     3723    RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
     3724}
     3725
     3726
     3727/**
    36903728 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet}
    36913729 */
     
    40984136    RTCritSectLeave(&pThis->CritSectIoReqRedo);
    40994137
    4100     return cIoReqSuspended;
     4138    return cIoReqSuspended + pThis->cIoReqsWaiting;
    41014139}
    41024140
     
    41104148
    41114149    AssertReturn(!drvvdMediaExIoReqIsVmRunning(pThis), VERR_INVALID_STATE);
    4112     AssertReturn(!RTListIsEmpty(&pThis->LstIoReqRedo), VERR_NOT_FOUND);
    4113 
    4114     RTCritSectEnter(&pThis->CritSectIoReqRedo);
    4115     PPDMMEDIAEXIOREQINT pIoReq = RTListGetFirst(&pThis->LstIoReqRedo, PDMMEDIAEXIOREQINT, NdLstWait);
     4150    AssertReturn(!(   RTListIsEmpty(&pThis->LstIoReqRedo)
     4151                   && RTListIsEmpty(&pThis->LstIoReqIoBufWait)), VERR_NOT_FOUND);
     4152
     4153    PRTLISTANCHOR pLst;
     4154    PRTCRITSECT pCritSect;
     4155    if (!RTListIsEmpty(&pThis->LstIoReqRedo))
     4156    {
     4157        pLst = &pThis->LstIoReqRedo;
     4158        pCritSect = &pThis->CritSectIoReqRedo;
     4159    }
     4160    else
     4161    {
     4162        pLst = &pThis->LstIoReqIoBufWait;
     4163        pCritSect = &pThis->CritSectIoReqsIoBufWait;
     4164    }
     4165
     4166    RTCritSectEnter(pCritSect);
     4167    PPDMMEDIAEXIOREQINT pIoReq = RTListGetFirst(pLst, PDMMEDIAEXIOREQINT, NdLstWait);
    41164168    *phIoReq       = pIoReq;
    41174169    *ppvIoReqAlloc = &pIoReq->abAlloc[0];
    4118     RTCritSectLeave(&pThis->CritSectIoReqRedo);
     4170    RTCritSectLeave(pCritSect);
    41194171
    41204172    return VINF_SUCCESS;
     
    41324184    AssertReturn(!drvvdMediaExIoReqIsVmRunning(pThis), VERR_INVALID_STATE);
    41334185    AssertPtrReturn(pIoReq, VERR_INVALID_HANDLE);
    4134     AssertReturn(!RTListNodeIsLast(&pThis->LstIoReqRedo, &pIoReq->NdLstWait), VERR_NOT_FOUND);
    4135 
    4136     RTCritSectEnter(&pThis->CritSectIoReqRedo);
    4137     PPDMMEDIAEXIOREQINT pIoReqNext = RTListNodeGetNext(&pIoReq->NdLstWait, PDMMEDIAEXIOREQINT, NdLstWait);
     4186    AssertReturn(   (   pIoReq->enmState == VDIOREQSTATE_SUSPENDED
     4187                     && (   !RTListNodeIsLast(&pThis->LstIoReqRedo, &pIoReq->NdLstWait)
     4188                         || !RTListIsEmpty(&pThis->LstIoReqIoBufWait)))
     4189                 || (   pIoReq->enmState == VDIOREQSTATE_ALLOCATED
     4190                     && !RTListNodeIsLast(&pThis->LstIoReqIoBufWait, &pIoReq->NdLstWait)), VERR_NOT_FOUND);
     4191
     4192    PPDMMEDIAEXIOREQINT pIoReqNext;
     4193    if (pIoReq->enmState == VDIOREQSTATE_SUSPENDED)
     4194    {
     4195        if (!RTListNodeIsLast(&pThis->LstIoReqRedo, &pIoReq->NdLstWait))
     4196        {
     4197            RTCritSectEnter(&pThis->CritSectIoReqRedo);
     4198            pIoReqNext = RTListNodeGetNext(&pIoReq->NdLstWait, PDMMEDIAEXIOREQINT, NdLstWait);
     4199            RTCritSectLeave(&pThis->CritSectIoReqRedo);
     4200        }
     4201        else
     4202        {
     4203            RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
     4204            pIoReqNext = RTListGetFirst(&pThis->LstIoReqIoBufWait, PDMMEDIAEXIOREQINT, NdLstWait);
     4205            RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
     4206        }
     4207    }
     4208    else
     4209    {
     4210        RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
     4211        pIoReqNext = RTListNodeGetNext(&pIoReq->NdLstWait, PDMMEDIAEXIOREQINT, NdLstWait);
     4212        RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
     4213    }
     4214
    41384215    *phIoReqNext       = pIoReqNext;
    41394216    *ppvIoReqAllocNext = &pIoReqNext->abAlloc[0];
    4140     RTCritSectLeave(&pThis->CritSectIoReqRedo);
    41414217
    41424218    return VINF_SUCCESS;
     
    41534229    AssertReturn(!drvvdMediaExIoReqIsVmRunning(pThis), VERR_INVALID_STATE);
    41544230    AssertPtrReturn(pIoReq, VERR_INVALID_HANDLE);
    4155     AssertReturn(pIoReq->enmState == VDIOREQSTATE_SUSPENDED, VERR_INVALID_STATE);
     4231    AssertReturn(   pIoReq->enmState == VDIOREQSTATE_SUSPENDED
     4232                 || pIoReq->enmState == VDIOREQSTATE_ALLOCATED, VERR_INVALID_STATE);
    41564233
    41574234    SSMR3PutU32(pSSM, DRVVD_IOREQ_SAVED_STATE_VERSION);
     
    46494726
    46504727    drvvdSetWritable(pThis);
    4651     pThis->fErrorUseRuntime = true;
     4728    pThis->fSuspending      = false;
    46524729
    46534730    if (pThis->pBlkCache)
     
    46594736    if (pThis->pDrvMediaExPort)
    46604737    {
     4738        /* Mark all requests waiting for I/O memory as active again so they get accounted for. */
     4739        RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
     4740        PPDMMEDIAEXIOREQINT pIoReq, pIoReqNext;
     4741        RTListForEachSafe(&pThis->LstIoReqIoBufWait, pIoReq, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
     4742        {
     4743            pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0],
     4744                                                         PDMMEDIAEXIOREQSTATE_ACTIVE);
     4745            ASMAtomicIncU32(&pThis->cIoReqsActive);
     4746        }
     4747        RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
     4748
    46614749        /* Kick of any request we have to redo. */
    4662         PPDMMEDIAEXIOREQINT pIoReq, pIoReqNext;
    46634750        RTCritSectEnter(&pThis->CritSectIoReqRedo);
    46644751        RTListForEachSafe(&pThis->LstIoReqRedo, pIoReq, pIoReqNext, PDMMEDIAEXIOREQINT, NdLstWait)
     
    47194806        RTCritSectLeave(&pThis->CritSectIoReqRedo);
    47204807    }
     4808
     4809    /* Try to process any requests waiting for I/O memory now. */
     4810    drvvdMediaExIoReqProcessWaiting(pThis);
     4811    pThis->fErrorUseRuntime = true;
    47214812}
    47224813
     
    48694960    pThis->hIoBufMgr                    = NIL_IOBUFMGR;
    48704961    pThis->pRegionList                  = NULL;
     4962    pThis->fSuspending                  = false;
    48714963
    48724964    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aIoReqAllocBins); i++)
     
    49064998    /* IMediaEx */
    49074999    pThis->IMediaEx.pfnQueryFeatures            = drvvdQueryFeatures;
     5000    pThis->IMediaEx.pfnNotifySuspend            = drvvdNotifySuspend;
    49085001    pThis->IMediaEx.pfnIoReqAllocSizeSet        = drvvdIoReqAllocSizeSet;
    49095002    pThis->IMediaEx.pfnIoReqAlloc               = drvvdIoReqAlloc;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette