Changeset 26671 in vbox
- Timestamp:
- Feb 22, 2010 7:21:34 AM (15 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 3 edited
-
PDMAsyncCompletionFile.cpp (modified) (8 diffs)
-
PDMAsyncCompletionFileInternal.h (modified) (6 diffs)
-
PDMAsyncCompletionFileNormal.cpp (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/PDMAsyncCompletionFile.cpp
r26527 r26671 464 464 465 465 /** 466 * I/O refresh timer callback. 467 */ 468 static 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 /** 466 493 * Destroys a async I/O manager. 467 494 * … … 490 517 491 518 pEpClassFile->cAioMgrs--; 492 493 519 rc = RTCritSectLeave(&pEpClassFile->CritSect); 494 520 AssertRC(rc); … … 501 527 502 528 MMR3HeapFree(pAioMgr); 529 } 530 531 static 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 568 static void pdmacFileBwMgrDestroy(PPDMACFILEBWMGR pBwMgr) 569 { 570 TMR3TimerDestroy(pBwMgr->pBwRefreshTimer); 571 MMR3HeapFree(pBwMgr); 572 } 573 574 static void pdmacFileBwRef(PPDMACFILEBWMGR pBwMgr) 575 { 576 pBwMgr->cRefs++; 577 if (pBwMgr->cRefs == 1) 578 TMTimerSetMillies(pBwMgr->pBwRefreshTimer, 1000); /* 1sec update interval */ 579 } 580 581 static void pdmacFileBwUnref(PPDMACFILEBWMGR pBwMgr) 582 { 583 Assert(pBwMgr->cRefs > 0); 584 pBwMgr->cRefs--; 585 if (!pBwMgr->cRefs) 586 TMTimerStop(pBwMgr->pBwRefreshTimer); 587 } 588 589 bool 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; 503 608 } 504 609 … … 572 677 else 573 678 LogRel(("AIOMgr: Cache was globally disabled\n")); 679 680 rc = pdmacFileBwMgrInitialize(pEpClassFile, pCfgNode, &pEpClassFile->pBwMgr); 681 if (RT_FAILURE(rc)) 682 RTCritSectDelete(&pEpClassFile->CritSect); 574 683 } 575 684 … … 593 702 594 703 RTCritSectDelete(&pEpClassFile->CritSect); 704 pdmacFileBwMgrDestroy(pEpClassFile->pBwMgr); 595 705 } 596 706 … … 705 815 706 816 pEpFile->pTasksFreeTail = pEpFile->pTasksFreeHead; 707 pEpFile->cTasksCached = 0; 817 pEpFile->cTasksCached = 0; 818 pEpFile->pBwMgr = pEpClassFile->pBwMgr; 819 pdmacFileBwRef(pEpFile->pBwMgr); 708 820 709 821 if (fUseFailsafeManager) … … 753 865 RTMemFree(pEpFile->AioMgr.pTreeRangesLocked); 754 866 MMR3HeapFree(pEpFile->pTasksFreeHead); 867 pdmacFileBwUnref(pEpFile->pBwMgr); 755 868 } 756 869 } … … 815 928 if (pEpFile->fCaching) 816 929 pdmacFileEpCacheDestroy(pEpFile); 930 931 /* Remove from the bandwidth manager */ 932 pdmacFileBwUnref(pEpFile->pBwMgr); 817 933 818 934 /* Destroy the locked ranges tree now. */ -
trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h
r26338 r26671 25 25 #include <VBox/cfgm.h> 26 26 #include <VBox/stam.h> 27 #include <VBox/tm.h> 27 28 #include <iprt/types.h> 28 29 #include <iprt/file.h> … … 148 149 /** Size of the array. */ 149 150 unsigned cReqEntries; 151 /** Flag whether at least one endpoint reached its bandwidth limit. */ 152 bool fBwLimitReached; 150 153 /** Critical section protecting the blocking event handling. */ 151 154 RTCRITSECT CritSectBlockingEvent; … … 188 191 189 192 /** 193 * Bandwidth control manager instance data 194 */ 195 typedef 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 */ 214 typedef PDMACFILEBWMGR *PPDMACFILEBWMGR; 215 /** Pointer to a bandwidth control manager pointer */ 216 typedef PPDMACFILEBWMGR *PPPDMACFILEBWMGR; 217 218 /** 190 219 * A file access range lock. 191 220 */ … … 371 400 /** Flag whether the out of resources warning was printed already. */ 372 401 bool fOutOfResourcesWarningPrinted; 402 /** The global bandwidth control manager */ 403 PPDMACFILEBWMGR pBwMgr; 373 404 } PDMASYNCCOMPLETIONEPCLASSFILE; 374 405 /** Pointer to the endpoint class data. */ … … 446 477 /** Cache of endpoint data. */ 447 478 PDMACFILEENDPOINTCACHE DataCache; 479 /** Pointer to the associated bandwidth control manager */ 480 PPDMACFILEBWMGR pBwMgr; 448 481 449 482 /** Flag whether a flush request is currently active */ … … 594 627 void pdmacFileEpTaskCompleted(PPDMACTASKFILE pTask, void *pvUser); 595 628 629 bool pdmacFileBwMgrIsTransferAllowed(PPDMACFILEBWMGR pBwMgr, uint32_t cbTransfer); 630 596 631 int pdmacFileCacheInit(PPDMASYNCCOMPLETIONEPCLASSFILE pClassFile, PCFGMNODE pCfgNode); 597 632 void pdmacFileCacheDestroy(PPDMASYNCCOMPLETIONEPCLASSFILE pClassFile); -
trunk/src/VBox/VMM/PDMAsyncCompletionFileNormal.cpp
r26526 r26671 712 712 PPDMACTASKFILE pCurr = pTaskHead; 713 713 714 if (!pdmacFileBwMgrIsTransferAllowed(pEndpoint->pBwMgr, pCurr->DataSeg.cbSeg)) 715 { 716 pAioMgr->fBwLimitReached = true; 717 break; 718 } 719 714 720 pTaskHead = pTaskHead->pNext; 715 721 … … 777 783 pdmacFileAioMgrEpAddTaskList(pEndpoint, pTaskHead); 778 784 779 if (RT_UNLIKELY(!cMaxRequests && !pEndpoint->pFlushReq)) 785 if (RT_UNLIKELY( !cMaxRequests 786 && !pEndpoint->pFlushReq 787 && !pAioMgr->fBwLimitReached)) 780 788 { 781 789 /* … … 954 962 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead; 955 963 964 pAioMgr->fBwLimitReached = false; 965 956 966 while (pEndpoint) 957 967 { … … 992 1002 993 1003 return rc; 1004 } 1005 1006 static 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 */ 994 1156 } 995 1157 … … 1040 1202 CHECK_RC(pAioMgr, rc); 1041 1203 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 } 1050 1259 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++)1065 1260 { 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 1073 1261 /* 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. 1078 1264 */ 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(); 1240 1266 } 1241 1267
Note:
See TracChangeset
for help on using the changeset viewer.

