VirtualBox

Changeset 26338 in vbox


Ignore:
Timestamp:
Feb 9, 2010 12:54:20 AM (15 years ago)
Author:
vboxsync
Message:

AsyncCompletion: Introduce range locks to prevent concurrent access to the same file range. Fixes inconsistent data for tasks with unaligned tasks where we have to use bounce buffers (i.e block table updates when a VDI file grows)

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

Legend:

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

    r26147 r26338  
    738738                }
    739739
    740                 pEpFile->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;
    741 
    742                 /* Assign the endpoint to the thread. */
    743                 rc = pdmacFileAioMgrAddEndpoint(pAioMgr, pEpFile);
    744                 if (RT_FAILURE(rc))
    745                     MMR3HeapFree(pEpFile->pTasksFreeHead);
     740                pEpFile->AioMgr.pTreeRangesLocked = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
     741                if (!pEpFile->AioMgr.pTreeRangesLocked)
     742                    rc = VERR_NO_MEMORY;
     743                else
     744                {
     745                    pEpFile->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;
     746
     747                    /* Assign the endpoint to the thread. */
     748                    rc = pdmacFileAioMgrAddEndpoint(pAioMgr, pEpFile);
     749                    if (RT_FAILURE(rc))
     750                    {
     751                        RTMemFree(pEpFile->AioMgr.pTreeRangesLocked);
     752                        MMR3HeapFree(pEpFile->pTasksFreeHead);
     753                    }
     754                }
    746755            }
    747756        }
     
    767776
    768777    return rc;
     778}
     779
     780static int pdmacFileEpRangesLockedDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
     781{
     782    AssertMsgFailed(("The locked ranges tree should be empty at that point\n"));
     783    return VINF_SUCCESS;
    769784}
    770785
     
    798813    if (pEpFile->fCaching)
    799814        pdmacFileEpCacheDestroy(pEpFile);
     815
     816    /* Destroy the locked ranges tree now. */
     817    RTAvlrFileOffsetDestroy(pEpFile->AioMgr.pTreeRangesLocked, pdmacFileEpRangesLockedDestroy, NULL);
    800818
    801819    RTFileClose(pEpFile->File);
  • trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h

    r26334 r26338  
    3434#include "PDMAsyncCompletionInternal.h"
    3535
    36 /** Enable the 2Q cache alogrithm. */
    37 #define VBOX_WITH_2Q_CACHE 1
    38 
    3936/** @todo: Revise the caching of tasks. We have currently four caches:
    4037 *  Per endpoint task cache
     
    6158/** Pointer to the global cache structure. */
    6259typedef struct PDMACFILECACHEGLOBAL *PPDMACFILECACHEGLOBAL;
     60/** Pointer to a task segment. */
     61typedef struct PDMACFILETASKSEG *PPDMACFILETASKSEG;
    6362
    6463/**
     
    189188
    190189/**
     190 * A file access range lock.
     191 */
     192typedef struct PDMACFILERANGELOCK
     193{
     194    /** AVL node in the locked range tree of the endpoint. */
     195    AVLRFOFFNODECORE            Core;
     196    /** How many tasks have locked this range. */
     197    uint32_t                    cRefs;
     198    /** Flag whether this is a read or write lock. */
     199    bool                        fReadLock;
     200    /** List of tasks which are waiting that the range gets unlocked. */
     201    PPDMACTASKFILE              pWaitingTasksHead;
     202    /** List of tasks which are waiting that the range gets unlocked. */
     203    PPDMACTASKFILE              pWaitingTasksTail;
     204} PDMACFILERANGELOCK, *PPDMACFILERANGELOCK;
     205
     206/**
    191207 * Data for one request segment waiting for cache entry.
    192208 */
     
    205221    /** Flag whether this entry writes data to the cache. */
    206222    bool                        fWrite;
    207 } PDMACFILETASKSEG, *PPDMACFILETASKSEG;
     223} PDMACFILETASKSEG;
    208224
    209225/**
     
    260276{
    261277    /** Head of the list. */
    262     PPDMACFILECACHEENTRY pHead;
     278    PPDMACFILECACHEENTRY  pHead;
    263279    /** Tail of the list. */
    264     PPDMACFILECACHEENTRY pTail;
     280    PPDMACFILECACHEENTRY  pTail;
    265281    /** Number of bytes cached in the list. */
    266     uint32_t             cbCached;
     282    uint32_t              cbCached;
    267283} PDMACFILELRULIST;
    268284
     
    278294    /** Critical section protecting the cache. */
    279295    RTCRITSECT       CritSect;
    280 #ifdef VBOX_WITH_2Q_CACHE
    281296    uint32_t         cbRecentlyUsedInMax;
    282297    uint32_t         cbRecentlyUsedOutMax;
     
    284299    PDMACFILELRULIST LruRecentlyUsedOut;
    285300    PDMACFILELRULIST LruFrequentlyUsed;
    286 #else
    287     /** Adaption parameter (p) */
    288     uint32_t         uAdaptVal;
    289     /** LRU list for recently used entries (T1) */
    290     PDMACFILELRULIST LruRecentlyUsed;
    291     /** LRU list for frequently used entries (T2) */
    292     PDMACFILELRULIST LruFrequentlyUsed;
    293     /** LRU list for recently evicted entries (B1) */
    294     PDMACFILELRULIST LruRecentlyGhost;
    295     /** LRU list for evicted entries from T2 (B2) */
    296     PDMACFILELRULIST LruFrequentlyGhost;
    297 #endif
    298301#ifdef VBOX_WITH_STATISTICS
    299302    /** Hit counter. */
     
    486489        /** Tail of pending requests. */
    487490        R3PTRTYPE(PPDMACTASKFILE)                  pReqsPendingTail;
     491        /** Tree of currently locked ranges.
     492         * If a write task is enqueued the range gets locked and any other
     493         * task writing to that range has to wait until the task completes.
     494         */
     495        PAVLRFOFFTREE                              pTreeRangesLocked;
    488496        /** Number of requests currently being processed for this endpoint
    489497         * (excluded flush requests). */
     
    527535typedef struct PDMACTASKFILE
    528536{
    529     /** next task in the list. */
     537    /** Pointer to the range lock we are waiting for */
     538    PPDMACFILERANGELOCK                  pRangeLock;
     539    /** Next task in the list. (Depending on the state) */
    530540    struct PDMACTASKFILE                *pNext;
    531541    /** Endpoint */
  • trunk/src/VBox/VMM/PDMAsyncCompletionFileNormal.cpp

    r26147 r26338  
    3636#define PDMACEPFILEMGR_REQS_MAX 512 /* @todo: Find better solution wrt. the request number*/
    3737
     38/*******************************************************************************
     39*   Internal functions                                                         *
     40*******************************************************************************/
     41static int pdmacFileAioMgrNormalProcessTaskList(PPDMACTASKFILE pTaskHead,
     42                                                PPDMACEPFILEMGR pAioMgr,
     43                                                PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint);
     44
     45
    3846int pdmacFileAioMgrNormalInit(PPDMACEPFILEMGR pAioMgr)
    3947{
     
    399407}
    400408
     409/**
     410 * Allocates a async I/O request.
     411 *
     412 * @returns Handle to the request.
     413 * @param   pAioMgr    The I/O manager.
     414 */
     415static RTFILEAIOREQ pdmacFileAioMgrNormalRequestAlloc(PPDMACEPFILEMGR pAioMgr)
     416{
     417    RTFILEAIOREQ hReq = NIL_RTFILEAIOREQ;
     418
     419    /* Get a request handle. */
     420    if (pAioMgr->iFreeReqNext != pAioMgr->iFreeEntryNext)
     421    {
     422        hReq = pAioMgr->pahReqsFree[pAioMgr->iFreeReqNext];
     423        pAioMgr->pahReqsFree[pAioMgr->iFreeReqNext] = NIL_RTFILEAIOREQ;
     424        pAioMgr->iFreeReqNext = (pAioMgr->iFreeReqNext + 1) % pAioMgr->cReqEntries;
     425    }
     426    else
     427    {
     428        int rc = RTFileAioReqCreate(&hReq);
     429        AssertRC(rc);
     430    }
     431
     432    return hReq;
     433}
     434
     435static bool pdmacFileAioMgrNormalIsRangeLocked(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
     436                                               RTFOFF offStart, size_t cbRange,
     437                                               PPDMACTASKFILE pTask)
     438{
     439    PPDMACFILERANGELOCK pRangeLock = NULL; /** < Range lock */
     440
     441    AssertMsg(   pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE
     442              || pTask->enmTransferType == PDMACTASKFILETRANSFER_READ,
     443                 ("Invalid task type %d\n", pTask->enmTransferType));
     444
     445    pRangeLock = (PPDMACFILERANGELOCK)RTAvlrFileOffsetGet(pEndpoint->AioMgr.pTreeRangesLocked, offStart);
     446    if (!pRangeLock)
     447    {
     448        pRangeLock = (PPDMACFILERANGELOCK)RTAvlrFileOffsetGetBestFit(pEndpoint->AioMgr.pTreeRangesLocked, offStart, true);
     449        /* Check if we intersect with the range. */
     450        if (   !pRangeLock
     451            || !(   (pRangeLock->Core.Key) <= (offStart + (RTFOFF)cbRange - 1)
     452                && (pRangeLock->Core.KeyLast) >= offStart))
     453        {
     454            pRangeLock = NULL; /* False alarm */
     455        }
     456    }
     457
     458    /* Check whether we have one of the situations explained below */
     459    if (   pRangeLock
     460#if 0 /** @todo: later. For now we will just block all requests if they interfere */
     461        && (   (pRangeLock->fReadLock && pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE)
     462            || (!pRangeLock->fReadLock)
     463#endif
     464        )
     465    {
     466        /* Add to the list. */
     467        pTask->pNext = NULL;
     468
     469        if (!pRangeLock->pWaitingTasksHead)
     470        {
     471            Assert(!pRangeLock->pWaitingTasksTail);
     472            pRangeLock->pWaitingTasksHead = pTask;
     473            pRangeLock->pWaitingTasksTail = pTask;
     474        }
     475        else
     476        {
     477            AssertPtr(pRangeLock->pWaitingTasksTail);
     478            pRangeLock->pWaitingTasksTail->pNext = pTask;
     479            pRangeLock->pWaitingTasksTail = pTask;
     480        }
     481        return true;
     482    }
     483
     484    return false;
     485}
     486
     487static int pdmacFileAioMgrNormalRangeLock(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
     488                                          RTFOFF offStart, size_t cbRange,
     489                                          PPDMACTASKFILE pTask)
     490{
     491    AssertMsg(!pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, offStart, cbRange, pTask),
     492              ("Range is already locked offStart=%RTfoff cbRange=%u\n",
     493               offStart, cbRange));
     494
     495    PPDMACFILERANGELOCK pRangeLock = (PPDMACFILERANGELOCK)RTMemAllocZ(sizeof(PDMACFILERANGELOCK));
     496    if (!pRangeLock)
     497        return VERR_NO_MEMORY;
     498
     499    /* Init the lock. */
     500    pRangeLock->Core.Key     = offStart;
     501    pRangeLock->Core.KeyLast = offStart + cbRange - 1;
     502    pRangeLock->cRefs        = 1;
     503    pRangeLock->fReadLock    = pTask->enmTransferType == PDMACTASKFILETRANSFER_READ;
     504
     505    bool fInserted = RTAvlrFileOffsetInsert(pEndpoint->AioMgr.pTreeRangesLocked, &pRangeLock->Core);
     506    AssertMsg(fInserted, ("Range lock was not inserted!\n"));
     507
     508    /* Let the task point to its lock. */
     509    pTask->pRangeLock = pRangeLock;
     510
     511    return VINF_SUCCESS;
     512}
     513
     514static int pdmacFileAioMgrNormalRangeLockFree(PPDMACEPFILEMGR pAioMgr,
     515                                              PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
     516                                              PPDMACFILERANGELOCK pRangeLock)
     517{
     518    PPDMACTASKFILE pTasksWaitingHead;
     519
     520    AssertPtr(pRangeLock);
     521    Assert(pRangeLock->cRefs == 1);
     522
     523    RTAvlrFileOffsetRemove(pEndpoint->AioMgr.pTreeRangesLocked, pRangeLock->Core.Key);
     524    pTasksWaitingHead = pRangeLock->pWaitingTasksHead;
     525    RTMemFree(pRangeLock);
     526
     527    return pdmacFileAioMgrNormalProcessTaskList(pTasksWaitingHead, pAioMgr, pEndpoint);
     528}
     529
     530static int pdmacFileAioMgrNormalTaskPrepare(PPDMACEPFILEMGR pAioMgr,
     531                                            PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
     532                                            PPDMACTASKFILE pTask, PRTFILEAIOREQ phReq)
     533{
     534    int rc = VINF_SUCCESS;
     535    RTFILEAIOREQ hReq = NIL_RTFILEAIOREQ;
     536    PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
     537    void *pvBuf = pTask->DataSeg.pvSeg;
     538
     539    /* Get a request handle. */
     540    hReq = pdmacFileAioMgrNormalRequestAlloc(pAioMgr);
     541    AssertMsg(hReq != NIL_RTFILEAIOREQ, ("Out of request handles\n"));
     542
     543    /*
     544     * Check if the alignment requirements are met.
     545     * Offset, transfer size and buffer address
     546     * need to be on a 512 boundary.
     547     */
     548    RTFOFF offStart = pTask->Off & ~(RTFOFF)(512-1);
     549    size_t cbToTransfer = RT_ALIGN_Z(pTask->DataSeg.cbSeg + (pTask->Off - offStart), 512);
     550    PDMACTASKFILETRANSFER enmTransferType = pTask->enmTransferType;
     551
     552    AssertMsg(   pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE
     553              || (uint64_t)(offStart + cbToTransfer) <= pEndpoint->cbFile,
     554              ("Read exceeds file size offStart=%RTfoff cbToTransfer=%d cbFile=%llu\n",
     555               offStart, cbToTransfer, pEndpoint->cbFile));
     556
     557    pTask->fPrefetch = false;
     558
     559    /*
     560     * Before we start to setup the request we have to check whether there is a task
     561     * already active which range intersects with ours. We have to defer execution
     562     * of this task in two cases:
     563     *     - The pending task is a write and the current is either read or write
     564     *     - The pending task is a read and the current task is a write task.
     565     *
     566     * To check whether a range is currently "locked" we use the AVL tree where every pending task
     567     * is stored by its file offset range. The current task will be added to the active task
     568     * and will be executed when the active one completes. (The method below
     569     * which checks whether a range is already used will add the task)
     570     *
     571     * This is neccessary because of the requirementto align all requests to a 512 boundary
     572     * which is enforced by the host OS (Linux and Windows atm). It is possible that
     573     * we have to process unaligned tasks and need to align them using bounce buffers.
     574     * While the data is feteched from the file another request might arrive writing to
     575     * the same range. This will result in data corruption if both are executed concurrently.
     576     */
     577    bool fLocked = pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, offStart, cbToTransfer, pTask);
     578
     579    if (!fLocked)
     580    {
     581        if (   RT_UNLIKELY(cbToTransfer != pTask->DataSeg.cbSeg)
     582            || RT_UNLIKELY(offStart != pTask->Off)
     583            || ((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) != (RTR3UINTPTR)pvBuf))
     584        {
     585            LogFlow(("Using bounce buffer for task %#p cbToTransfer=%zd cbSeg=%zd offStart=%RTfoff off=%RTfoff\n",
     586                     pTask, cbToTransfer, pTask->DataSeg.cbSeg, offStart, pTask->Off));
     587
     588            /* Create bounce buffer. */
     589            pTask->fBounceBuffer = true;
     590
     591            AssertMsg(pTask->Off >= offStart, ("Overflow in calculation Off=%llu offStart=%llu\n",
     592                      pTask->Off, offStart));
     593            pTask->uBounceBufOffset = pTask->Off - offStart;
     594
     595            /** @todo: I think we need something like a RTMemAllocAligned method here.
     596             * Current assumption is that the maximum alignment is 4096byte
     597             * (GPT disk on Windows)
     598             * so we can use RTMemPageAlloc here.
     599             */
     600            pTask->pvBounceBuffer = RTMemPageAlloc(cbToTransfer);
     601            if (RT_LIKELY(pTask->pvBounceBuffer))
     602            {
     603                pvBuf = pTask->pvBounceBuffer;
     604
     605                if (pTask->enmTransferType == PDMACTASKFILETRANSFER_WRITE)
     606                {
     607                    if (   RT_UNLIKELY(cbToTransfer != pTask->DataSeg.cbSeg)
     608                        || RT_UNLIKELY(offStart != pTask->Off))
     609                    {
     610                        /* We have to fill the buffer first before we can update the data. */
     611                        LogFlow(("Prefetching data for task %#p\n", pTask));
     612                        pTask->fPrefetch = true;
     613                        enmTransferType = PDMACTASKFILETRANSFER_READ;
     614                    }
     615                    else
     616                        memcpy(pvBuf, pTask->DataSeg.pvSeg, pTask->DataSeg.cbSeg);
     617                }
     618            }
     619            else
     620                rc = VERR_NO_MEMORY;
     621        }
     622        else
     623            pTask->fBounceBuffer = false;
     624
     625        if (RT_SUCCESS(rc))
     626        {
     627            AssertMsg((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) == (RTR3UINTPTR)pvBuf,
     628                      ("AIO: Alignment restrictions not met! pvBuf=%p uBitmaskAlignment=%p\n", pvBuf, pEpClassFile->uBitmaskAlignment));
     629
     630            if (enmTransferType == PDMACTASKFILETRANSFER_WRITE)
     631            {
     632                /* Grow the file if needed. */
     633                if (RT_UNLIKELY((uint64_t)(pTask->Off + pTask->DataSeg.cbSeg) > pEndpoint->cbFile))
     634                {
     635                    ASMAtomicWriteU64(&pEndpoint->cbFile, pTask->Off + pTask->DataSeg.cbSeg);
     636                    RTFileSetSize(pEndpoint->File, pTask->Off + pTask->DataSeg.cbSeg);
     637                }
     638
     639                rc = RTFileAioReqPrepareWrite(hReq, pEndpoint->File,
     640                                              offStart, pvBuf, cbToTransfer, pTask);
     641            }
     642            else
     643                rc = RTFileAioReqPrepareRead(hReq, pEndpoint->File,
     644                                             offStart, pvBuf, cbToTransfer, pTask);
     645            AssertRC(rc);
     646
     647            rc = pdmacFileAioMgrNormalRangeLock(pEndpoint, offStart, cbToTransfer, pTask);
     648
     649            if (RT_SUCCESS(rc))
     650                *phReq = hReq;
     651            else
     652            {
     653                /* Cleanup */
     654                if (pTask->fBounceBuffer)
     655                    RTMemPageFree(pTask->pvBounceBuffer);
     656            }
     657        }
     658    }
     659    else
     660    {
     661        LogFlow(("Task %#p was deferred because the access range is locked\n", pTask));
     662        rc = VINF_SUCCESS;
     663    }
     664
     665    return rc;
     666}
     667
    401668static int pdmacFileAioMgrNormalProcessTaskList(PPDMACTASKFILE pTaskHead,
    402669                                                PPDMACEPFILEMGR pAioMgr,
     
    407674    unsigned      cMaxRequests = PDMACEPFILEMGR_REQS_MAX - pAioMgr->cRequestsActive;
    408675    int           rc = VINF_SUCCESS;
    409     PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
    410676
    411677    AssertMsg(pEndpoint->enmState == PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE,
     
    439705                else
    440706                {
     707                    Assert(!pEndpoint->pFlushReq);
    441708                    pEndpoint->pFlushReq = pCurr;
    442709                }
     
    447714            {
    448715                RTFILEAIOREQ hReq = NIL_RTFILEAIOREQ;
    449                 void *pvBuf = pCurr->DataSeg.pvSeg;
    450 
    451                 /* Get a request handle. */
    452                 if (pAioMgr->iFreeReqNext != pAioMgr->iFreeEntryNext)
     716
     717                rc = pdmacFileAioMgrNormalTaskPrepare(pAioMgr, pEndpoint, pCurr, &hReq);
     718                AssertRC(rc);
     719
     720                if (hReq != NIL_RTFILEAIOREQ)
    453721                {
    454                     hReq = pAioMgr->pahReqsFree[pAioMgr->iFreeReqNext];
    455                     pAioMgr->pahReqsFree[pAioMgr->iFreeReqNext] = NIL_RTFILEAIOREQ;
    456                     pAioMgr->iFreeReqNext = (pAioMgr->iFreeReqNext + 1) % pAioMgr->cReqEntries;
    457                 }
    458                 else
    459                 {
    460                     rc = RTFileAioReqCreate(&hReq);
    461                     AssertRC(rc);
    462                 }
    463 
    464                 AssertMsg(hReq != NIL_RTFILEAIOREQ, ("Out of request handles\n"));
    465 
    466                 /* Check if the alignment requirements are met.
    467                  * Offset, transfer size and buffer address
    468                  * need to be on a 512 boundary. */
    469                 RTFOFF offStart = pCurr->Off & ~(RTFOFF)(512-1);
    470                 size_t cbToTransfer = RT_ALIGN_Z(pCurr->DataSeg.cbSeg + (pCurr->Off - offStart), 512);
    471                 PDMACTASKFILETRANSFER enmTransferType = pCurr->enmTransferType;
    472 
    473                 AssertMsg(   pCurr->enmTransferType == PDMACTASKFILETRANSFER_WRITE
    474                           || (uint64_t)(offStart + cbToTransfer) <= pEndpoint->cbFile,
    475                           ("Read exceeds file size offStart=%RTfoff cbToTransfer=%d cbFile=%llu\n",
    476                           offStart, cbToTransfer, pEndpoint->cbFile));
    477 
    478                 pCurr->fPrefetch = false;
    479 
    480                 if (   RT_UNLIKELY(cbToTransfer != pCurr->DataSeg.cbSeg)
    481                     || RT_UNLIKELY(offStart != pCurr->Off)
    482                     || ((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) != (RTR3UINTPTR)pvBuf))
    483                 {
    484                     LogFlow(("Using bounce buffer for task %#p cbToTransfer=%zd cbSeg=%zd offStart=%RTfoff off=%RTfoff\n",
    485                              pCurr, cbToTransfer, pCurr->DataSeg.cbSeg, offStart, pCurr->Off));
    486 
    487                     /* Create bounce buffer. */
    488                     pCurr->fBounceBuffer = true;
    489 
    490                     AssertMsg(pCurr->Off >= offStart, ("Overflow in calculation Off=%llu offStart=%llu\n",
    491                               pCurr->Off, offStart));
    492                     pCurr->uBounceBufOffset = pCurr->Off - offStart;
    493 
    494                     /** @todo: I think we need something like a RTMemAllocAligned method here.
    495                      * Current assumption is that the maximum alignment is 4096byte
    496                      * (GPT disk on Windows)
    497                      * so we can use RTMemPageAlloc here.
    498                      */
    499                     pCurr->pvBounceBuffer = RTMemPageAlloc(cbToTransfer);
    500                     AssertPtr(pCurr->pvBounceBuffer);
    501                     pvBuf = pCurr->pvBounceBuffer;
    502 
    503                     if (pCurr->enmTransferType == PDMACTASKFILETRANSFER_WRITE)
     722                    apReqs[cRequests] = hReq;
     723                    pEndpoint->AioMgr.cReqsProcessed++;
     724                    cMaxRequests--;
     725                    cRequests++;
     726                    if (cRequests == RT_ELEMENTS(apReqs))
    504727                    {
    505                         if (   RT_UNLIKELY(cbToTransfer != pCurr->DataSeg.cbSeg)
    506                             || RT_UNLIKELY(offStart != pCurr->Off))
    507                         {
    508                             /* We have to fill the buffer first before we can update the data. */
    509                             LogFlow(("Prefetching data for task %#p\n", pCurr));
    510                             pCurr->fPrefetch = true;
    511                             enmTransferType = PDMACTASKFILETRANSFER_READ;
    512                         }
    513                         else
    514                             memcpy(pvBuf, pCurr->DataSeg.pvSeg, pCurr->DataSeg.cbSeg);
     728                        rc = pdmacFileAioMgrNormalReqsEnqueue(pAioMgr, pEndpoint, apReqs, cRequests);
     729                        cRequests = 0;
     730                        AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
     731                                  ("Unexpected return code\n"));
    515732                    }
    516                 }
    517                 else
    518                     pCurr->fBounceBuffer = false;
    519 
    520                 AssertMsg((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) == (RTR3UINTPTR)pvBuf,
    521                           ("AIO: Alignment restrictions not met! pvBuf=%p uBitmaskAlignment=%p\n", pvBuf, pEpClassFile->uBitmaskAlignment));
    522 
    523                 if (enmTransferType == PDMACTASKFILETRANSFER_WRITE)
    524                 {
    525                     /* Grow the file if needed. */
    526                     if (RT_UNLIKELY((uint64_t)(pCurr->Off + pCurr->DataSeg.cbSeg) > pEndpoint->cbFile))
    527                     {
    528                         ASMAtomicWriteU64(&pEndpoint->cbFile, pCurr->Off + pCurr->DataSeg.cbSeg);
    529                         RTFileSetSize(pEndpoint->File, pCurr->Off + pCurr->DataSeg.cbSeg);
    530                     }
    531 
    532                     rc = RTFileAioReqPrepareWrite(hReq, pEndpoint->File,
    533                                                   offStart, pvBuf, cbToTransfer, pCurr);
    534                 }
    535                 else
    536                     rc = RTFileAioReqPrepareRead(hReq, pEndpoint->File,
    537                                                  offStart, pvBuf, cbToTransfer, pCurr);
    538                 AssertRC(rc);
    539 
    540                 apReqs[cRequests] = hReq;
    541                 pEndpoint->AioMgr.cReqsProcessed++;
    542                 cMaxRequests--;
    543                 cRequests++;
    544                 if (cRequests == RT_ELEMENTS(apReqs))
    545                 {
    546                     rc = pdmacFileAioMgrNormalReqsEnqueue(pAioMgr, pEndpoint, apReqs, cRequests);
    547                     cRequests = 0;
    548                     AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES),
    549                               ("Unexpected return code\n"));
    550733                }
    551734                break;
     
    9681151                            pEndpoint->AioMgr.cReqsProcessed++;
    9691152
     1153                            /* Free the lock and process pending tasks if neccessary */
     1154                            pdmacFileAioMgrNormalRangeLockFree(pAioMgr, pEndpoint, pTask->pRangeLock);
     1155
    9701156                            /* Call completion callback */
    9711157                            pTask->pfnCompleted(pTask, pTask->pvUser);
  • trunk/src/VBox/VMM/testcase/tstPDMAsyncCompletionStress.cpp

    r26240 r26338  
    4949#include <iprt/thread.h>
    5050#include <iprt/param.h>
     51#include <iprt/message.h>
    5152
    5253#define TESTCASE "tstPDMAsyncCompletionStress"
     
    179180
    180181        if (memcmp(pbBuf, pbTestPattern, cbCompare))
    181             AssertMsgFailed(("Unexpected data for off=%RTfoff size=%u\n", pTestTask->off, pTestTask->DataSeg.cbSeg));
     182        {
     183            unsigned idx = 0;
     184
     185            while (   (pbBuf[idx] == pbTestPattern[idx])
     186                   && (idx < cbCompare))
     187                idx++;
     188
     189            RTMsgError("Unexpected data for off=%RTfoff size=%u\n"
     190                       "Expected %c got %c\n",
     191                       pTestTask->off + idx, pTestTask->DataSeg.cbSeg,
     192                       pbTestPattern[idx], pbBuf[idx]);
     193            RTAssertDebugBreak();
     194        }
    182195
    183196        pbBuf  += cbCompare;
     
    315328    int uRnd = RTRandU32Ex(0, 100);
    316329
    317     return (uRnd < iPercentage); /* This should be enough for our purpose */
     330    return (uRnd <= iPercentage); /* This should be enough for our purpose */
    318331}
    319332
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