VirtualBox

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


Ignore:
Timestamp:
Jun 1, 2009 8:25:54 PM (16 years ago)
Author:
vboxsync
Message:

First part of the PDMAsyncCompletion rewrite:

  • The Host specific parts in VMM are deleted (moved into Runtime)
  • Implemented a incomplete manager for file operations:
    • A slightly tested failsafe method to do operations is implemented using the synchronous RTFile* API. The failsafe method will be always used if the host has no support for async I/O or something bad happens during the operation reducing the risk of VM termination
  • Changed the testcase and drivers to use the new API
  • Removed the now obsolete async transport driver
  • Removed the obsolete raw async image driver
  • Removed the fault injection driver (useless from the beginning)
Location:
trunk/src/VBox/Devices/Storage
Files:
2 edited

Legend:

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

    r18778 r20167  
    2727#include <VBox/VBoxHDD.h>
    2828#include <VBox/pdmdrv.h>
     29#include <VBox/pdmasynccompletion.h>
    2930#include <iprt/alloc.h>
    3031#include <iprt/assert.h>
     
    3435#include <iprt/cache.h>
    3536#include <iprt/tcp.h>
     37#include <iprt/semaphore.h>
    3638
    3739#ifdef VBOX_WITH_INIP
     
    7274    ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) )
    7375
    74 /** Converts a pointer to VBOXDISK::ITransportAsyncPort to a PVBOXDISK. */
    75 #define PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface) \
    76     ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, ITransportAsyncPort)) )
    77 
    78 /**
    79  * Structure for an async I/O task.
    80  */
    81 typedef struct DRVVDASYNCTASK
    82 {
    83     /** Callback which is called on completion. */
    84     PFNVDCOMPLETED pfnCompleted;
    85     /** Opqaue user data which is passed on completion. */
    86     void           *pvUser;
    87     /** Opaque user data the caller passed on transfer initiation. */
    88     void           *pvUserCaller;
    89 } DRVVDASYNCTASK, *PDRVVDASYNCTASK;
    90 
    9176/**
    9277 * VBox disk container, image information, private part.
     
    10287    VDINTERFACE        VDIConfig;
    10388} VBOXIMAGE, *PVBOXIMAGE;
     89
     90/**
     91 * Storage backend data.
     92 */
     93typedef struct DRVVDSTORAGEBACKEND
     94{
     95    /** PDM async completion end point. */
     96    PPDMASYNCCOMPLETIONENDPOINT pEndpoint;
     97    /** The template. */
     98    PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
     99    /** Event semaphore for synchronous operations. */
     100    RTSEMEVENT                  EventSem;
     101    /** Flag whether a synchronous operation is currently pending. */
     102    volatile bool               fSyncIoPending;
     103    /** Callback routine */
     104    PFNVDCOMPLETED              pfnCompleted;
     105} DRVVDSTORAGEBACKEND, *PDRVVDSTORAGEBACKEND;
    104106
    105107/**
     
    140142    /** The async media port interface above. */
    141143    PPDMIMEDIAASYNCPORT      pDrvMediaAsyncPort;
    142     /** Pointer to the asynchronous media driver below. */
    143     PPDMITRANSPORTASYNC      pDrvTransportAsync;
    144     /** Async transport port interface. */
    145     PDMITRANSPORTASYNCPORT   ITransportAsyncPort;
    146     /** Our cache to reduce allocation overhead. */
    147     PRTOBJCACHE              pCache;
    148144    /** Pointer to the list of data we need to keep per image. */
    149145    PVBOXIMAGE               pImages;
     
    207203*******************************************************************************/
    208204
    209 static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation, bool fReadonly, void **ppStorage)
     205static DECLCALLBACK(void) drvvdAsyncTaskCompleted(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser)
     206{
     207    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     208    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pvTemplateUser;
     209    int rc = VINF_VD_ASYNC_IO_FINISHED;
     210    void *pvCallerUser = NULL;
     211
     212    if (pStorageBackend->fSyncIoPending)
     213    {
     214        pStorageBackend->fSyncIoPending;
     215        RTSemEventSignal(pStorageBackend->EventSem);
     216    }
     217    else if (pStorageBackend->pfnCompleted)
     218        rc = pStorageBackend->pfnCompleted(pvUser, &pvCallerUser);
     219    else
     220        pvCallerUser = pvUser;
     221
     222    if (rc == VINF_VD_ASYNC_IO_FINISHED)
     223    {
     224        rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvCallerUser);
     225        AssertRC(rc);
     226    }
     227    else
     228        AssertMsg(rc == VERR_VD_ASYNC_IO_IN_PROGRESS, ("Invalid return code from disk backend rc=%Rrc\n", rc));
     229}
     230
     231static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation, bool fReadonly,
     232                                          PFNVDCOMPLETED pfnCompleted, void **ppStorage)
    210233{
    211234    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    212 
    213     return pDrvVD->pDrvTransportAsync->pfnOpen(pDrvVD->pDrvTransportAsync, pszLocation, fReadonly, ppStorage);
     235    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)RTMemAllocZ(sizeof(DRVVDSTORAGEBACKEND));
     236    int rc = VINF_SUCCESS;
     237
     238    if (pStorageBackend)
     239    {
     240        pStorageBackend->fSyncIoPending = false;
     241        pStorageBackend->pfnCompleted   = pfnCompleted;
     242
     243        int rc = RTSemEventCreate(&pStorageBackend->EventSem);
     244        if (RT_SUCCESS(rc))
     245        {
     246            rc = PDMDrvHlpPDMAsyncCompletionTemplateCreate(pDrvVD->pDrvIns, &pStorageBackend->pTemplate,
     247                                                           drvvdAsyncTaskCompleted, pStorageBackend, "AsyncTaskCompleted");
     248            if (RT_SUCCESS(rc))
     249            {
     250                rc = PDMR3AsyncCompletionEpCreateForFile(&pStorageBackend->pEndpoint, pszLocation,
     251                                                         fReadonly
     252                                                         ? PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING
     253                                                         : PDMACEP_FILE_FLAGS_CACHING,
     254                                                         pStorageBackend->pTemplate);
     255                if (RT_SUCCESS(rc))
     256                {
     257                    *ppStorage = pStorageBackend;
     258                    return VINF_SUCCESS;
     259                }
     260
     261                PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
     262            }
     263            RTSemEventDestroy(pStorageBackend->EventSem);
     264        }
     265        RTMemFree(pStorageBackend);
     266    }
     267    else
     268        rc = VERR_NO_MEMORY;
     269
     270    return rc;
    214271}
    215272
     
    217274{
    218275    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    219 
    220     AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
    221 
    222    return pDrvVD->pDrvTransportAsync->pfnClose(pDrvVD->pDrvTransportAsync, pStorage);
    223 }
    224 
    225 static DECLCALLBACK(int) drvvdAsyncIORead(void *pvUser, void *pStorage, uint64_t uOffset,
    226                                           size_t cbRead, void *pvBuf, size_t *pcbRead)
     276    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     277
     278    PDMR3AsyncCompletionEpClose(pStorageBackend->pEndpoint);
     279    PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
     280    RTSemEventDestroy(pStorageBackend->EventSem);
     281    RTMemFree(pStorageBackend);
     282
     283    return VINF_SUCCESS;;
     284}
     285
     286static DECLCALLBACK(int) drvvdAsyncIOGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
    227287{
    228288    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    229 
    230     AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
    231 
    232     return pDrvVD->pDrvTransportAsync->pfnReadSynchronous(pDrvVD->pDrvTransportAsync,
    233                                                           pStorage,
    234                                                           uOffset, pvBuf, cbRead, pcbRead);
    235 }
    236 
    237 static DECLCALLBACK(int) drvvdAsyncIOWrite(void *pvUser, void *pStorage, uint64_t uOffset,
    238                                            size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
     289    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     290
     291    return PDMR3AsyncCompletionEpGetSize(pStorageBackend->pEndpoint, pcbSize);
     292}
     293
     294static DECLCALLBACK(int) drvvdAsyncIOReadSync(void *pvUser, void *pStorage, uint64_t uOffset,
     295                                              size_t cbRead, void *pvBuf, size_t *pcbRead)
    239296{
    240297    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    241 
    242     AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
    243 
    244     return pDrvVD->pDrvTransportAsync->pfnWriteSynchronous(pDrvVD->pDrvTransportAsync,
    245                                                            pStorage,
    246                                                            uOffset, pvBuf, cbWrite, pcbWritten);
    247 }
    248 
    249 static DECLCALLBACK(int) drvvdAsyncIOFlush(void *pvUser, void *pStorage)
    250 {
    251     PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    252 
    253     AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
    254 
    255     return pDrvVD->pDrvTransportAsync->pfnFlushSynchronous(pDrvVD->pDrvTransportAsync, pStorage);
    256 }
    257 
    258 static DECLCALLBACK(int) drvvdAsyncIOPrepareRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbRead, void **ppTask)
    259 {
    260     PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    261 
    262     AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
    263 
    264     return pDrvVD->pDrvTransportAsync->pfnPrepareRead(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbRead, ppTask);
    265 }
    266 
    267 static DECLCALLBACK(int) drvvdAsyncIOPrepareWrite(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbWrite, void **ppTask)
    268 {
    269     PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    270 
    271     AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
    272 
    273     return pDrvVD->pDrvTransportAsync->pfnPrepareWrite(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbWrite, ppTask);
    274 }
    275 
    276 static DECLCALLBACK(int) drvvdAsyncIOTasksSubmit(void *pvUser, void *apTasks[], unsigned cTasks, void *pvUser2,
    277                                                  void *pvUserCaller, PFNVDCOMPLETED pfnTasksCompleted)
    278 {
    279     PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
    280     PDRVVDASYNCTASK pDrvVDAsyncTask;
    281     int rc;
    282 
    283     AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
    284 
    285     rc = RTCacheRequest(pDrvVD->pCache, (void **)&pDrvVDAsyncTask);
    286 
     298    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     299    PDMDATASEG DataSeg;
     300    PPDMASYNCCOMPLETIONTASK pTask;
     301
     302    Assert(!pStorageBackend->fSyncIoPending);
     303    pStorageBackend->fSyncIoPending = true;
     304    DataSeg.cbSeg = cbRead;
     305    DataSeg.pvSeg = pvBuf;
     306
     307    int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbRead, NULL, &pTask);
    287308    if (RT_FAILURE(rc))
    288309        return rc;
    289310
    290     pDrvVDAsyncTask->pfnCompleted = pfnTasksCompleted;
    291     pDrvVDAsyncTask->pvUser       = pvUser2;
    292     pDrvVDAsyncTask->pvUserCaller = pvUserCaller;
    293 
    294     return pDrvVD->pDrvTransportAsync->pfnTasksSubmit(pDrvVD->pDrvTransportAsync, apTasks, cTasks, pDrvVDAsyncTask);
    295 }
     311    /* Wait */
     312    rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
     313    AssertRC(rc);
     314
     315    if (pcbRead)
     316        *pcbRead = cbRead;
     317
     318    return VINF_SUCCESS;
     319}
     320
     321static DECLCALLBACK(int) drvvdAsyncIOWriteSync(void *pvUser, void *pStorage, uint64_t uOffset,
     322                                               size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
     323{
     324    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     325    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     326    PDMDATASEG DataSeg;
     327    PPDMASYNCCOMPLETIONTASK pTask;
     328
     329    Assert(!pStorageBackend->fSyncIoPending);
     330    pStorageBackend->fSyncIoPending = true;
     331    DataSeg.cbSeg = cbWrite;
     332    DataSeg.pvSeg = (void *)pvBuf;
     333
     334    int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbWrite, NULL, &pTask);
     335    if (RT_FAILURE(rc))
     336        return rc;
     337
     338    /* Wait */
     339    rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
     340    AssertRC(rc);
     341
     342    if (pcbWritten)
     343        *pcbWritten = cbWrite;
     344
     345    return VINF_SUCCESS;
     346}
     347
     348static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage)
     349{
     350    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     351    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     352    PPDMASYNCCOMPLETIONTASK pTask;
     353
     354    Assert(!pStorageBackend->fSyncIoPending);
     355    pStorageBackend->fSyncIoPending = true;
     356
     357    int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, NULL, &pTask);
     358    if (RT_FAILURE(rc))
     359        return rc;
     360
     361    /* Wait */
     362    rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
     363    AssertRC(rc);
     364
     365    return VINF_SUCCESS;
     366}
     367
     368static DECLCALLBACK(int) drvvdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset,
     369                                               PCPDMDATASEG paSegments, size_t cSegments,
     370                                               size_t cbRead, void *pvCompletion,
     371                                               void **ppTask)
     372{
     373    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     374    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     375
     376    return PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbRead,
     377                                      pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
     378}
     379
     380static DECLCALLBACK(int) drvvdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset,
     381                                                PCPDMDATASEG paSegments, size_t cSegments,
     382                                                size_t cbWrite, void *pvCompletion,
     383                                                void **ppTask)
     384{
     385    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     386    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     387
     388    return PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbWrite,
     389                                       pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
     390}
     391
     392static DECLCALLBACK(int) drvvdAsyncIOFlushAsync(void *pvUser, void *pStorage,
     393                                                void *pvCompletion, void **ppTask)
     394{
     395    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     396    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
     397
     398    return PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, pvCompletion,
     399                                       (PPPDMASYNCCOMPLETIONTASK)ppTask);
     400}
     401
    296402
    297403/*******************************************************************************
     
    641747*******************************************************************************/
    642748
    643 static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMITRANSPORTASYNCPORT pInterface, void *pvUser)
    644 {
    645     PVBOXDISK pThis = PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface);
    646     PDRVVDASYNCTASK pDrvVDAsyncTask = (PDRVVDASYNCTASK)pvUser;
    647     int rc = VINF_VD_ASYNC_IO_FINISHED;
    648 
    649     /* Having a completion callback for a task is not mandatory. */
    650     if (pDrvVDAsyncTask->pfnCompleted)
    651         rc = pDrvVDAsyncTask->pfnCompleted(pDrvVDAsyncTask->pvUser);
    652 
    653     /* Check if the request is finished. */
    654     if (rc == VINF_VD_ASYNC_IO_FINISHED)
    655     {
    656         rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pDrvVDAsyncTask->pvUserCaller);
    657     }
    658     else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
    659         rc = VINF_SUCCESS;
    660 
    661     rc = RTCacheInsert(pThis->pCache, pDrvVDAsyncTask);
    662     AssertRC(rc);
    663 
    664     return rc;
     749static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMDRVINS pDrvIns, void *pvUser)
     750{
     751    return VERR_NOT_IMPLEMENTED;
    665752}
    666753
     
    684771        case PDMINTERFACE_MEDIA_ASYNC:
    685772            return pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL;
    686         case PDMINTERFACE_TRANSPORT_ASYNC_PORT:
    687             return &pThis->ITransportAsyncPort;
    688773        default:
    689774            return NULL;
     
    743828    pThis->IMediaAsync.pfnStartWrite      = drvvdStartWrite;
    744829
    745     /* ITransportAsyncPort */
    746     pThis->ITransportAsyncPort.pfnTaskCompleteNotify  = drvvdTasksCompleteNotify;
    747 
    748830    /* Initialize supported VD interfaces. */
    749831    pThis->pVDIfsDisk = NULL;
     
    761843    pThis->VDIAsyncIOCallbacks.pfnOpen                 = drvvdAsyncIOOpen;
    762844    pThis->VDIAsyncIOCallbacks.pfnClose                = drvvdAsyncIOClose;
    763     pThis->VDIAsyncIOCallbacks.pfnRead                 = drvvdAsyncIORead;
    764     pThis->VDIAsyncIOCallbacks.pfnWrite                = drvvdAsyncIOWrite;
    765     pThis->VDIAsyncIOCallbacks.pfnFlush                = drvvdAsyncIOFlush;
    766     pThis->VDIAsyncIOCallbacks.pfnPrepareRead          = drvvdAsyncIOPrepareRead;
    767     pThis->VDIAsyncIOCallbacks.pfnPrepareWrite         = drvvdAsyncIOPrepareWrite;
    768     pThis->VDIAsyncIOCallbacks.pfnTasksSubmit          = drvvdAsyncIOTasksSubmit;
     845    pThis->VDIAsyncIOCallbacks.pfnGetSize              = drvvdAsyncIOGetSize;
     846    pThis->VDIAsyncIOCallbacks.pfnReadSync             = drvvdAsyncIOReadSync;
     847    pThis->VDIAsyncIOCallbacks.pfnWriteSync            = drvvdAsyncIOWriteSync;
     848    pThis->VDIAsyncIOCallbacks.pfnFlushSync            = drvvdAsyncIOFlushSync;
     849    pThis->VDIAsyncIOCallbacks.pfnReadAsync            = drvvdAsyncIOReadAsync;
     850    pThis->VDIAsyncIOCallbacks.pfnWriteAsync           = drvvdAsyncIOWriteAsync;
     851    pThis->VDIAsyncIOCallbacks.pfnFlushAsync           = drvvdAsyncIOFlushAsync;
    769852
    770853    rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
     
    820903            pThis->fAsyncIOSupported = true;
    821904
    822             /* Success query the async transport interface. */
    823             pThis->pDrvTransportAsync = (PPDMITRANSPORTASYNC)pBase->pfnQueryInterface(pBase, PDMINTERFACE_TRANSPORT_ASYNC);
    824             if (!pThis->pDrvTransportAsync)
    825             {
    826                 /* An attached driver without an async transport interface - impossible. */
    827                 AssertMsgFailed(("Configuration error: No async transport interface below!\n"));
    828                 return VERR_PDM_MISSING_INTERFACE_ABOVE;
    829             }
     905            /** @todo: Use PDM async completion manager */
    830906        }
    831907    }
     
    11081184        }
    11091185
    1110         /*
    1111          * We know definitly if async I/O is supported now.
    1112          * Create cache if it is supported.
    1113          */
    1114         if (pThis->fAsyncIOSupported)
    1115         {
    1116             rc = RTCacheCreate(&pThis->pCache, 0, sizeof(DRVVDASYNCTASK), RTOBJCACHE_PROTECT_INSERT);
    1117             AssertMsgRC(rc, ("Failed to create cache rc=%Rrc\n", rc));
    1118         }
    1119 
    11201186        /* Switch to runtime error facility. */
    11211187        pThis->fErrorUseRuntime = true;
     
    11411207
    11421208    drvvdFreeImages(pThis);
    1143     if (pThis->pCache)
    1144     {
    1145         rc = RTCacheDestroy(pThis->pCache);
    1146         AssertRC(rc);
    1147     }
    11481209}
    11491210
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r19921 r20167  
    432432    PVDINTERFACEASYNCIO pInterfaceAsyncIOCallbacks;
    433433    /**
    434      * Pointer to an array of task handles for task submission.
     434     * Pointer to an array of segment entries for async I/O.
    435435     * This is an optimization because the task number to submit is not known
    436436     * and allocating/freeing an array in the read/write functions every time
    437437     * is too expensive.
    438438     */
    439     void            **apTask;
    440     /** Entries available in the task handle array. */
    441     unsigned        cTask;
     439    PPDMDATASEG     paSegments;
     440    /** Entries available in the segments array. */
     441    unsigned        cSegments;
    442442
    443443    /** Open flags passed by VBoxHD layer. */
     
    584584                                                           ? true
    585585                                                           : false,
     586                                                         NULL,
    586587                                                         &pVmdkFile->pStorage);
    587588        pVmdkFile->fAsyncIO = true;
     
    670671
    671672    if (pVmdkFile->fAsyncIO)
    672         return pImage->pInterfaceAsyncIOCallbacks->pfnRead(pImage->pInterfaceAsyncIO->pvUser,
    673                                                            pVmdkFile->pStorage, uOffset,
    674                                                            cbToRead, pvBuf, pcbRead);
     673        return pImage->pInterfaceAsyncIOCallbacks->pfnReadSync(pImage->pInterfaceAsyncIO->pvUser,
     674                                                               pVmdkFile->pStorage, uOffset,
     675                                                               cbToRead, pvBuf, pcbRead);
    675676    else
    676677        return RTFileReadAt(pVmdkFile->File, uOffset, pvBuf, cbToRead, pcbRead);
     
    687688
    688689    if (pVmdkFile->fAsyncIO)
    689         return pImage->pInterfaceAsyncIOCallbacks->pfnWrite(pImage->pInterfaceAsyncIO->pvUser,
    690                                                             pVmdkFile->pStorage, uOffset,
    691                                                             cbToWrite, pvBuf, pcbWritten);
     690        return pImage->pInterfaceAsyncIOCallbacks->pfnWriteSync(pImage->pInterfaceAsyncIO->pvUser,
     691                                                                pVmdkFile->pStorage, uOffset,
     692                                                                cbToWrite, pvBuf, pcbWritten);
    692693    else
    693694        return RTFileWriteAt(pVmdkFile->File, uOffset, pvBuf, cbToWrite, pcbWritten);
     
    730731
    731732    if (pVmdkFile->fAsyncIO)
    732         return pImage->pInterfaceAsyncIOCallbacks->pfnFlush(pImage->pInterfaceAsyncIO->pvUser,
    733                                                             pVmdkFile->pStorage);
     733        return pImage->pInterfaceAsyncIOCallbacks->pfnFlushSync(pImage->pInterfaceAsyncIO->pvUser,
     734                                                                pVmdkFile->pStorage);
    734735    else
    735736        return RTFileFlush(pVmdkFile->File);
     
    57405741    PVMDKEXTENT pExtent;
    57415742    int rc = VINF_SUCCESS;
    5742     unsigned cTasksToSubmit = 0;
     5743    unsigned cSegments = 0;
    57435744    PPDMDATASEG paSegCurrent = paSeg;
    57445745    size_t cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     
    57735774        }
    57745775
    5775         /* Clip read range to remain in this extent. */
     5776        /* Clip write range to remain in this extent. */
    57765777        cbToRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    5777         /* Clip read range to remain into current data segment. */
     5778        /* Clip write range to remain into current data segment. */
    57785779        cbToRead = RT_MIN(cbToRead, cbLeftInCurrentSegment);
    57795780
     
    57835784            case VMDKETYPE_FLAT:
    57845785            {
    5785                 /* Setup new task. */
    5786                 void *pTask;
    5787                 rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareRead(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage,
    5788                                                                         VMDK_SECTOR2BYTE(uSectorExtentRel),
    5789                                                                         (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment,
    5790                                                                         cbToRead, &pTask);
    5791                 if (RT_FAILURE(rc))
    5792                 {
    5793                     AssertMsgFailed(("Preparing read failed rc=%Rrc\n", rc));
    5794                     goto out;
    5795                 }
    5796 
    57975786                /* Check for enough room first. */
    5798                 if (cTasksToSubmit >= pImage->cTask)
     5787                if (RT_LIKELY(cSegments >= pImage->cSegments))
    57995788                {
    58005789                    /* We reached maximum, resize array. Try to realloc memory first. */
    5801                     void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *));
    5802 
    5803                     if (!apTaskNew)
     5790                    PPDMDATASEG paSegmentsNew = (PPDMDATASEG)RTMemRealloc(pImage->paSegments, (cSegments + 10)*sizeof(PDMDATASEG));
     5791
     5792                    if (!paSegmentsNew)
    58045793                    {
    58055794                        /* We failed. Allocate completely new. */
    5806                         apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *));
    5807                         if (!apTaskNew)
     5795                        paSegmentsNew = (PPDMDATASEG)RTMemAllocZ((cSegments + 10)* sizeof(PDMDATASEG));
     5796                        if (!paSegmentsNew)
    58085797                        {
    58095798                            /* Damn, we are out of memory. */
     
    58135802
    58145803                        /* Copy task handles over. */
    5815                         for (unsigned i = 0; i < cTasksToSubmit; i++)
    5816                             apTaskNew[i] = pImage->apTask[i];
     5804                        for (unsigned i = 0; i < cSegments; i++)
     5805                            paSegmentsNew[i] = pImage->paSegments[i];
    58175806
    58185807                        /* Free old memory. */
    5819                         RTMemFree(pImage->apTask);
     5808                        RTMemFree(pImage->paSegments);
    58205809                    }
    58215810
    5822                     pImage->cTask = cTasksToSubmit + 10;
    5823                     pImage->apTask = apTaskNew;
     5811                    pImage->cSegments = cSegments + 10;
     5812                    pImage->paSegments = paSegmentsNew;
    58245813                }
    58255814
    5826                 pImage->apTask[cTasksToSubmit] = pTask;
    5827                 cTasksToSubmit++;
    5828                 break;
    5829             }
    5830             case VMDKETYPE_ZERO:
    5831                 memset((uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 0, cbToRead);
    5832                 break;
    5833             default:
    5834                 AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType));
    5835         }
    5836 
    5837         cbRead -= cbToRead;
    5838         uOffset += cbToRead;
    5839         cbLeftInCurrentSegment -= cbToRead;
    5840         uOffsetInCurrentSegment += cbToRead;
    5841         /* Go to next extent if there is no space left in current one. */
    5842         if (!cbLeftInCurrentSegment)
    5843         {
    5844             uOffsetInCurrentSegment = 0;
    5845             paSegCurrent++;
    5846             cSeg--;
    5847             cbLeftInCurrentSegment = paSegCurrent->cbSeg;
    5848         }
    5849     }
    5850 
    5851     AssertMsg(cbRead == 0, ("No segment left but there is still data to read\n"));
    5852 
    5853     if (cTasksToSubmit == 0)
    5854     {
    5855         /* The request was completely in a ZERO extent nothing to do. */
    5856         rc = VINF_VD_ASYNC_IO_FINISHED;
    5857     }
    5858     else
    5859     {
    5860         /* Submit tasks. */
    5861         rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser,
    5862                                                                 pImage->apTask, cTasksToSubmit,
    5863                                                                 NULL, pvUser,
    5864                                                                 NULL /* Nothing required after read. */);
    5865         AssertMsgRC(rc, ("Failed to enqueue tasks rc=%Rrc\n", rc));
    5866     }
    5867 
    5868 out:
    5869     LogFlowFunc(("returns %Rrc\n", rc));
    5870     return rc;
    5871 }
    5872 
    5873 static int vmdkAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
    5874                           PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
    5875 {
    5876     PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
    5877     PVMDKEXTENT pExtent;
    5878     int rc = VINF_SUCCESS;
    5879     unsigned cTasksToSubmit = 0;
    5880     PPDMDATASEG paSegCurrent = paSeg;
    5881     size_t cbLeftInCurrentSegment = paSegCurrent->cbSeg;
    5882     size_t uOffsetInCurrentSegment = 0;
    5883 
    5884     AssertPtr(pImage);
    5885     Assert(uOffset % 512 == 0);
    5886     Assert(cbWrite % 512 == 0);
    5887 
    5888     if (   uOffset + cbWrite > pImage->cbSize
    5889         || cbWrite == 0)
    5890     {
    5891         rc = VERR_INVALID_PARAMETER;
    5892         goto out;
    5893     }
    5894 
    5895     while (cbWrite && cSeg)
    5896     {
    5897         size_t cbToWrite;
    5898         uint64_t uSectorExtentRel;
    5899 
    5900         rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
    5901                             &pExtent, &uSectorExtentRel);
    5902         if (RT_FAILURE(rc))
    5903             goto out;
    5904 
    5905         /* Check access permissions as defined in the extent descriptor. */
    5906         if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
    5907         {
    5908             rc = VERR_VD_VMDK_INVALID_STATE;
    5909             goto out;
    5910         }
    5911 
    5912         /* Clip write range to remain in this extent. */
    5913         cbToWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    5914         /* Clip write range to remain into current data segment. */
    5915         cbToWrite = RT_MIN(cbToWrite, cbLeftInCurrentSegment);
    5916 
    5917         switch (pExtent->enmType)
    5918         {
    5919             case VMDKETYPE_VMFS:
    5920             case VMDKETYPE_FLAT:
    5921             {
    5922                 /* Setup new task. */
    5923                 void *pTask;
    5924                 rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareWrite(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage,
    5925                                                                          VMDK_SECTOR2BYTE(uSectorExtentRel),
    5926                                                                          (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment,
    5927                                                                          cbToWrite, &pTask);
    5928                 if (RT_FAILURE(rc))
    5929                 {
    5930                     AssertMsgFailed(("Preparing read failed rc=%Rrc\n", rc));
    5931                     goto out;
    5932                 }
    5933 
    5934                 /* Check for enough room first. */
    5935                 if (cTasksToSubmit >= pImage->cTask)
    5936                 {
    5937                     /* We reached maximum, resize array. Try to realloc memory first. */
    5938                     void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *));
    5939 
    5940                     if (!apTaskNew)
    5941                     {
    5942                         /* We failed. Allocate completely new. */
    5943                         apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *));
    5944                         if (!apTaskNew)
    5945                         {
    5946                             /* Damn, we are out of memory. */
    5947                             rc = VERR_NO_MEMORY;
    5948                             goto out;
    5949                         }
    5950 
    5951                         /* Copy task handles over. */
    5952                         for (unsigned i = 0; i < cTasksToSubmit; i++)
    5953                             apTaskNew[i] = pImage->apTask[i];
    5954 
    5955                         /* Free old memory. */
    5956                         RTMemFree(pImage->apTask);
    5957                     }
    5958 
    5959                     pImage->cTask = cTasksToSubmit + 10;
    5960                     pImage->apTask = apTaskNew;
    5961                 }
    5962 
    5963                 pImage->apTask[cTasksToSubmit] = pTask;
    5964                 cTasksToSubmit++;
     5815                pImage->paSegments[cSegments].cbSeg = cbToRead;
     5816                pImage->paSegments[cSegments].pvSeg = (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment;
     5817                cSegments++;
    59655818                break;
    59665819            }
     
    59725825        }
    59735826
     5827        cbRead -= cbToRead;
     5828        uOffset += cbToRead;
     5829        cbLeftInCurrentSegment -= cbToRead;
     5830        uOffsetInCurrentSegment += cbToRead;
     5831        /* Go to next extent if there is no space left in current one. */
     5832        if (!cbLeftInCurrentSegment)
     5833        {
     5834            uOffsetInCurrentSegment = 0;
     5835            paSegCurrent++;
     5836            cSeg--;
     5837            cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     5838        }
     5839    }
     5840
     5841    AssertMsg(cbRead == 0, ("No segment left but there is still data to write\n"));
     5842
     5843    if (cSegments == 0)
     5844    {
     5845        /* The request was completely in a ZERO extent nothing to do. */
     5846        rc = VINF_VD_ASYNC_IO_FINISHED;
     5847    }
     5848    else
     5849    {
     5850        /* Start the write */
     5851        void *pTask;
     5852        rc = pImage->pInterfaceAsyncIOCallbacks->pfnReadAsync(pImage->pInterfaceAsyncIO->pvUser,
     5853                                                               pExtent->pFile->pStorage, uOffset,
     5854                                                               pImage->paSegments, cSegments, cbRead,
     5855                                                               pvUser, &pTask);
     5856    }
     5857
     5858out:
     5859    LogFlowFunc(("returns %Rrc\n", rc));
     5860    return rc;
     5861}
     5862
     5863static int vmdkAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     5864                          PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
     5865{
     5866    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     5867    PVMDKEXTENT pExtent;
     5868    int rc = VINF_SUCCESS;
     5869    unsigned cSegments = 0;
     5870    PPDMDATASEG paSegCurrent = paSeg;
     5871    size_t cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     5872    size_t uOffsetInCurrentSegment = 0;
     5873
     5874    AssertPtr(pImage);
     5875    Assert(uOffset % 512 == 0);
     5876    Assert(cbWrite % 512 == 0);
     5877
     5878    if (   uOffset + cbWrite > pImage->cbSize
     5879        || cbWrite == 0)
     5880    {
     5881        rc = VERR_INVALID_PARAMETER;
     5882        goto out;
     5883    }
     5884
     5885    while (cbWrite && cSeg)
     5886    {
     5887        size_t cbToWrite;
     5888        uint64_t uSectorExtentRel;
     5889
     5890        rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
     5891                            &pExtent, &uSectorExtentRel);
     5892        if (RT_FAILURE(rc))
     5893            goto out;
     5894
     5895        /* Check access permissions as defined in the extent descriptor. */
     5896        if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
     5897        {
     5898            rc = VERR_VD_VMDK_INVALID_STATE;
     5899            goto out;
     5900        }
     5901
     5902        /* Clip write range to remain in this extent. */
     5903        cbToWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     5904        /* Clip write range to remain into current data segment. */
     5905        cbToWrite = RT_MIN(cbToWrite, cbLeftInCurrentSegment);
     5906
     5907        switch (pExtent->enmType)
     5908        {
     5909            case VMDKETYPE_VMFS:
     5910            case VMDKETYPE_FLAT:
     5911            {
     5912                /* Check for enough room first. */
     5913                if (RT_LIKELY(cSegments >= pImage->cSegments))
     5914                {
     5915                    /* We reached maximum, resize array. Try to realloc memory first. */
     5916                    PPDMDATASEG paSegmentsNew = (PPDMDATASEG)RTMemRealloc(pImage->paSegments, (cSegments + 10)*sizeof(PDMDATASEG));
     5917
     5918                    if (!paSegmentsNew)
     5919                    {
     5920                        /* We failed. Allocate completely new. */
     5921                        paSegmentsNew = (PPDMDATASEG)RTMemAllocZ((cSegments + 10)* sizeof(PDMDATASEG));
     5922                        if (!paSegmentsNew)
     5923                        {
     5924                            /* Damn, we are out of memory. */
     5925                            rc = VERR_NO_MEMORY;
     5926                            goto out;
     5927                        }
     5928
     5929                        /* Copy task handles over. */
     5930                        for (unsigned i = 0; i < cSegments; i++)
     5931                            paSegmentsNew[i] = pImage->paSegments[i];
     5932
     5933                        /* Free old memory. */
     5934                        RTMemFree(pImage->paSegments);
     5935                    }
     5936
     5937                    pImage->cSegments = cSegments + 10;
     5938                    pImage->paSegments = paSegmentsNew;
     5939                }
     5940
     5941                pImage->paSegments[cSegments].cbSeg = cbToWrite;
     5942                pImage->paSegments[cSegments].pvSeg = (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment;
     5943                cSegments++;
     5944                break;
     5945            }
     5946            case VMDKETYPE_ZERO:
     5947                /* Nothing left to do. */
     5948                break;
     5949            default:
     5950                AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType));
     5951        }
     5952
    59745953        cbWrite -= cbToWrite;
    59755954        uOffset += cbToWrite;
     
    59865965    }
    59875966
    5988     AssertMsg(cbWrite == 0, ("No segment left but there is still data to read\n"));
    5989 
    5990     if (cTasksToSubmit == 0)
     5967    AssertMsg(cbWrite == 0, ("No segment left but there is still data to write\n"));
     5968
     5969    if (cSegments == 0)
    59915970    {
    59925971        /* The request was completely in a ZERO extent nothing to do. */
     
    59955974    else
    59965975    {
    5997         /* Submit tasks. */
    5998         rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser,
    5999                                                                 pImage->apTask, cTasksToSubmit,
    6000                                                                 NULL, pvUser,
    6001                                                                 NULL /* Nothing required after read. */);
    6002         AssertMsgRC(rc, ("Failed to enqueue tasks rc=%Rrc\n", rc));
     5976        /* Start the write */
     5977        void *pTask;
     5978        rc = pImage->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pImage->pInterfaceAsyncIO->pvUser,
     5979                                                               pExtent->pFile->pStorage, uOffset,
     5980                                                               pImage->paSegments, cSegments, cbWrite,
     5981                                                               pvUser, &pTask);
    60035982    }
    60045983
     
    60065985    LogFlowFunc(("returns %Rrc\n", rc));
    60075986    return rc;
    6008 
    60095987}
    60105988
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