VirtualBox

Changeset 26671 in vbox


Ignore:
Timestamp:
Feb 22, 2010 7:21:34 AM (15 years ago)
Author:
vboxsync
Message:

AsyncCompletion: Make it possible to limit the bandwidth of a VM

Location:
trunk/src/VBox/VMM
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/PDMAsyncCompletionFile.cpp

    r26527 r26671  
    464464
    465465/**
     466 * I/O refresh timer callback.
     467 */
     468static void pdmacFileBwRefresh(PVM pVM, PTMTIMER pTimer, void *pvUser)
     469{
     470    PPDMACFILEBWMGR pBwMgr = (PPDMACFILEBWMGR)pvUser;
     471
     472    LogFlowFunc(("pVM=%p pTimer=%p pvUser=%p\n", pVM, pTimer, pvUser));
     473
     474    /* Reset the counter growing the maximum if allowed and needed */
     475    bool fIncreaseNeeded = ASMAtomicReadBool(&pBwMgr->fVMTransferLimitReached);
     476
     477    if (   fIncreaseNeeded
     478        && pBwMgr->cbVMTransferPerSecStart < pBwMgr->cbVMTransferPerSecMax)
     479    {
     480       pBwMgr->cbVMTransferPerSecStart = RT_MIN(pBwMgr->cbVMTransferPerSecMax, pBwMgr->cbVMTransferPerSecStart + pBwMgr->cbVMTransferPerSecStep);
     481       LogFlow(("AIOMgr: Increasing maximum bandwidth to %u bytes/sec\n", pBwMgr->cbVMTransferPerSecStart));
     482    }
     483
     484    /* Update */
     485    ASMAtomicWriteU32(&pBwMgr->cbVMTransferAllowed, pBwMgr->cbVMTransferPerSecStart);
     486    ASMAtomicWriteBool(&pBwMgr->fVMTransferLimitReached, false);
     487
     488    /* Arm the timer */
     489    TMTimerSetMillies(pTimer, 1000);
     490}
     491
     492/**
    466493 * Destroys a async I/O manager.
    467494 *
     
    490517
    491518    pEpClassFile->cAioMgrs--;
    492 
    493519    rc = RTCritSectLeave(&pEpClassFile->CritSect);
    494520    AssertRC(rc);
     
    501527
    502528    MMR3HeapFree(pAioMgr);
     529}
     530
     531static int pdmacFileBwMgrInitialize(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile,
     532                                    PCFGMNODE pCfgNode, PPPDMACFILEBWMGR ppBwMgr)
     533{
     534    int rc = VINF_SUCCESS;
     535    PPDMACFILEBWMGR pBwMgr = NULL;
     536
     537    rc = MMR3HeapAllocZEx(pEpClassFile->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION,
     538                          sizeof(PDMACFILEBWMGR),
     539                          (void **)&pBwMgr);
     540    if (RT_SUCCESS(rc))
     541    {
     542        /* Init I/O flow control. */
     543        rc = CFGMR3QueryU32Def(pCfgNode, "VMTransferPerSecMax", &pBwMgr->cbVMTransferPerSecMax, UINT32_MAX);
     544        AssertLogRelRCReturn(rc, rc);
     545        rc = CFGMR3QueryU32Def(pCfgNode, "VMTransferPerSecStart", &pBwMgr->cbVMTransferPerSecStart, _1M);
     546        AssertLogRelRCReturn(rc, rc);
     547        rc = CFGMR3QueryU32Def(pCfgNode, "VMTransferPerSecStep", &pBwMgr->cbVMTransferPerSecStep, _1M);
     548        AssertLogRelRCReturn(rc, rc);
     549
     550        pBwMgr->cbVMTransferAllowed = pBwMgr->cbVMTransferPerSecStart;
     551
     552        /* Init the refresh timer */
     553        rc = TMR3TimerCreateInternal(pEpClassFile->Core.pVM,
     554                                     TMCLOCK_REAL,
     555                                     pdmacFileBwRefresh,
     556                                     pBwMgr,
     557                                     "AsyncCompletionFile-BW-Refresh",
     558                                     &pBwMgr->pBwRefreshTimer);
     559        if (RT_SUCCESS(rc))
     560            *ppBwMgr = pBwMgr;
     561        else
     562            MMR3HeapFree(pBwMgr);
     563    }
     564
     565    return rc;
     566}
     567
     568static void pdmacFileBwMgrDestroy(PPDMACFILEBWMGR pBwMgr)
     569{
     570    TMR3TimerDestroy(pBwMgr->pBwRefreshTimer);
     571    MMR3HeapFree(pBwMgr);
     572}
     573
     574static void pdmacFileBwRef(PPDMACFILEBWMGR pBwMgr)
     575{
     576    pBwMgr->cRefs++;
     577    if (pBwMgr->cRefs == 1)
     578        TMTimerSetMillies(pBwMgr->pBwRefreshTimer, 1000); /* 1sec update interval */
     579}
     580
     581static void pdmacFileBwUnref(PPDMACFILEBWMGR pBwMgr)
     582{
     583    Assert(pBwMgr->cRefs > 0);
     584    pBwMgr->cRefs--;
     585    if (!pBwMgr->cRefs)
     586        TMTimerStop(pBwMgr->pBwRefreshTimer);
     587}
     588
     589bool pdmacFileBwMgrIsTransferAllowed(PPDMACFILEBWMGR pBwMgr, uint32_t cbTransfer)
     590{
     591    bool fAllowed = false;
     592
     593    LogFlowFunc(("pBwMgr=%p cbTransfer=%u\n", pBwMgr, cbTransfer));
     594
     595    uint32_t cbOld = ASMAtomicSubU32(&pBwMgr->cbVMTransferAllowed, cbTransfer);
     596    if (RT_LIKELY(cbOld >= cbTransfer))
     597        fAllowed = true;
     598    else
     599    {
     600        /* We are out of ressources */
     601        ASMAtomicAddU32(&pBwMgr->cbVMTransferAllowed, cbTransfer);
     602        ASMAtomicXchgBool(&pBwMgr->fVMTransferLimitReached, true);
     603    }
     604
     605    LogFlowFunc(("fAllowed=%RTbool\n", fAllowed));
     606
     607    return fAllowed;
    503608}
    504609
     
    572677        else
    573678            LogRel(("AIOMgr: Cache was globally disabled\n"));
     679
     680        rc = pdmacFileBwMgrInitialize(pEpClassFile, pCfgNode, &pEpClassFile->pBwMgr);
     681        if (RT_FAILURE(rc))
     682            RTCritSectDelete(&pEpClassFile->CritSect);
    574683    }
    575684
     
    593702
    594703    RTCritSectDelete(&pEpClassFile->CritSect);
     704    pdmacFileBwMgrDestroy(pEpClassFile->pBwMgr);
    595705}
    596706
     
    705815
    706816                pEpFile->pTasksFreeTail = pEpFile->pTasksFreeHead;
    707                 pEpFile->cTasksCached = 0;
     817                pEpFile->cTasksCached   = 0;
     818                pEpFile->pBwMgr         = pEpClassFile->pBwMgr;
     819                pdmacFileBwRef(pEpFile->pBwMgr);
    708820
    709821                if (fUseFailsafeManager)
     
    753865                        RTMemFree(pEpFile->AioMgr.pTreeRangesLocked);
    754866                        MMR3HeapFree(pEpFile->pTasksFreeHead);
     867                        pdmacFileBwUnref(pEpFile->pBwMgr);
    755868                    }
    756869                }
     
    815928    if (pEpFile->fCaching)
    816929        pdmacFileEpCacheDestroy(pEpFile);
     930
     931    /* Remove from the bandwidth manager */
     932    pdmacFileBwUnref(pEpFile->pBwMgr);
    817933
    818934    /* Destroy the locked ranges tree now. */
  • trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h

    r26338 r26671  
    2525#include <VBox/cfgm.h>
    2626#include <VBox/stam.h>
     27#include <VBox/tm.h>
    2728#include <iprt/types.h>
    2829#include <iprt/file.h>
     
    148149    /** Size of the array. */
    149150    unsigned                               cReqEntries;
     151    /** Flag whether at least one endpoint reached its bandwidth limit. */
     152    bool                                   fBwLimitReached;
    150153    /** Critical section protecting the blocking event handling. */
    151154    RTCRITSECT                             CritSectBlockingEvent;
     
    188191
    189192/**
     193 * Bandwidth control manager instance data
     194 */
     195typedef struct PDMACFILEBWMGR
     196{
     197    /** Maximum number of bytes the VM is allowed to transfer (Max is 4GB/s) */
     198    uint32_t          cbVMTransferPerSecMax;
     199    /** Number of bytes we start with */
     200    uint32_t          cbVMTransferPerSecStart;
     201    /** Step after each update */
     202    uint32_t          cbVMTransferPerSecStep;
     203    /** Number of bytes we are allowed to transfer till the next update.
     204     * Resetted by the refresh timer. */
     205    volatile uint32_t cbVMTransferAllowed;
     206    /** Flag whether a request could not processed due to the limit. */
     207    volatile bool     fVMTransferLimitReached;
     208    /** Reference counter - How many endpoints are associated with this manager. */
     209    uint32_t          cRefs;
     210    /** The refresh timer */
     211    PTMTIMERR3        pBwRefreshTimer;
     212} PDMACFILEBWMGR;
     213/** Pointer to a bandwidth control manager */
     214typedef PDMACFILEBWMGR *PPDMACFILEBWMGR;
     215/** Pointer to a bandwidth control manager pointer */
     216typedef PPDMACFILEBWMGR *PPPDMACFILEBWMGR;
     217
     218/**
    190219 * A file access range lock.
    191220 */
     
    371400    /** Flag whether the out of resources warning was printed already. */
    372401    bool                                fOutOfResourcesWarningPrinted;
     402    /** The global bandwidth control manager */
     403    PPDMACFILEBWMGR                     pBwMgr;
    373404} PDMASYNCCOMPLETIONEPCLASSFILE;
    374405/** Pointer to the endpoint class data. */
     
    446477    /** Cache of endpoint data. */
    447478    PDMACFILEENDPOINTCACHE                 DataCache;
     479    /** Pointer to the associated bandwidth control manager */
     480    PPDMACFILEBWMGR                        pBwMgr;
    448481
    449482    /** Flag whether a flush request is currently active */
     
    594627void pdmacFileEpTaskCompleted(PPDMACTASKFILE pTask, void *pvUser);
    595628
     629bool pdmacFileBwMgrIsTransferAllowed(PPDMACFILEBWMGR pBwMgr, uint32_t cbTransfer);
     630
    596631int pdmacFileCacheInit(PPDMASYNCCOMPLETIONEPCLASSFILE pClassFile, PCFGMNODE pCfgNode);
    597632void pdmacFileCacheDestroy(PPDMASYNCCOMPLETIONEPCLASSFILE pClassFile);
  • trunk/src/VBox/VMM/PDMAsyncCompletionFileNormal.cpp

    r26526 r26671  
    712712        PPDMACTASKFILE pCurr = pTaskHead;
    713713
     714        if (!pdmacFileBwMgrIsTransferAllowed(pEndpoint->pBwMgr, pCurr->DataSeg.cbSeg))
     715        {
     716            pAioMgr->fBwLimitReached = true;
     717            break;
     718        }
     719
    714720        pTaskHead = pTaskHead->pNext;
    715721
     
    777783        pdmacFileAioMgrEpAddTaskList(pEndpoint, pTaskHead);
    778784
    779         if (RT_UNLIKELY(!cMaxRequests && !pEndpoint->pFlushReq))
     785        if (RT_UNLIKELY(  !cMaxRequests
     786                       && !pEndpoint->pFlushReq
     787                       && !pAioMgr->fBwLimitReached))
    780788        {
    781789            /*
     
    954962    PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead;
    955963
     964    pAioMgr->fBwLimitReached = false;
     965
    956966    while (pEndpoint)
    957967    {
     
    9921002
    9931003    return rc;
     1004}
     1005
     1006static void pdmacFileAioMgrNormalReqComplete(PPDMACEPFILEMGR pAioMgr, RTFILEAIOREQ hReq)
     1007{
     1008    int rc = VINF_SUCCESS;
     1009    PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint;
     1010    size_t cbTransfered  = 0;
     1011    int rcReq            = RTFileAioReqGetRC(hReq, &cbTransfered);
     1012    PPDMACTASKFILE pTask = (PPDMACTASKFILE)RTFileAioReqGetUser(hReq);
     1013
     1014    pEndpoint = pTask->pEndpoint;
     1015
     1016    /*
     1017     * It is possible that the request failed on Linux with kernels < 2.6.23
     1018     * if the passed buffer was allocated with remap_pfn_range or if the file
     1019     * is on an NFS endpoint which does not support async and direct I/O at the same time.
     1020     * The endpoint will be migrated to a failsafe manager in case a request fails.
     1021     */
     1022    if (RT_FAILURE(rcReq))
     1023    {
     1024        /* Free bounce buffers and the IPRT request. */
     1025        pAioMgr->pahReqsFree[pAioMgr->iFreeEntryNext] = hReq;
     1026        pAioMgr->iFreeEntryNext = (pAioMgr->iFreeEntryNext + 1) % pAioMgr->cReqEntries;
     1027
     1028        pAioMgr->cRequestsActive--;
     1029        pEndpoint->AioMgr.cRequestsActive--;
     1030        pEndpoint->AioMgr.cReqsProcessed++;
     1031
     1032        if (pTask->fBounceBuffer)
     1033            RTMemFree(pTask->pvBounceBuffer);
     1034
     1035        /* Queue the request on the pending list. */
     1036        pTask->pNext = pEndpoint->AioMgr.pReqsPendingHead;
     1037        pEndpoint->AioMgr.pReqsPendingHead = pTask;
     1038
     1039        /* Create a new failsafe manager if neccessary. */
     1040        if (!pEndpoint->AioMgr.fMoving)
     1041        {
     1042            PPDMACEPFILEMGR pAioMgrFailsafe;
     1043
     1044            LogRel(("%s: Request %#p failed with rc=%Rrc, migrating endpoint %s to failsafe manager.\n",
     1045                    RTThreadGetName(pAioMgr->Thread), pTask, rcReq, pEndpoint->Core.pszUri));
     1046
     1047            pEndpoint->AioMgr.fMoving = true;
     1048
     1049            rc = pdmacFileAioMgrCreate((PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass,
     1050                                        &pAioMgrFailsafe, true);
     1051            AssertRC(rc);
     1052
     1053            pEndpoint->AioMgr.pAioMgrDst = pAioMgrFailsafe;
     1054
     1055            /* Update the flags to open the file with. Disable async I/O and enable the host cache. */
     1056            pEndpoint->fFlags &= ~(RTFILE_O_ASYNC_IO | RTFILE_O_NO_CACHE);
     1057        }
     1058
     1059        /* If this was the last request for the endpoint migrate it to the new manager. */
     1060        if (!pEndpoint->AioMgr.cRequestsActive)
     1061        {
     1062            bool fReqsPending = pdmacFileAioMgrNormalRemoveEndpoint(pEndpoint);
     1063            Assert(!fReqsPending);
     1064
     1065            rc = pdmacFileAioMgrAddEndpoint(pEndpoint->AioMgr.pAioMgrDst, pEndpoint);
     1066            AssertRC(rc);
     1067        }
     1068    }
     1069    else
     1070    {
     1071        AssertMsg((   (cbTransfered == pTask->DataSeg.cbSeg)
     1072                    || (pTask->fBounceBuffer && (cbTransfered >= pTask->DataSeg.cbSeg))),
     1073                    ("Task didn't completed successfully (rc=%Rrc) or was incomplete (cbTransfered=%u)\n", rcReq, cbTransfered));
     1074
     1075        if (pTask->fPrefetch)
     1076        {
     1077            Assert(pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE);
     1078            Assert(pTask->fBounceBuffer);
     1079
     1080            memcpy(((uint8_t *)pTask->pvBounceBuffer) + pTask->uBounceBufOffset,
     1081                    pTask->DataSeg.pvSeg,
     1082                    pTask->DataSeg.cbSeg);
     1083
     1084            /* Write it now. */
     1085            pTask->fPrefetch = false;
     1086            size_t cbToTransfer = RT_ALIGN_Z(pTask->DataSeg.cbSeg, 512);
     1087            RTFOFF offStart = pTask->Off & ~(RTFOFF)(512-1);
     1088
     1089            /* Grow the file if needed. */
     1090            if (RT_UNLIKELY((uint64_t)(pTask->Off + pTask->DataSeg.cbSeg) > pEndpoint->cbFile))
     1091            {
     1092                ASMAtomicWriteU64(&pEndpoint->cbFile, pTask->Off + pTask->DataSeg.cbSeg);
     1093                RTFileSetSize(pEndpoint->File, pTask->Off + pTask->DataSeg.cbSeg);
     1094            }
     1095
     1096            rc = RTFileAioReqPrepareWrite(hReq, pEndpoint->File,
     1097                                          offStart, pTask->pvBounceBuffer, cbToTransfer, pTask);
     1098            AssertRC(rc);
     1099            rc = RTFileAioCtxSubmit(pAioMgr->hAioCtx, &hReq, 1);
     1100            AssertRC(rc);
     1101        }
     1102        else
     1103        {
     1104            if (pTask->fBounceBuffer)
     1105            {
     1106                if (pTask->enmTransferType == PDMACTASKFILETRANSFER_READ)
     1107                    memcpy(pTask->DataSeg.pvSeg,
     1108                            ((uint8_t *)pTask->pvBounceBuffer) + pTask->uBounceBufOffset,
     1109                            pTask->DataSeg.cbSeg);
     1110
     1111                RTMemPageFree(pTask->pvBounceBuffer);
     1112            }
     1113
     1114            /* Put the entry on the free array */
     1115            pAioMgr->pahReqsFree[pAioMgr->iFreeEntryNext] = hReq;
     1116            pAioMgr->iFreeEntryNext = (pAioMgr->iFreeEntryNext + 1) % pAioMgr->cReqEntries;
     1117
     1118            pAioMgr->cRequestsActive--;
     1119            pEndpoint->AioMgr.cRequestsActive--;
     1120            pEndpoint->AioMgr.cReqsProcessed++;
     1121
     1122            /* Free the lock and process pending tasks if neccessary */
     1123            pdmacFileAioMgrNormalRangeLockFree(pAioMgr, pEndpoint, pTask->pRangeLock);
     1124
     1125            /* Call completion callback */
     1126            pTask->pfnCompleted(pTask, pTask->pvUser);
     1127            pdmacFileTaskFree(pEndpoint, pTask);
     1128
     1129            /*
     1130             * If there is no request left on the endpoint but a flush request is set
     1131             * it completed now and we notify the owner.
     1132             * Furthermore we look for new requests and continue.
     1133             */
     1134            if (!pEndpoint->AioMgr.cRequestsActive && pEndpoint->pFlushReq)
     1135            {
     1136                /* Call completion callback */
     1137                pTask = pEndpoint->pFlushReq;
     1138                pEndpoint->pFlushReq = NULL;
     1139
     1140                AssertMsg(pTask->pEndpoint == pEndpoint, ("Endpoint of the flush request does not match assigned one\n"));
     1141
     1142                pTask->pfnCompleted(pTask, pTask->pvUser);
     1143                pdmacFileTaskFree(pEndpoint, pTask);
     1144            }
     1145            else if (RT_UNLIKELY(!pEndpoint->AioMgr.cRequestsActive && pEndpoint->AioMgr.fMoving))
     1146            {
     1147                /* If the endpoint is about to be migrated do it now. */
     1148                bool fReqsPending = pdmacFileAioMgrNormalRemoveEndpoint(pEndpoint);
     1149                Assert(!fReqsPending);
     1150
     1151                rc = pdmacFileAioMgrAddEndpoint(pEndpoint->AioMgr.pAioMgrDst, pEndpoint);
     1152                AssertRC(rc);
     1153            }
     1154        }
     1155    } /* request completed successfully */
    9941156}
    9951157
     
    10401202            CHECK_RC(pAioMgr, rc);
    10411203
    1042             while (pAioMgr->cRequestsActive)
    1043             {
    1044                 RTFILEAIOREQ  apReqs[20];
    1045                 uint32_t cReqsCompleted = 0;
    1046                 size_t cReqsWait;
    1047 
    1048                 if (pAioMgr->cRequestsActive > RT_ELEMENTS(apReqs))
    1049                     cReqsWait = RT_ELEMENTS(apReqs);
     1204            while (   pAioMgr->cRequestsActive
     1205                   || pAioMgr->fBwLimitReached)
     1206            {
     1207                if (pAioMgr->cRequestsActive)
     1208                {
     1209                    RTFILEAIOREQ  apReqs[20];
     1210                    uint32_t cReqsCompleted = 0;
     1211                    size_t cReqsWait;
     1212
     1213                    if (pAioMgr->cRequestsActive > RT_ELEMENTS(apReqs))
     1214                        cReqsWait = RT_ELEMENTS(apReqs);
     1215                    else
     1216                        cReqsWait = pAioMgr->cRequestsActive;
     1217
     1218                    LogFlow(("Waiting for %d of %d tasks to complete\n", pAioMgr->cRequestsActive, cReqsWait));
     1219
     1220                    rc = RTFileAioCtxWait(pAioMgr->hAioCtx,
     1221                                          cReqsWait,
     1222                                          RT_INDEFINITE_WAIT, apReqs,
     1223                                          RT_ELEMENTS(apReqs), &cReqsCompleted);
     1224                    if (RT_FAILURE(rc) && (rc != VERR_INTERRUPTED))
     1225                        CHECK_RC(pAioMgr, rc);
     1226
     1227                    LogFlow(("%d tasks completed\n", cReqsCompleted));
     1228
     1229                    for (uint32_t i = 0; i < cReqsCompleted; i++)
     1230                        pdmacFileAioMgrNormalReqComplete(pAioMgr, apReqs[i]);
     1231
     1232                    /* Check for an external blocking event before we go to sleep again. */
     1233                    if (pAioMgr->fBlockingEventPending)
     1234                    {
     1235                        rc = pdmacFileAioMgrNormalProcessBlockingEvent(pAioMgr);
     1236                        CHECK_RC(pAioMgr, rc);
     1237                    }
     1238
     1239                    /* Update load statistics. */
     1240                    uint64_t uMillisCurr = RTTimeMilliTS();
     1241                    if (uMillisCurr > uMillisEnd)
     1242                    {
     1243                        PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointCurr = pAioMgr->pEndpointsHead;
     1244
     1245                        /* Calculate timespan. */
     1246                        uMillisCurr -= uMillisEnd;
     1247
     1248                        while (pEndpointCurr)
     1249                        {
     1250                            pEndpointCurr->AioMgr.cReqsPerSec    = pEndpointCurr->AioMgr.cReqsProcessed / (uMillisCurr + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD);
     1251                            pEndpointCurr->AioMgr.cReqsProcessed = 0;
     1252                            pEndpointCurr = pEndpointCurr->AioMgr.pEndpointNext;
     1253                        }
     1254
     1255                        /* Set new update interval */
     1256                        uMillisEnd = RTTimeMilliTS() + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD;
     1257                    }
     1258                }
    10501259                else
    1051                     cReqsWait = pAioMgr->cRequestsActive;
    1052 
    1053                 LogFlow(("Waiting for %d of %d tasks to complete\n", pAioMgr->cRequestsActive, cReqsWait));
    1054 
    1055                 rc = RTFileAioCtxWait(pAioMgr->hAioCtx,
    1056                                       cReqsWait,
    1057                                       RT_INDEFINITE_WAIT, apReqs,
    1058                                       RT_ELEMENTS(apReqs), &cReqsCompleted);
    1059                 if (RT_FAILURE(rc) && (rc != VERR_INTERRUPTED))
    1060                     CHECK_RC(pAioMgr, rc);
    1061 
    1062                 LogFlow(("%d tasks completed\n", cReqsCompleted));
    1063 
    1064                 for (uint32_t i = 0; i < cReqsCompleted; i++)
    10651260                {
    1066                     PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint;
    1067                     size_t cbTransfered  = 0;
    1068                     int rcReq            = RTFileAioReqGetRC(apReqs[i], &cbTransfered);
    1069                     PPDMACTASKFILE pTask = (PPDMACTASKFILE)RTFileAioReqGetUser(apReqs[i]);
    1070 
    1071                     pEndpoint = pTask->pEndpoint;
    1072 
    10731261                    /*
    1074                      * It is possible that the request failed on Linux with kernels < 2.6.23
    1075                      * if the passed buffer was allocated with remap_pfn_range or if the file
    1076                      * is on an NFS endpoint which does not support async and direct I/O at the same time.
    1077                      * The endpoint will be migrated to a failsafe manager in case a request fails.
     1262                     * Bandwidth limit reached for all endpoints.
     1263                     * Yield and wait until we have enough resources again.
    10781264                     */
    1079                     if (RT_FAILURE(rcReq))
    1080                     {
    1081                         /* Free bounce buffers and the IPRT request. */
    1082                         pAioMgr->pahReqsFree[pAioMgr->iFreeEntryNext] = apReqs[i];
    1083                         pAioMgr->iFreeEntryNext = (pAioMgr->iFreeEntryNext + 1) % pAioMgr->cReqEntries;
    1084 
    1085                         pAioMgr->cRequestsActive--;
    1086                         pEndpoint->AioMgr.cRequestsActive--;
    1087                         pEndpoint->AioMgr.cReqsProcessed++;
    1088 
    1089                         if (pTask->fBounceBuffer)
    1090                             RTMemFree(pTask->pvBounceBuffer);
    1091 
    1092                         /* Queue the request on the pending list. */
    1093                         pTask->pNext = pEndpoint->AioMgr.pReqsPendingHead;
    1094                         pEndpoint->AioMgr.pReqsPendingHead = pTask;
    1095 
    1096                         /* Create a new failsafe manager if neccessary. */
    1097                         if (!pEndpoint->AioMgr.fMoving)
    1098                         {
    1099                             PPDMACEPFILEMGR pAioMgrFailsafe;
    1100 
    1101                             LogRel(("%s: Request %#p failed with rc=%Rrc, migrating endpoint %s to failsafe manager.\n",
    1102                                     RTThreadGetName(pAioMgr->Thread), pTask, rcReq, pEndpoint->Core.pszUri));
    1103 
    1104                             pEndpoint->AioMgr.fMoving = true;
    1105 
    1106                             rc = pdmacFileAioMgrCreate((PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass,
    1107                                                        &pAioMgrFailsafe, true);
    1108                             AssertRC(rc);
    1109 
    1110                             pEndpoint->AioMgr.pAioMgrDst = pAioMgrFailsafe;
    1111 
    1112                             /* Update the flags to open the file with. Disable async I/O and enable the host cache. */
    1113                             pEndpoint->fFlags &= ~(RTFILE_O_ASYNC_IO | RTFILE_O_NO_CACHE);
    1114                         }
    1115 
    1116                         /* If this was the last request for the endpoint migrate it to the new manager. */
    1117                         if (!pEndpoint->AioMgr.cRequestsActive)
    1118                         {
    1119                             bool fReqsPending = pdmacFileAioMgrNormalRemoveEndpoint(pEndpoint);
    1120                             Assert(!fReqsPending);
    1121 
    1122                             rc = pdmacFileAioMgrAddEndpoint(pEndpoint->AioMgr.pAioMgrDst, pEndpoint);
    1123                             AssertRC(rc);
    1124                         }
    1125                     }
    1126                     else
    1127                     {
    1128                         AssertMsg((   (cbTransfered == pTask->DataSeg.cbSeg)
    1129                                    || (pTask->fBounceBuffer && (cbTransfered >= pTask->DataSeg.cbSeg))),
    1130                                   ("Task didn't completed successfully (rc=%Rrc) or was incomplete (cbTransfered=%u)\n", rcReq, cbTransfered));
    1131 
    1132                         if (pTask->fPrefetch)
    1133                         {
    1134                             Assert(pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE);
    1135                             Assert(pTask->fBounceBuffer);
    1136 
    1137                             memcpy(((uint8_t *)pTask->pvBounceBuffer) + pTask->uBounceBufOffset,
    1138                                     pTask->DataSeg.pvSeg,
    1139                                     pTask->DataSeg.cbSeg);
    1140 
    1141                             /* Write it now. */
    1142                             pTask->fPrefetch = false;
    1143                             size_t cbToTransfer = RT_ALIGN_Z(pTask->DataSeg.cbSeg, 512);
    1144                             RTFOFF offStart = pTask->Off & ~(RTFOFF)(512-1);
    1145 
    1146                             /* Grow the file if needed. */
    1147                             if (RT_UNLIKELY((uint64_t)(pTask->Off + pTask->DataSeg.cbSeg) > pEndpoint->cbFile))
    1148                             {
    1149                                 ASMAtomicWriteU64(&pEndpoint->cbFile, pTask->Off + pTask->DataSeg.cbSeg);
    1150                                 RTFileSetSize(pEndpoint->File, pTask->Off + pTask->DataSeg.cbSeg);
    1151                             }
    1152 
    1153                             rc = RTFileAioReqPrepareWrite(apReqs[i], pEndpoint->File,
    1154                                                           offStart, pTask->pvBounceBuffer, cbToTransfer, pTask);
    1155                             AssertRC(rc);
    1156                             rc = RTFileAioCtxSubmit(pAioMgr->hAioCtx, &apReqs[i], 1);
    1157                             AssertRC(rc);
    1158                         }
    1159                         else
    1160                         {
    1161                             if (pTask->fBounceBuffer)
    1162                             {
    1163                                 if (pTask->enmTransferType == PDMACTASKFILETRANSFER_READ)
    1164                                     memcpy(pTask->DataSeg.pvSeg,
    1165                                            ((uint8_t *)pTask->pvBounceBuffer) + pTask->uBounceBufOffset,
    1166                                            pTask->DataSeg.cbSeg);
    1167 
    1168                                 RTMemPageFree(pTask->pvBounceBuffer);
    1169                             }
    1170 
    1171                             /* Put the entry on the free array */
    1172                             pAioMgr->pahReqsFree[pAioMgr->iFreeEntryNext] = apReqs[i];
    1173                             pAioMgr->iFreeEntryNext = (pAioMgr->iFreeEntryNext + 1) % pAioMgr->cReqEntries;
    1174 
    1175                             pAioMgr->cRequestsActive--;
    1176                             pEndpoint->AioMgr.cRequestsActive--;
    1177                             pEndpoint->AioMgr.cReqsProcessed++;
    1178 
    1179                             /* Free the lock and process pending tasks if neccessary */
    1180                             pdmacFileAioMgrNormalRangeLockFree(pAioMgr, pEndpoint, pTask->pRangeLock);
    1181 
    1182                             /* Call completion callback */
    1183                             pTask->pfnCompleted(pTask, pTask->pvUser);
    1184                             pdmacFileTaskFree(pEndpoint, pTask);
    1185 
    1186                             /*
    1187                              * If there is no request left on the endpoint but a flush request is set
    1188                              * it completed now and we notify the owner.
    1189                              * Furthermore we look for new requests and continue.
    1190                              */
    1191                             if (!pEndpoint->AioMgr.cRequestsActive && pEndpoint->pFlushReq)
    1192                             {
    1193                                 /* Call completion callback */
    1194                                 pTask = pEndpoint->pFlushReq;
    1195                                 pEndpoint->pFlushReq = NULL;
    1196 
    1197                                 AssertMsg(pTask->pEndpoint == pEndpoint, ("Endpoint of the flush request does not match assigned one\n"));
    1198 
    1199                                 pTask->pfnCompleted(pTask, pTask->pvUser);
    1200                                 pdmacFileTaskFree(pEndpoint, pTask);
    1201                             }
    1202                             else if (RT_UNLIKELY(!pEndpoint->AioMgr.cRequestsActive && pEndpoint->AioMgr.fMoving))
    1203                             {
    1204                                 /* If the endpoint is about to be migrated do it now. */
    1205                                 bool fReqsPending = pdmacFileAioMgrNormalRemoveEndpoint(pEndpoint);
    1206                                 Assert(!fReqsPending);
    1207 
    1208                                 rc = pdmacFileAioMgrAddEndpoint(pEndpoint->AioMgr.pAioMgrDst, pEndpoint);
    1209                                 AssertRC(rc);
    1210                             }
    1211                         }
    1212                     } /* request completed successfully */
    1213                 } /* for every completed request */
    1214 
    1215                 /* Check for an external blocking event before we go to sleep again. */
    1216                 if (pAioMgr->fBlockingEventPending)
    1217                 {
    1218                     rc = pdmacFileAioMgrNormalProcessBlockingEvent(pAioMgr);
    1219                     CHECK_RC(pAioMgr, rc);
    1220                 }
    1221 
    1222                 /* Update load statistics. */
    1223                 uint64_t uMillisCurr = RTTimeMilliTS();
    1224                 if (uMillisCurr > uMillisEnd)
    1225                 {
    1226                     PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointCurr = pAioMgr->pEndpointsHead;
    1227 
    1228                     /* Calculate timespan. */
    1229                     uMillisCurr -= uMillisEnd;
    1230 
    1231                     while (pEndpointCurr)
    1232                     {
    1233                         pEndpointCurr->AioMgr.cReqsPerSec    = pEndpointCurr->AioMgr.cReqsProcessed / (uMillisCurr + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD);
    1234                         pEndpointCurr->AioMgr.cReqsProcessed = 0;
    1235                         pEndpointCurr = pEndpointCurr->AioMgr.pEndpointNext;
    1236                     }
    1237 
    1238                     /* Set new update interval */
    1239                     uMillisEnd = RTTimeMilliTS() + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD;
     1265                    RTThreadYield();
    12401266                }
    12411267
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