diff options
Diffstat (limited to 'src/VBox/VMM/VMMR3/PDMAsyncCompletionFileNormal.cpp')
| -rw-r--r-- | src/VBox/VMM/VMMR3/PDMAsyncCompletionFileNormal.cpp | 67 |
1 files changed, 43 insertions, 24 deletions
diff --git a/src/VBox/VMM/VMMR3/PDMAsyncCompletionFileNormal.cpp b/src/VBox/VMM/VMMR3/PDMAsyncCompletionFileNormal.cpp index 2b37f009..44d31e7f 100644 --- a/src/VBox/VMM/VMMR3/PDMAsyncCompletionFileNormal.cpp +++ b/src/VBox/VMM/VMMR3/PDMAsyncCompletionFileNormal.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -54,9 +54,9 @@ int pdmacFileAioMgrNormalInit(PPDMACEPFILEMGR pAioMgr) { pAioMgr->cRequestsActiveMax = PDMACEPFILEMGR_REQS_STEP; - int rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, RTFILEAIO_UNLIMITED_REQS); + int rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, RTFILEAIO_UNLIMITED_REQS, 0 /* fFlags */); if (rc == VERR_OUT_OF_RANGE) - rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, pAioMgr->cRequestsActiveMax); + rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, pAioMgr->cRequestsActiveMax, 0 /* fFlags */); if (RT_SUCCESS(rc)) { @@ -354,9 +354,9 @@ static int pdmacFileAioMgrNormalGrow(PPDMACEPFILEMGR pAioMgr) pAioMgr->cRequestsActiveMax += PDMACEPFILEMGR_REQS_STEP; RTFILEAIOCTX hAioCtxNew = NIL_RTFILEAIOCTX; - int rc = RTFileAioCtxCreate(&hAioCtxNew, RTFILEAIO_UNLIMITED_REQS); + int rc = RTFileAioCtxCreate(&hAioCtxNew, RTFILEAIO_UNLIMITED_REQS, 0 /* fFlags */); if (rc == VERR_OUT_OF_RANGE) - rc = RTFileAioCtxCreate(&hAioCtxNew, pAioMgr->cRequestsActiveMax); + rc = RTFileAioCtxCreate(&hAioCtxNew, pAioMgr->cRequestsActiveMax, 0 /* fFlags */); if (RT_SUCCESS(rc)) { @@ -637,12 +637,19 @@ static int pdmacFileAioMgrNormalReqsEnqueue(PPDMACEPFILEMGR pAioMgr, static bool pdmacFileAioMgrNormalIsRangeLocked(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, RTFOFF offStart, size_t cbRange, - PPDMACTASKFILE pTask) + PPDMACTASKFILE pTask, bool fAlignedReq) { AssertMsg( pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE || pTask->enmTransferType == PDMACTASKFILETRANSFER_READ, ("Invalid task type %d\n", pTask->enmTransferType)); + /* + * If there is no unaligned request active and the current one is aligned + * just pass it through. + */ + if (!pEndpoint->AioMgr.cLockedReqsActive && fAlignedReq) + return false; + PPDMACFILERANGELOCK pRangeLock; pRangeLock = (PPDMACFILERANGELOCK)RTAvlrFileOffsetRangeGet(pEndpoint->AioMgr.pTreeRangesLocked, offStart); if (!pRangeLock) @@ -658,12 +665,7 @@ static bool pdmacFileAioMgrNormalIsRangeLocked(PPDMASYNCCOMPLETIONENDPOINTFILE p } /* Check whether we have one of the situations explained below */ - if ( pRangeLock -#if 0 /** @todo later. For now we will just block all requests if they interfere */ - && ( (pRangeLock->fReadLock && pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE) - || (!pRangeLock->fReadLock) -#endif - ) + if (pRangeLock) { /* Add to the list. */ pTask->pNext = NULL; @@ -689,15 +691,25 @@ static bool pdmacFileAioMgrNormalIsRangeLocked(PPDMASYNCCOMPLETIONENDPOINTFILE p static int pdmacFileAioMgrNormalRangeLock(PPDMACEPFILEMGR pAioMgr, PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, RTFOFF offStart, size_t cbRange, - PPDMACTASKFILE pTask) + PPDMACTASKFILE pTask, bool fAlignedReq) { LogFlowFunc(("pAioMgr=%#p pEndpoint=%#p offStart=%RTfoff cbRange=%zu pTask=%#p\n", pAioMgr, pEndpoint, offStart, cbRange, pTask)); - AssertMsg(!pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, offStart, cbRange, pTask), + AssertMsg(!pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, offStart, cbRange, pTask, fAlignedReq), ("Range is already locked offStart=%RTfoff cbRange=%u\n", offStart, cbRange)); + /* + * If there is no unaligned request active and the current one is aligned + * just don't use the lock. + */ + if (!pEndpoint->AioMgr.cLockedReqsActive && fAlignedReq) + { + pTask->pRangeLock = NULL; + return VINF_SUCCESS; + } + PPDMACFILERANGELOCK pRangeLock = (PPDMACFILERANGELOCK)RTMemCacheAlloc(pAioMgr->hMemCacheRangeLocks); if (!pRangeLock) return VERR_NO_MEMORY; @@ -715,6 +727,7 @@ static int pdmacFileAioMgrNormalRangeLock(PPDMACEPFILEMGR pAioMgr, /* Let the task point to its lock. */ pTask->pRangeLock = pRangeLock; + pEndpoint->AioMgr.cLockedReqsActive++; return VINF_SUCCESS; } @@ -728,7 +741,10 @@ static PPDMACTASKFILE pdmacFileAioMgrNormalRangeLockFree(PPDMACEPFILEMGR pAioMgr LogFlowFunc(("pAioMgr=%#p pEndpoint=%#p pRangeLock=%#p\n", pAioMgr, pEndpoint, pRangeLock)); - AssertPtr(pRangeLock); + /* pRangeLock can be NULL if there was no lock assigned with the task. */ + if (!pRangeLock) + return NULL; + Assert(pRangeLock->cRefs == 1); RTAvlrFileOffsetRemove(pEndpoint->AioMgr.pTreeRangesLocked, pRangeLock->Core.Key); @@ -736,6 +752,7 @@ static PPDMACTASKFILE pdmacFileAioMgrNormalRangeLockFree(PPDMACEPFILEMGR pAioMgr pRangeLock->pWaitingTasksHead = NULL; pRangeLock->pWaitingTasksTail = NULL; RTMemCacheFree(pAioMgr->hMemCacheRangeLocks, pRangeLock); + pEndpoint->AioMgr.cLockedReqsActive--; return pTasksWaitingHead; } @@ -771,7 +788,8 @@ static int pdmacFileAioMgrNormalTaskPrepareBuffered(PPDMACEPFILEMGR pAioMgr, * the same range. This will result in data corruption if both are executed concurrently. */ int rc = VINF_SUCCESS; - bool fLocked = pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, pTask->Off, pTask->DataSeg.cbSeg, pTask); + bool fLocked = pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, pTask->Off, pTask->DataSeg.cbSeg, pTask, + true /* fAlignedReq */); if (!fLocked) { /* Get a request handle. */ @@ -799,7 +817,7 @@ static int pdmacFileAioMgrNormalTaskPrepareBuffered(PPDMACEPFILEMGR pAioMgr, rc = pdmacFileAioMgrNormalRangeLock(pAioMgr, pEndpoint, pTask->Off, pTask->DataSeg.cbSeg, - pTask); + pTask, true /* fAlignedReq */); if (RT_SUCCESS(rc)) { @@ -825,6 +843,8 @@ static int pdmacFileAioMgrNormalTaskPrepareNonBuffered(PPDMACEPFILEMGR pAioMgr, RTFOFF offStart = pTask->Off & ~(RTFOFF)(512-1); size_t cbToTransfer = RT_ALIGN_Z(pTask->DataSeg.cbSeg + (pTask->Off - offStart), 512); PDMACTASKFILETRANSFER enmTransferType = pTask->enmTransferType; + bool fAlignedReq = cbToTransfer == pTask->DataSeg.cbSeg + && offStart == pTask->Off; AssertMsg( pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE || (uint64_t)(offStart + cbToTransfer) <= pEndpoint->cbFile, @@ -852,7 +872,7 @@ static int pdmacFileAioMgrNormalTaskPrepareNonBuffered(PPDMACEPFILEMGR pAioMgr, * the same range. This will result in data corruption if both are executed concurrently. */ int rc = VINF_SUCCESS; - bool fLocked = pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, offStart, cbToTransfer, pTask); + bool fLocked = pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, offStart, cbToTransfer, pTask, fAlignedReq); if (!fLocked) { PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass; @@ -862,8 +882,7 @@ static int pdmacFileAioMgrNormalTaskPrepareNonBuffered(PPDMACEPFILEMGR pAioMgr, RTFILEAIOREQ hReq = pdmacFileAioMgrNormalRequestAlloc(pAioMgr); AssertMsg(hReq != NIL_RTFILEAIOREQ, ("Out of request handles\n")); - if ( RT_UNLIKELY(cbToTransfer != pTask->DataSeg.cbSeg) - || RT_UNLIKELY(offStart != pTask->Off) + if ( !fAlignedReq || ((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) != (RTR3UINTPTR)pvBuf)) { LogFlow(("Using bounce buffer for task %#p cbToTransfer=%zd cbSeg=%zd offStart=%RTfoff off=%RTfoff\n", @@ -928,8 +947,7 @@ static int pdmacFileAioMgrNormalTaskPrepareNonBuffered(PPDMACEPFILEMGR pAioMgr, offStart, pvBuf, cbToTransfer, pTask); AssertRC(rc); - rc = pdmacFileAioMgrNormalRangeLock(pAioMgr, pEndpoint, offStart, cbToTransfer, pTask); - + rc = pdmacFileAioMgrNormalRangeLock(pAioMgr, pEndpoint, offStart, cbToTransfer, pTask, fAlignedReq); if (RT_SUCCESS(rc)) { pTask->hReq = hReq; @@ -998,6 +1016,7 @@ static int pdmacFileAioMgrNormalProcessTaskList(PPDMACTASKFILE pTaskHead, rc = RTFileAioReqPrepareFlush(hReq, pEndpoint->hFile, pCurr); if (RT_FAILURE(rc)) { + LogRel(("AIOMgr: Preparing flush failed with %Rrc, disabling async flushes\n", rc)); pEndpoint->fAsyncFlushSupported = false; pdmacFileAioMgrNormalRequestFree(pAioMgr, hReq); rc = VINF_SUCCESS; /* Fake success */ @@ -1349,7 +1368,7 @@ static void pdmacFileAioMgrNormalReqCompleteRc(PPDMACEPFILEMGR pAioMgr, RTFILEAI if (pTask->enmTransferType == PDMACTASKFILETRANSFER_FLUSH) { - LogFlow(("Async flushes are not supported for this endpoint, disabling\n")); + LogRel(("AIOMgr: Flush failed with %Rrc, disabling async flushes\n", rcReq)); pEndpoint->fAsyncFlushSupported = false; AssertMsg(pEndpoint->pFlushReq == pTask, ("Failed flush request doesn't match active one\n")); /* The other method will take over now. */ @@ -1497,8 +1516,8 @@ static void pdmacFileAioMgrNormalReqCompleteRc(PPDMACEPFILEMGR pAioMgr, RTFILEAI /* Write it now. */ pTask->fPrefetch = false; - size_t cbToTransfer = RT_ALIGN_Z(pTask->DataSeg.cbSeg, 512); RTFOFF offStart = pTask->Off & ~(RTFOFF)(512-1); + size_t cbToTransfer = RT_ALIGN_Z(pTask->DataSeg.cbSeg + (pTask->Off - offStart), 512); /* Grow the file if needed. */ if (RT_UNLIKELY((uint64_t)(pTask->Off + pTask->DataSeg.cbSeg) > pEndpoint->cbFile)) |
