VirtualBox

Changeset 10715 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jul 16, 2008 10:38:23 PM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
33435
Message:

Merge async I/O for VMDK backend from private branch

Location:
trunk/src/VBox/Devices
Files:
10 edited

Legend:

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

    r8529 r10715  
    260260
    261261/** @copydoc PDMIBLOCKASYNC::pfnRead */
    262 static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
     262static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
    263263{
    264264    PDRVBLOCK pData = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
     
    279279
    280280/** @copydoc PDMIBLOCKASYNC::pfnWrite */
    281 static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)
     281static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)
    282282{
    283283    PDRVBLOCK pData = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
     
    302302#define PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface)    ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMediaAsyncPort))) )
    303303
    304 
    305 static DECLCALLBACK(int) drvblockAsyncReadCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, uint64_t uOffset, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
     304static DECLCALLBACK(int) drvblockAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser)
    306305{
    307306    PDRVBLOCK pData = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface);
    308307
    309     return pData->pDrvBlockAsyncPort->pfnReadCompleteNotify(pData->pDrvBlockAsyncPort, uOffset, pSeg, cSeg, cbRead, pvUser);
    310 }
    311 
    312 static DECLCALLBACK(int) drvblockAsyncWriteCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, uint64_t uOffset, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWritten, void *pvUser)
    313 {
    314     PDRVBLOCK pData = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface);
    315 
    316 #ifdef VBOX_PERIODIC_FLUSH
    317     if (pData->cbFlushInterval)
    318     {
    319         pData->cbDataWritten += cbWritten;
    320         if (pData->cbDataWritten > pData->cbFlushInterval)
    321         {
    322             pData->cbDataWritten = 0;
    323             pData->pDrvMedia->pfnFlush(pData->pDrvMedia);
    324         }
    325     }
    326 #endif /* VBOX_PERIODIC_FLUSH */
    327 
    328     return pData->pDrvBlockAsyncPort->pfnWriteCompleteNotify(pData->pDrvBlockAsyncPort, uOffset, pSeg, cSeg, cbWritten, pvUser);
     308    return pData->pDrvBlockAsyncPort->pfnTransferCompleteNotify(pData->pDrvBlockAsyncPort, pvUser);
    329309}
    330310
     
    678658            return pData->pDrvMediaAsync ? &pData->IBlockAsync : NULL;
    679659        case PDMINTERFACE_MEDIA_ASYNC_PORT:
    680             return &pData->IMediaAsyncPort;
     660            return pData->pDrvBlockAsyncPort ? &pData->IMediaAsyncPort : NULL;
    681661        default:
    682662            return NULL;
     
    771751
    772752    /* IMediaAsyncPort. */
    773     pData->IMediaAsyncPort.pfnReadCompleteNotify  = drvblockAsyncReadCompleteNotify;
    774     pData->IMediaAsyncPort.pfnWriteCompleteNotify = drvblockAsyncWriteCompleteNotify;
     753    pData->IMediaAsyncPort.pfnTransferCompleteNotify  = drvblockAsyncTransferCompleteNotify;
    775754
    776755    /*
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r8155 r10715  
    3434#include <iprt/file.h>
    3535#include <iprt/string.h>
     36#include <iprt/cache.h>
    3637
    3738#include "Builtins.h"
     
    5455    ( PDMINS2DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) )
    5556
     57/** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */
     58#define PDMIMEDIAASYNC_2_VBOXDISK(pInterface) \
     59    ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) )
     60
     61/** Converts a pointer to VBOXDISK::ITransportAsyncPort to a PVBOXDISK. */
     62#define PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface) \
     63    ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, ITransportAsyncPort)) )
     64
     65/**
     66 * Structure for an async I/O task.
     67 */
     68typedef struct DRVVDASYNCTASK
     69{
     70    /** Callback which is called on completion. */
     71    PFNVDCOMPLETED pfnCompleted;
     72    /** Opqaue user data which is passed on completion. */
     73    void           *pvUser;
     74    /** Opaque user data the caller passed on transfer initiation. */
     75    void           *pvUserCaller;
     76} DRVVDASYNCTASK, *PDRVVDASYNCTASK;
    5677
    5778/**
     
    6182{
    6283    /** The VBox disk container. */
    63     PVBOXHDD        pDisk;
     84    PVBOXHDD           pDisk;
    6485    /** The media interface. */
    65     PDMIMEDIA       IMedia;
     86    PDMIMEDIA          IMedia;
    6687    /** Pointer to the driver instance. */
    67     PPDMDRVINS      pDrvIns;
     88    PPDMDRVINS         pDrvIns;
    6889    /** Flag whether suspend has changed image open mode to read only. */
    69     bool            fTempReadOnly;
     90    bool               fTempReadOnly;
     91    /** Common structure for the supported error interface. */
     92    VDINTERFACE        VDIError;
     93    /** Callback table for error interface. */
     94    VDINTERFACEERROR   VDIErrorCallbacks;
     95    /** Common structure for the supported async I/O interface. */
     96    VDINTERFACE        VDIAsyncIO;
     97    /** Callback table for async I/O interface. */
     98    VDINTERFACEASYNCIO VDIAsyncIOCallbacks;
     99    /** Flag whether opened disk suppports async I/O operations. */
     100    bool               fAsyncIOSupported;
     101    /** The async media interface. */
     102    PDMIMEDIAASYNC           IMediaAsync;
     103    /** The async media port interface above. */
     104    PPDMIMEDIAASYNCPORT      pDrvMediaAsyncPort;
     105    /** Pointer to the asynchronous media driver below. */
     106    PPDMITRANSPORTASYNC      pDrvTransportAsync;
     107    /** Async transport port interface. */
     108    PDMITRANSPORTASYNCPORT   ITransportAsyncPort;
     109    /** Our cache to reduce allocation overhead. */
     110    PRTOBJCACHE              pCache;
    70111} VBOXDISK, *PVBOXDISK;
    71112
     
    79120    PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser;
    80121    pDrvIns->pDrvHlp->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
     122}
     123
     124/*******************************************************************************
     125*   VD Async I/O interface implementation                                      *
     126*******************************************************************************/
     127
     128static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation, bool fReadonly, void **ppStorage)
     129{
     130    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     131
     132    return pDrvVD->pDrvTransportAsync->pfnOpen(pDrvVD->pDrvTransportAsync, pszLocation, fReadonly, ppStorage);
     133}
     134
     135static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage)
     136{
     137    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     138
     139    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
     140
     141   return pDrvVD->pDrvTransportAsync->pfnClose(pDrvVD->pDrvTransportAsync, pStorage);
     142}
     143
     144static DECLCALLBACK(int) drvvdAsyncIORead(void *pvUser, void *pStorage, uint64_t uOffset,
     145                                          size_t cbRead, void *pvBuf, size_t *pcbRead)
     146{
     147    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     148
     149    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
     150
     151    return pDrvVD->pDrvTransportAsync->pfnReadSynchronous(pDrvVD->pDrvTransportAsync,
     152                                                          pStorage,
     153                                                          uOffset, pvBuf, cbRead, pcbRead);
     154}
     155
     156static DECLCALLBACK(int) drvvdAsyncIOWrite(void *pvUser, void *pStorage, uint64_t uOffset,
     157                                           size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
     158{
     159    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     160
     161    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
     162
     163    return pDrvVD->pDrvTransportAsync->pfnWriteSynchronous(pDrvVD->pDrvTransportAsync,
     164                                                           pStorage,
     165                                                           uOffset, pvBuf, cbWrite, pcbWritten);
     166}
     167
     168static DECLCALLBACK(int) drvvdAsyncIOFlush(void *pvUser, void *pStorage)
     169{
     170    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     171
     172    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
     173
     174    return pDrvVD->pDrvTransportAsync->pfnFlushSynchronous(pDrvVD->pDrvTransportAsync, pStorage);
     175}
     176
     177static DECLCALLBACK(int) drvvdAsyncIOPrepareRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbRead, void **ppTask)
     178{
     179    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     180
     181    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
     182
     183    return pDrvVD->pDrvTransportAsync->pfnPrepareRead(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbRead, ppTask);
     184}
     185
     186static DECLCALLBACK(int) drvvdAsyncIOPrepareWrite(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbWrite, void **ppTask)
     187{
     188    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     189
     190    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
     191
     192    return pDrvVD->pDrvTransportAsync->pfnPrepareWrite(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbWrite, ppTask);
     193}
     194
     195static DECLCALLBACK(int) drvvdAsyncIOTasksSubmit(void *pvUser, void *apTasks[], unsigned cTasks, void *pvUser2,
     196                                                 void *pvUserCaller, PFNVDCOMPLETED pfnTasksCompleted)
     197{
     198    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
     199    PDRVVDASYNCTASK pDrvVDAsyncTask;
     200    int rc;
     201
     202    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
     203
     204    rc = RTCacheRequest(pDrvVD->pCache, (void **)&pDrvVDAsyncTask);
     205
     206    if (RT_FAILURE(rc))
     207        return rc;
     208
     209    pDrvVDAsyncTask->pfnCompleted = pfnTasksCompleted;
     210    pDrvVDAsyncTask->pvUser       = pvUser2;
     211    pDrvVDAsyncTask->pvUserCaller = pvUserCaller;
     212
     213    return pDrvVD->pDrvTransportAsync->pfnTasksSubmit(pDrvVD->pDrvTransportAsync, apTasks, cTasks, pDrvVDAsyncTask);
    81214}
    82215
     
    213346}
    214347
     348/*******************************************************************************
     349*   Async Media interface methods                                              *
     350*******************************************************************************/
     351
     352static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
     353                                        PPDMDATASEG paSeg, unsigned cSeg,
     354                                        size_t cbRead, void *pvUser)
     355{
     356     LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
     357             uOffset, paSeg, cSeg, cbRead, pvUser));
     358    PVBOXDISK pData = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
     359    int rc = VDAsyncRead(pData->pDisk, uOffset, cbRead, paSeg, cSeg, pvUser);
     360    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     361    return rc;
     362}
     363
     364static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
     365                                         PPDMDATASEG paSeg, unsigned cSeg,
     366                                         size_t cbWrite, void *pvUser)
     367{
     368     LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d\n pvUser=%#p", __FUNCTION__,
     369             uOffset, paSeg, cSeg, cbWrite, pvUser));
     370    PVBOXDISK pData = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
     371    int rc = VDAsyncWrite(pData->pDisk, uOffset, cbWrite, paSeg, cSeg, pvUser);
     372    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     373    return rc;
     374}
     375
     376/*******************************************************************************
     377*   Async transport port interface methods                                     *
     378*******************************************************************************/
     379
     380static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMITRANSPORTASYNCPORT pInterface, void *pvUser)
     381{
     382    PVBOXDISK pData = PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface);
     383    PDRVVDASYNCTASK pDrvVDAsyncTask = (PDRVVDASYNCTASK)pvUser;
     384    int rc = VINF_VDI_ASYNC_IO_FINISHED;
     385   
     386    /* Having a completion callback for a task is not mandatory. */
     387    if (pDrvVDAsyncTask->pfnCompleted)
     388        rc = pDrvVDAsyncTask->pfnCompleted(pDrvVDAsyncTask->pvUser);
     389
     390    /* Check if the request is finished. */
     391    if (rc == VINF_VDI_ASYNC_IO_FINISHED)
     392    {
     393        rc = pData->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pData->pDrvMediaAsyncPort, pDrvVDAsyncTask->pvUserCaller);
     394    }
     395    else if (rc == VERR_VDI_ASYNC_IO_IN_PROGRESS)
     396        rc = VINF_SUCCESS;
     397
     398    rc = RTCacheInsert(pData->pCache, pDrvVDAsyncTask);
     399    AssertRC(rc);
     400
     401    return rc;
     402}
     403
    215404
    216405/*******************************************************************************
     
    230419        case PDMINTERFACE_MEDIA:
    231420            return &pData->IMedia;
     421        case PDMINTERFACE_MEDIA_ASYNC:
     422            return pData->fAsyncIOSupported ? &pData->IMediaAsync : NULL;
     423        case PDMINTERFACE_TRANSPORT_ASYNC_PORT:
     424            return &pData->ITransportAsyncPort;
    232425        default:
    233426            return NULL;
     
    282475    pData->IMedia.pfnGetUuid            = drvvdGetUuid;
    283476
     477    /* IMediaAsync */
     478    pData->IMediaAsync.pfnStartRead       = drvvdStartRead;
     479    pData->IMediaAsync.pfnStartWrite      = drvvdStartWrite;
     480
     481    /* ITransportAsyncPort */
     482    pData->ITransportAsyncPort.pfnTaskCompleteNotify  = drvvdTasksCompleteNotify;
     483
     484    /* Initialize supported VD interfaces. */
     485    pData->VDIErrorCallbacks.cbSize       = sizeof(VDINTERFACEERROR);
     486    pData->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     487    pData->VDIErrorCallbacks.pfnError     = drvvdErrorCallback;
     488
     489    rc = VDInterfaceCreate(&pData->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
     490                           &pData->VDIErrorCallbacks, pData, NULL);
     491    AssertRC(rc);
     492
     493    pData->VDIAsyncIOCallbacks.cbSize                  = sizeof(VDINTERFACEASYNCIO);
     494    pData->VDIAsyncIOCallbacks.enmInterface            = VDINTERFACETYPE_ASYNCIO;
     495    pData->VDIAsyncIOCallbacks.pfnOpen                 = drvvdAsyncIOOpen;
     496    pData->VDIAsyncIOCallbacks.pfnClose                = drvvdAsyncIOClose;
     497    pData->VDIAsyncIOCallbacks.pfnRead                 = drvvdAsyncIORead;
     498    pData->VDIAsyncIOCallbacks.pfnWrite                = drvvdAsyncIOWrite;
     499    pData->VDIAsyncIOCallbacks.pfnFlush                = drvvdAsyncIOFlush;
     500    pData->VDIAsyncIOCallbacks.pfnPrepareRead          = drvvdAsyncIOPrepareRead;
     501    pData->VDIAsyncIOCallbacks.pfnPrepareWrite         = drvvdAsyncIOPrepareWrite;
     502    pData->VDIAsyncIOCallbacks.pfnTasksSubmit          = drvvdAsyncIOTasksSubmit;
     503
     504    rc = VDInterfaceCreate(&pData->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
     505                           &pData->VDIAsyncIOCallbacks, pData, &pData->VDIError);
     506    AssertRC(rc);
     507
     508    /* Try to attach async media port interface above.*/
     509    pData->pDrvMediaAsyncPort = (PPDMIMEDIAASYNCPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MEDIA_ASYNC_PORT);
     510
     511    /*
     512     * Attach the async transport driver below of the device above us implements the
     513     * async interface.
     514     */
     515    if (pData->pDrvMediaAsyncPort)
     516    {
     517        /* Try to attach the driver. */
     518        PPDMIBASE pBase;
     519
     520        rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBase);
     521        if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
     522        {
     523            /*
     524             * Though the device supports async I/O the backend seems to not support it.
     525             * Revert to non async I/O.
     526             */
     527            pData->pDrvMediaAsyncPort = NULL;
     528        }
     529        else if (VBOX_FAILURE(rc))
     530        {
     531            AssertMsgFailed(("Failed to attach async transport driver below rc=%Vrc\n", rc));
     532        }
     533        else
     534        {
     535            /* Success query the async transport interface. */
     536            pData->pDrvTransportAsync = (PPDMITRANSPORTASYNC)pBase->pfnQueryInterface(pBase, PDMINTERFACE_TRANSPORT_ASYNC);
     537            if (!pData->pDrvTransportAsync)
     538            {
     539                /* Whoops. */
     540                AssertMsgFailed(("Configuration error: No async transport interface below!\n"));
     541                return VERR_PDM_MISSING_INTERFACE_ABOVE;
     542
     543            }
     544        }
     545    }
     546
    284547    /*
    285548     * Validate configuration and find all parent images.
     
    325588    if (VBOX_SUCCESS(rc))
    326589    {
    327         rc = VDCreate(drvvdErrorCallback, pDrvIns, &pData->pDisk);
     590        rc = VDCreate(&pData->VDIAsyncIO, &pData->pDisk);
    328591        /* Error message is already set correctly. */
    329592    }
     
    388651        if (fHonorZeroWrites)
    389652            uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
     653        if (pData->pDrvMediaAsyncPort)
     654            uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
     655
     656        /** Try to open backend in asyc I/O mode first. */
    390657        rc = VDOpen(pData->pDisk, pszFormat, pszName, uOpenFlags);
     658        if (rc == VERR_NOT_SUPPORTED)
     659        {
     660            /* Seems asxnc I/O is not supported by the backend, open in normal mode. */
     661            uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
     662            rc = VDOpen(pData->pDisk, pszFormat, pszName, uOpenFlags);
     663        }
     664
    391665        if (VBOX_SUCCESS(rc))
    392666            Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
     
    395669        else
    396670        {
    397             AssertMsgFailed(("Failed to open image '%s' rc=%Vrc\n", pszName, rc));
    398             break;
    399         }
     671           AssertMsgFailed(("Failed to open image '%s' rc=%Vrc\n", pszName, rc));
     672           break;
     673        }
     674
     675
    400676        MMR3HeapFree(pszName);
    401677        pszName = NULL;
     
    419695        if (VALID_PTR(pszFormat))
    420696            MMR3HeapFree(pszFormat);
     697    }
     698
     699    /*
     700     * Check for async I/O support. Every opened image has to support
     701     * it.
     702     */
     703    pData->fAsyncIOSupported = true;
     704    for (unsigned i = 0; i < VDGetCount(pData->pDisk); i++)
     705    {
     706        VDBACKENDINFO vdBackendInfo;
     707
     708        rc = VDBackendInfoSingle(pData->pDisk, i, &vdBackendInfo);
     709        AssertRC(rc);
     710
     711        if (vdBackendInfo.uBackendCaps & VD_CAP_ASYNC)
     712        {
     713            /*
     714             * Backend indicates support for at least some files.
     715             * Check if current file is supported with async I/O)
     716             */
     717            rc = VDImageIsAsyncIOSupported(pData->pDisk, i, &pData->fAsyncIOSupported);
     718            AssertRC(rc);
     719
     720            /*
     721             * Check if current image is supported.
     722             * If not we can stop checking because
     723             * at least one does not support it.
     724             */
     725            if (!pData->fAsyncIOSupported)
     726                break;
     727        }
     728        else
     729        {
     730            pData->fAsyncIOSupported = false;
     731            break;
     732        }
     733    }
     734
     735    /* Create cache if async I/O is supported. */
     736    if (pData->fAsyncIOSupported)
     737    {
     738        rc = RTCacheCreate(&pData->pCache, 0, sizeof(DRVVDASYNCTASK), RTOBJCACHE_PROTECT_INSERT);
     739        AssertMsg(RT_SUCCESS(rc), ("Failed to create cache rc=%Vrc\n", rc));
    421740    }
    422741
     
    435754static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
    436755{
    437     LogFlow(("%s:\n", __FUNCTION__));
     756    int rc;
    438757    PVBOXDISK pData = PDMINS2DATA(pDrvIns, PVBOXDISK);
    439     int rc = VDCloseAll(pData->pDisk);
     758    LogFlow(("%s:\n", __FUNCTION__));
     759    rc = RTCacheDestroy(pData->pCache);
    440760    AssertRC(rc);
    441761}
     
    487807}
    488808
    489 
     809static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
     810{
     811    LogFlow(("%s:\n", __FUNCTION__));
     812    PVBOXDISK pData = PDMINS2DATA(pDrvIns, PVBOXDISK);
     813
     814    /*
     815     * We must close the disk here to ensure that
     816     * the backend closes all files before the
     817     * async transport driver is destructed.
     818     */
     819    int rc = VDCloseAll(pData->pDisk);
     820    AssertRC(rc);
     821}
    490822
    491823/**
     
    523855    drvvdResume,
    524856    /* pfnDetach */
    525     NULL
     857    NULL,
     858    /* pfnPowerOff */
     859    drvvdPowerOff
    526860};
  • trunk/src/VBox/Devices/Storage/RawHDDCore.cpp

    r10467 r10715  
    4848
    4949    /** Error callback. */
    50     PFNVDERROR      pfnError;
     50    PVDINTERFACE      pInterfaceError;
    5151    /** Opaque data for error callback. */
    52     void            *pvErrorUser;
     52    PVDINTERFACEERROR pInterfaceErrorCallbacks;
    5353
    5454    /** Open flags passed by VBoxHD layer. */
     
    8484    va_list va;
    8585    va_start(va, pszFormat);
    86     if (pImage->pfnError)
    87         pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,
    88                          pszFormat, va);
     86    if (pImage->pInterfaceError)
     87        pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
     88                                                   pszFormat, va);
    8989    va_end(va);
    9090    return rc;
     
    9898    int rc;
    9999    RTFILE File;
     100
     101    if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
     102        return VERR_NOT_SUPPORTED;
    100103
    101104    pImage->uOpenFlags = uOpenFlags;
     
    305308/** @copydoc VBOXHDDBACKEND::pfnOpen */
    306309static int rawOpen(const char *pszFilename, unsigned uOpenFlags,
    307                     PFNVDERROR pfnError, void *pvErrorUser,
    308                     void **ppBackendData)
     310                   PVDINTERFACE pInterfaces, void **ppBackendData)
    309311{
    310312    LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x ppBackendData=%#p\n", pszFilename, uOpenFlags, ppBackendData));
     
    336338    pImage->pszFilename = pszFilename;
    337339    pImage->File = NIL_RTFILE;
    338     pImage->pfnError = pfnError;
    339     pImage->pvErrorUser = pvErrorUser;
     340    pImage->pInterfaceError = NULL;
     341    pImage->pInterfaceErrorCallbacks = NULL;
     342
     343    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
     344    if (pImage->pInterfaceError)
     345        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks);
    340346
    341347    rc = rawOpenImage(pImage, uOpenFlags);
     
    356362                     unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
    357363                     void *pvUser, unsigned uPercentStart,
    358                      unsigned uPercentSpan, PFNVDERROR pfnError,
    359                      void *pvErrorUser, void **ppBackendData)
    360 {
    361     LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
     364                     unsigned uPercentSpan, PVDINTERFACE pInterfaces,
     365                     void **ppBackendData)
     366{
     367    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData));
    362368    int rc;
    363369    PRAWIMAGE pImage;
     
    389395    pImage->pszFilename = pszFilename;
    390396    pImage->File = NIL_RTFILE;
    391     pImage->pfnError = pfnError;
    392     pImage->pvErrorUser = pvErrorUser;
     397
     398    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
     399    if (pImage->pInterfaceError)
     400        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
     401
    393402
    394403    rc = rawCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
     
    987996}
    988997
     998static int rawGetTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
     999{
     1000    int rc = VERR_NOT_IMPLEMENTED;
     1001    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     1002    return rc;
     1003}
     1004
     1005static int rawGetParentTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
     1006{
     1007    int rc = VERR_NOT_IMPLEMENTED;
     1008    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     1009    return rc;
     1010}
     1011
     1012static int rawSetParentTimeStamp(void *pvBackendData, PCRTTIMESPEC pTimeStamp)
     1013{
     1014    int rc = VERR_NOT_IMPLEMENTED;
     1015    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     1016    return rc;
     1017}
     1018
     1019static int rawGetParentFilename(void *pvBackendData, char **ppszParentFilename)
     1020{
     1021    int rc = VERR_NOT_IMPLEMENTED;
     1022    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     1023    return rc;
     1024}
     1025
     1026static int rawSetParentFilename(void *pvBackendData, const char *pszParentFilename)
     1027{
     1028    int rc = VERR_NOT_IMPLEMENTED;
     1029    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     1030    return rc;
     1031}
     1032
     1033static bool rawIsAsyncIOSupported(void *pvBackendData)
     1034{
     1035    return false;
     1036}
     1037
     1038static int rawAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
     1039                        PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
     1040{
     1041    int rc = VERR_NOT_IMPLEMENTED;
     1042    LogFlowFunc(("returns %Vrc\n", rc));
     1043    return rc;
     1044}
     1045
     1046static int rawAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     1047                         PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
     1048{
     1049    int rc = VERR_NOT_IMPLEMENTED;
     1050    LogFlowFunc(("returns %Vrc\n", rc));
     1051    return rc;
     1052}
    9891053
    9901054VBOXHDDBACKEND g_RawBackend =
     
    10551119    rawSetParentModificationUuid,
    10561120    /* pfnDump */
    1057     rawDump
     1121    rawDump,
     1122    /* pfnGetTimeStamp */
     1123    rawGetTimeStamp,
     1124    /* pfnGetParentTimeStamp */
     1125    rawGetParentTimeStamp,
     1126    /* pfnSetParentTimeStamp */
     1127    rawSetParentTimeStamp,
     1128    /* pfnGetParentFilename */
     1129    rawGetParentFilename,
     1130    /* pfnSetParentFilename */
     1131    rawSetParentFilename,
     1132    /* pfnIsAsyncIOSupported */
     1133    rawIsAsyncIOSupported,
     1134    /* pfnAsyncRead */
     1135    rawAsyncRead,
     1136    /* pfnAsyncWrite */
     1137    rawAsyncWrite
    10581138};
     1139
  • trunk/src/VBox/Devices/Storage/VBoxHDD-new.cpp

    r10540 r10715  
    108108    PDMMEDIAGEOMETRY    LCHSGeometry;
    109109
    110     /** Error message processing callback. */
    111     PFNVDERROR          pfnError;
    112     /** Opaque data for error callback. */
    113     void                *pvErrorUser;
     110    /** List of interfaces the caller supports. */
     111    PVDINTERFACE        pInterfaces;
     112    /** Pointer to the common interface structure for error reporting. */
     113    PVDINTERFACE        pInterfaceError;
     114    /** Pointer to the error interface we use if available. */
     115    PVDINTERFACEERROR   pInterfaceErrorCallbacks;
    114116};
    115117
     
    148150    va_list va;
    149151    va_start(va, pszFormat);
    150     if (pDisk->pfnError)
    151         pDisk->pfnError(pDisk->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
     152    if (pDisk->pInterfaceErrorCallbacks)
     153        pDisk->pInterfaceErrorCallbacks->pfnError(pDisk->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
    152154    va_end(va);
    153155    return rc;
     
    761763}
    762764
     765/**
     766 * Lists the capablities of a backend indentified by its name.
     767 * Free all returned names with RTStrFree() when you no longer need them.
     768 *
     769 * @returns VBox status code.
     770 * @param   pszBackend      The backend name.
     771 * @param   pEntries        Pointer to an entry.
     772 */
     773VBOXDDU_DECL(int) VDBackendInfoOne(const char *pszBackend, PVDBACKENDINFO pEntry)
     774{
     775    return VERR_NOT_IMPLEMENTED;
     776}
    763777
    764778/**
     
    767781 *
    768782 * @returns VBox status code.
    769  * @param   pfnError        Callback for setting extended error information.
    770  * @param   pvErrorUser     Opaque parameter for pfnError.
     783 * @param   pInterfaces     Pointer to the first supported interface.
    771784 * @param   ppDisk          Where to store the reference to HDD container.
    772785 */
    773 VBOXDDU_DECL(int) VDCreate(PFNVDERROR pfnError, void *pvErrorUser,
    774                            PVBOXHDD *ppDisk)
     786VBOXDDU_DECL(int) VDCreate(PVDINTERFACE pInterfaces, PVBOXHDD *ppDisk)
    775787{
    776788    int rc = VINF_SUCCESS;
    777789    PVBOXHDD pDisk = NULL;
    778790
    779     LogFlowFunc(("pfnError=%#p pvErrorUser=%#p\n", pfnError, pvErrorUser));
     791    LogFlowFunc(("pInterfaces=%#p\n", pInterfaces));
    780792    do
    781793    {
    782794        /* Check arguments. */
    783         AssertMsgBreakStmt(VALID_PTR(pfnError),
    784                            ("pfnError=%#p\n", pfnError),
    785                            rc = VERR_INVALID_PARAMETER);
    786795        AssertMsgBreakStmt(VALID_PTR(ppDisk),
    787796                           ("ppDisk=%#p\n", ppDisk),
     
    802811            pDisk->LCHSGeometry.cHeads     = 0;
    803812            pDisk->LCHSGeometry.cSectors   = 0;
    804             pDisk->pfnError     = pfnError;
    805             pDisk->pvErrorUser  = pvErrorUser;
     813            pDisk->pInterfaces  = pInterfaces;
     814            pDisk->pInterfaceError = NULL;
     815            pDisk->pInterfaceErrorCallbacks = NULL;
     816
     817            pDisk->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
     818            if (pDisk->pInterfaceError)
     819                pDisk->pInterfaceErrorCallbacks = VDGetInterfaceError(pDisk->pInterfaceError->pCallbacks);
    806820            *ppDisk = pDisk;
    807821        }
     
    10781092        rc = pImage->Backend->pfnOpen(pImage->pszFilename,
    10791093                                      uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME,
    1080                                       pDisk->pfnError, pDisk->pvErrorUser,
     1094                                      pDisk->pInterfaces,
    10811095                                      &pImage->pvBackendData);
    10821096        /* If the open in read-write mode failed, retry in read-only mode. */
     
    10921106                                                (uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME)
    10931107                                               | VD_OPEN_FLAGS_READONLY,
    1094                                                pDisk->pfnError, pDisk->pvErrorUser,
     1108                                               pDisk->pInterfaces,
    10951109                                               &pImage->pvBackendData);
    10961110            if (VBOX_FAILURE(rc))
     
    13421356                                        uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME,
    13431357                                        pfnProgress, pvUser, 0, 99,
    1344                                         pDisk->pfnError, pDisk->pvErrorUser,
     1358                                        pDisk->pInterfaces,
    13451359                                        &pImage->pvBackendData);
    13461360
     
    15151529                                        uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME,
    15161530                                        pfnProgress, pvUser, 0, 99,
    1517                                         pDisk->pfnError, pDisk->pvErrorUser,
     1531                                        pDisk->pInterfaces,
    15181532                                        &pImage->pvBackendData);
    15191533
     
    24712485    } while (0);
    24722486
    2473     LogFlowFunc(("%s: %Vrc (PCHS=%u/%u/%u)\n", rc,
     2487    LogFlowFunc(("%s: %Vrc (PCHS=%u/%u/%u)\n", __FUNCTION__, rc,
    24742488                 pDisk->PCHSGeometry.cCylinders, pDisk->PCHSGeometry.cHeads,
    24752489                 pDisk->PCHSGeometry.cSectors));
     
    26172631    } while (0);
    26182632
    2619     LogFlowFunc(("%s: %Vrc (LCHS=%u/%u/%u)\n", rc,
     2633    LogFlowFunc((": %Vrc (LCHS=%u/%u/%u)\n", rc,
    26202634                 pDisk->LCHSGeometry.cCylinders, pDisk->LCHSGeometry.cHeads,
    26212635                 pDisk->LCHSGeometry.cSectors));
     
    28002814}
    28012815
     2816
     2817/**
     2818 * List the capabilities of image backend in HDD container.
     2819 *
     2820 * @returns VBox status code.
     2821 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     2822 * @param   pDisk           Pointer to the HDD container.
     2823 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     2824 * @param   pbackendInfo    Where to store the backend information.
     2825 */
     2826VBOXDDU_DECL(int) VDBackendInfoSingle(PVBOXHDD pDisk, unsigned nImage,
     2827                                      PVDBACKENDINFO pBackendInfo)
     2828{
     2829    int rc = VINF_SUCCESS;
     2830
     2831    LogFlowFunc(("pDisk=%#p nImage=%u penmType=%#p\n",
     2832                 pDisk, nImage, pBackendInfo));
     2833    do
     2834    {
     2835        /* sanity check */
     2836        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
     2837        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2838
     2839        /* Check arguments. */
     2840        AssertMsgBreakStmt(VALID_PTR(pBackendInfo),
     2841                           ("pBackendInfo=%#p\n", pBackendInfo),
     2842                           rc = VERR_INVALID_PARAMETER);
     2843
     2844        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2845        AssertPtrBreakStmt(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2846
     2847        if (    pImage->enmImageType >= VD_IMAGE_TYPE_FIRST
     2848            &&  pImage->enmImageType <= VD_IMAGE_TYPE_DIFF)
     2849        {
     2850            pBackendInfo->pszBackend = RTStrDup(pImage->Backend->pszBackendName);
     2851            pBackendInfo->uBackendCaps = pImage->Backend->uBackendCaps;
     2852            rc = VINF_SUCCESS;
     2853        }
     2854        else
     2855            rc = VERR_VDI_INVALID_TYPE;
     2856    } while (0);
     2857
     2858    LogFlowFunc(("returns %Vrc\n", rc));
     2859    return rc;
     2860}
     2861
    28022862/**
    28032863 * Get flags of image in HDD container.
     
    33063366}
    33073367
     3368/**
     3369 * Query if asynchronous operations are supported for this disk.
     3370 *
     3371 * @returns VBox status code.
     3372 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     3373 * @param   pDisk           Pointer to the HDD container.
     3374 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     3375 * @param   pfAIOSupported  Where to store if async IO is supported.
     3376 */
     3377VBOXDDU_DECL(int) VDImageIsAsyncIOSupported(PVBOXHDD pDisk, unsigned nImage, bool *pfAIOSupported)
     3378{
     3379    int rc = VINF_SUCCESS;
     3380
     3381    LogFlowFunc(("pDisk=%#p nImage=%u pfAIOSupported=%#p\n", pDisk, nImage, pfAIOSupported));
     3382    do
     3383    {
     3384        /* sanity check */
     3385        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
     3386        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     3387
     3388        /* Check arguments. */
     3389        AssertMsgBreakStmt(VALID_PTR(pfAIOSupported),
     3390                           ("pfAIOSupported=%#p\n", pfAIOSupported),
     3391                           rc = VERR_INVALID_PARAMETER);
     3392
     3393        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     3394        AssertPtrBreakStmt(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     3395
     3396        if (pImage->Backend->uBackendCaps & VD_CAP_ASYNC)
     3397            *pfAIOSupported = pImage->Backend->pfnIsAsyncIOSupported(pImage->pvBackendData);
     3398        else
     3399            *pfAIOSupported = false;
     3400    } while (0);
     3401
     3402    LogFlowFunc(("returns %Vrc, fAIOSupported=%u\n", rc, *pfAIOSupported));
     3403    return rc;
     3404}
     3405
     3406/**
     3407 * Start a asynchronous read request.
     3408 *
     3409 * @returns VBox status code.
     3410 * @param   pDisk           Pointer to the HDD container.
     3411 * @param   uOffset         The offset of the virtual disk to read from.
     3412 * @param   cbRead          How many bytes to read.
     3413 * @param   paSeg           Pointer to an array of segments.
     3414 * @param   cSeg            Number of segments in the array.
     3415 * @param   pvUser          User data which is passed on completion
     3416 */
     3417VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead,
     3418                              PPDMDATASEG paSeg, unsigned cSeg,
     3419                              void *pvUser)
     3420{
     3421    int rc = VERR_VDI_BLOCK_FREE;
     3422
     3423    LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbRead=%zu\n",
     3424                 pDisk, uOffset, paSeg, cSeg, cbRead));
     3425    do
     3426    {
     3427        /* sanity check */
     3428        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
     3429        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     3430
     3431        /* Check arguments. */
     3432        AssertMsgBreakStmt(cbRead,
     3433                           ("cbRead=%zu\n", cbRead),
     3434                           rc = VERR_INVALID_PARAMETER);
     3435        AssertMsgBreakStmt(uOffset + cbRead <= pDisk->cbSize,
     3436                           ("uOffset=%llu cbRead=%zu pDisk->cbSize=%llu\n",
     3437                            uOffset, cbRead, pDisk->cbSize),
     3438                           rc = VERR_INVALID_PARAMETER);
     3439        AssertMsgBreakStmt(VALID_PTR(paSeg),
     3440                           ("paSeg=%#p\n", paSeg),
     3441                           rc = VERR_INVALID_PARAMETER);
     3442        AssertMsgBreakStmt(cSeg,
     3443                           ("cSeg=%zu\n", cSeg),
     3444                           rc = VERR_INVALID_PARAMETER);
     3445
     3446
     3447        PVDIMAGE pImage = pDisk->pLast;
     3448        AssertPtrBreakStmt(pImage, rc = VERR_VDI_NOT_OPENED);
     3449
     3450        /* @todo: This does not work for images which do not have all meta data in memory. */
     3451        for (PVDIMAGE pCurrImage = pImage;
     3452             pCurrImage != NULL && rc == VERR_VDI_BLOCK_FREE;
     3453             pCurrImage = pCurrImage->pPrev)
     3454        {
     3455            rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pvBackendData,
     3456                                                   uOffset, cbRead, paSeg, cSeg,
     3457                                                   pvUser);
     3458        }
     3459
     3460        /* No image in the chain contains the data for the block. */
     3461        if (rc == VERR_VDI_BLOCK_FREE)
     3462        {
     3463            for (unsigned i = 0; i < cSeg && (cbRead > 0); i++)
     3464            {
     3465                memset(paSeg[i].pvSeg, '\0', paSeg[i].cbSeg);
     3466                cbRead -= paSeg[i].cbSeg;
     3467            }
     3468            /* Request finished without the need to enqueue a async I/O request. Tell caller. */
     3469            rc = VINF_VDI_ASYNC_IO_FINISHED;
     3470        }
     3471
     3472    } while (0);
     3473
     3474    LogFlowFunc(("returns %Vrc\n", rc));
     3475    return rc;
     3476}
     3477
     3478
     3479/**
     3480 * Start a asynchronous write request.
     3481 *
     3482 * @returns VBox status code.
     3483 * @param   pDisk           Pointer to the HDD container.
     3484 * @param   uOffset         The offset of the virtual disk to write to.
     3485 * @param   cbWrtie         How many bytes to write.
     3486 * @param   paSeg           Pointer to an array of segments.
     3487 * @param   cSeg            Number of segments in the array.
     3488 * @param   pvUser          User data which is passed on completion.
     3489 */
     3490VBOXDDU_DECL(int) VDAsyncWrite(PVBOXHDD pDisk, uint64_t uOffset, size_t cbWrite,
     3491                               PPDMDATASEG paSeg, unsigned cSeg,
     3492                               void *pvUser)
     3493{
     3494    int rc;
     3495
     3496    LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbWrite=%zu\n",
     3497                 pDisk, uOffset, paSeg, cSeg, cbWrite));
     3498    do
     3499    {
     3500        /* sanity check */
     3501        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
     3502        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     3503
     3504        /* Check arguments. */
     3505        AssertMsgBreakStmt(cbWrite,
     3506                           ("cbWrite=%zu\n", cbWrite),
     3507                           rc = VERR_INVALID_PARAMETER);
     3508        AssertMsgBreakStmt(uOffset + cbWrite <= pDisk->cbSize,
     3509                           ("uOffset=%llu cbWrite=%zu pDisk->cbSize=%llu\n",
     3510                            uOffset, cbWrite, pDisk->cbSize),
     3511                           rc = VERR_INVALID_PARAMETER);
     3512        AssertMsgBreakStmt(VALID_PTR(paSeg),
     3513                           ("paSeg=%#p\n", paSeg),
     3514                           rc = VERR_INVALID_PARAMETER);
     3515        AssertMsgBreakStmt(cSeg,
     3516                           ("cSeg=%zu\n", cSeg),
     3517                           rc = VERR_INVALID_PARAMETER);
     3518
     3519
     3520        PVDIMAGE pImage = pDisk->pLast;
     3521        AssertPtrBreakStmt(pImage, rc = VERR_VDI_NOT_OPENED);
     3522
     3523        vdSetModifiedFlag(pDisk);
     3524        rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData,
     3525                                            uOffset, cbWrite,
     3526                                            paSeg, cSeg, pvUser);
     3527    } while (0);
     3528
     3529    LogFlowFunc(("returns %Vrc\n", rc));
     3530    return rc;
     3531
     3532}
     3533
  • trunk/src/VBox/Devices/Storage/VBoxHDD-newInternal.h

    r9734 r10715  
    7171     *                          unchanged during the lifetime of this image.
    7272     * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
    73      * @param   pfnError        Callback for setting extended error information.
    74      * @param   pvErrorUser     Opaque parameter for pfnError.
     73     * @param   pInterfaces     Pointer to the first element of supported interfaces of the caller.
    7574     * @param   ppvBackendData  Opaque state data for this image.
    7675     */
    77     DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData));
     76    DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags,
     77                                        PVDINTERFACE pInterfaces, void **ppvBackendData));
    7878
    7979    /**
     
    9494     * @param   uPercentStart   Starting value for progress percentage.
    9595     * @param   uPercentSpan    Span for varying progress percentage.
    96      * @param   pfnError        Callback for setting extended error information.
    97      * @param   pvErrorUser     Opaque parameter for pfnError.
     96     * @param   pInterfaces     Pointer to the supported interfaces of the caller.
    9897     * @param   ppvBackendData  Opaque state data for this image.
    9998     */
    100     DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, unsigned uPercentStart, unsigned uPercentSpan, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData));
     99    DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, unsigned uPercentStart, unsigned uPercentSpan, PVDINTERFACE pInterfaces, void **ppvBackendData));
    101100
    102101    /**
     
    421420    DECLR3CALLBACKMEMBER(int, pfnSetParentFilename, (void *pvBackendData, const char *pszParentFilename));
    422421
     422    /**
     423     * Return whether asynchronous I/O operations are supported for this image.
     424     *
     425     * @returns true if asynchronous I/O is supported
     426     *          false otherwise.
     427     * @param   pvBackendData    Opaque state data for this image.
     428     */
     429    DECLR3CALLBACKMEMBER(bool, pfnIsAsyncIOSupported, (void *pvBackendData));
     430
     431    /**
     432     * Start an asynchronous read request.
     433     *
     434     * @returns VBox status code.
     435     * @param   pvBackendData   Opaque state data for this image.
     436     * @param   uOffset         The offset of the virtual disk to read from.
     437     * @param   cbRead          How many bytes to read.
     438     * @param   paSeg           Pointer to the segment array.
     439     * @param   cSeg            Number of segments.
     440     * @param   pvUser          Opaque user data.
     441     */
     442    DECLR3CALLBACKMEMBER(int, pfnAsyncRead, (void *pvBackendData, uint64_t uOffset, size_t cbRead,
     443                                             PPDMDATASEG paSeg, unsigned cSeg, void *pvUser));
     444
     445    /**
     446     * Start an asynchronous write request.
     447     *
     448     * @returns VBox status code.
     449     * @param   pvBackendData   Opaque state data for this image.
     450     * @param   uOffset         The offset of the virtual disk to write to.
     451     * @param   cbWrite         How many bytes to write.
     452     * @param   paSeg           Pointer to the segment array.
     453     * @param   cSeg            Number of segments.
     454     * @param   pvUser          Oaque user data-
     455     */
     456    DECLR3CALLBACKMEMBER(int, pfnAsyncWrite, (void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     457                                              PPDMDATASEG paSeg, unsigned cSeg, void *pvUser));
     458
    423459} VBOXHDDBACKEND;
    424460
  • trunk/src/VBox/Devices/Storage/VDICore.h

    r8170 r10715  
    562562    /** Physical geometry of this image (never actually stored). */
    563563    PDMMEDIAGEOMETRY        PCHSGeometry;
    564     /** Error callback. */
    565     PFNVDERROR              pfnError;
    566     /** Opaque data for error callback. */
    567     void                   *pvErrorUser;
     564    /** Error interface. */
     565    PVDINTERFACE            pInterfaceError;
     566    /** Error interface callback table. */
     567    PVDINTERFACEERROR       pInterfaceErrorCallbacks;
    568568#endif /* VBOX_VDICORE_VD */
    569569} VDIIMAGEDESC, *PVDIIMAGEDESC;
  • trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp

    r10539 r10715  
    6363    va_list va;
    6464    va_start(va, pszFormat);
    65     if (pImage->pfnError)
    66         pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,
    67                          pszFormat, va);
     65    if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
     66        pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser,
     67                                                   rc, RT_SRC_POS_ARGS,
     68                                                   pszFormat, va);
    6869    va_end(va);
    6970    return rc;
     
    508509    int rc;
    509510    RTFILE File;
     511
     512    if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
     513        return VERR_NOT_SUPPORTED;
    510514
    511515    pImage->uOpenFlags = uOpenFlags;
     
    731735    pImage->File = NIL_RTFILE;
    732736    pImage->paBlocks = NULL;
    733     pImage->pfnError = NULL;
    734     pImage->pvErrorUser = NULL;
     737    pImage->pInterfaceError = NULL;
     738    pImage->pInterfaceErrorCallbacks = NULL;
    735739
    736740    rc = vdiOpenImage(pImage, VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY);
     
    744748/** @copydoc VBOXHDDBACKEND::pfnOpen */
    745749static int vdiOpen(const char *pszFilename, unsigned uOpenFlags,
    746                    PFNVDERROR pfnError, void *pvErrorUser,
     750                   PVDINTERFACE pInterfaces,
    747751                   void **ppBackendData)
    748752{
     
    775779    pImage->File = NIL_RTFILE;
    776780    pImage->paBlocks = NULL;
    777     pImage->pfnError = pfnError;
    778     pImage->pvErrorUser = pvErrorUser;
     781    pImage->pInterfaceError = NULL;
     782    pImage->pInterfaceErrorCallbacks = NULL;
     783
     784    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
     785    if (pImage->pInterfaceError)
     786        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks);
    779787
    780788    rc = vdiOpenImage(pImage, uOpenFlags);
     
    795803                     unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
    796804                     void *pvUser, unsigned uPercentStart,
    797                      unsigned uPercentSpan, PFNVDERROR pfnError,
    798                      void *pvErrorUser, void **ppBackendData)
    799 {
    800     LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
     805                     unsigned uPercentSpan, PVDINTERFACE pInterfaces,
     806                     void **ppBackendData)
     807{
     808    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData));
    801809    int rc;
    802810    PVDIIMAGEDESC pImage;
     
    831839    pImage->File = NIL_RTFILE;
    832840    pImage->paBlocks = NULL;
    833     pImage->pfnError = pfnError;
    834     pImage->pvErrorUser = pvErrorUser;
     841    pImage->pInterfaceError = NULL;
     842    pImage->pInterfaceErrorCallbacks = NULL;
    835843
    836844    rc = vdiCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
     
    17531761    return rc;
    17541762}
     1763
     1764static bool vdiIsAsyncIOSupported(void *pvBackendData)
     1765{
     1766    return false;
     1767}
     1768
     1769static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
     1770                        PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
     1771{
     1772    int rc = VERR_NOT_IMPLEMENTED;
     1773    LogFlowFunc(("returns %Vrc\n", rc));
     1774    return rc;
     1775}
     1776
     1777static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     1778                         PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
     1779{
     1780    int rc = VERR_NOT_IMPLEMENTED;
     1781    LogFlowFunc(("returns %Vrc\n", rc));
     1782    return rc;
     1783}
     1784
    17551785
    17561786VBOXHDDBACKEND g_VDIBackend =
     
    18321862    vdiGetParentFilename,
    18331863    /* pfnSetParentFilename */
    1834     vdiSetParentFilename
     1864    vdiSetParentFilename,
     1865    /* pfnIsAsyncIOSupported */
     1866    vdiIsAsyncIOSupported,
     1867    /* pfnAsyncRead */
     1868    vdiAsyncRead,
     1869    /* pfnAsyncWrite */
     1870    vdiAsyncWrite
    18351871};
    18361872
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r10539 r10715  
    179179} VMDKACCESS, *PVMDKACCESS;
    180180
     181/** Forward declaration for PVMDKIMAGE. */
     182typedef struct VMDKIMAGE *PVMDKIMAGE;
     183
     184/**
     185 * Extents files entry. Used for opening a particular file only once.
     186 */
     187typedef struct VMDKFILE
     188{
     189    /** Pointer to filename. Local copy. */
     190    const char *pszFilename;
     191    /** File open flags for consistency checking. */
     192    unsigned    fOpen;
     193    /** File handle. */
     194    RTFILE      File;
     195    /** Handle for asnychronous access if requested.*/
     196    void       *pStorage;
     197    /** Flag whether to use File or pStorage. */
     198    bool        fAsyncIO;
     199    /** Reference counter. */
     200    unsigned    uReferences;
     201    /** Flag whether the file should be deleted on last close. */
     202    bool        fDelete;
     203    /** Pointer to the image we belong to. */
     204    PVMDKIMAGE  pImage;
     205    /** Pointer to next file descriptor. */
     206    struct VMDKFILE *pNext;
     207    /** Pointer to the previous file descriptor. */
     208    struct VMDKFILE *pPrev;
     209} VMDKFILE, *PVMDKFILE;
     210
    181211/**
    182212 * VMDK extent data structure.
     
    185215{
    186216    /** File handle. */
    187     RTFILE      File;
     217    PVMDKFILE    pFile;
    188218    /** Base name of the image extent. */
    189219    const char  *pszBasename;
     
    239269
    240270/**
    241  * Extents files entry. Used for opening a particular file only once.
    242  */
    243 typedef struct VMDKFILE
    244 {
    245     /** Pointer to filename. Local copy. */
    246     const char *pszFilename;
    247     /** File open flags for consistency checking. */
    248     unsigned    fOpen;
    249     /** File handle. */
    250     RTFILE      File;
    251     /** Reference counter. */
    252     unsigned    uReferences;
    253     /** Flag whether the file should be deleted on last close. */
    254     bool        fDelete;
    255     /** Pointer to next file descriptor. Singly linked list is fast enough. */
    256     struct VMDKFILE *pNext;
    257 } VMDKFILE, *PVMDKFILE;
    258 
    259 /**
    260271 * Grain table cache size. Allocated per image.
    261272 */
     
    346357    const char      *pszFilename;
    347358    /** Descriptor file if applicable. */
    348     RTFILE          File;
    349 
    350     /** Error callback. */
    351     PFNVDERROR      pfnError;
    352     /** Opaque data for error callback. */
    353     void            *pvErrorUser;
     359    PVMDKFILE        pFile;
     360
     361    /** Error interface. */
     362    PVDINTERFACE      pInterfaceError;
     363    /** Error interface callbacks. */
     364    PVDINTERFACEERROR pInterfaceErrorCallbacks;
     365
     366    /** Async I/O interface. */
     367    PVDINTERFACE        pInterfaceAsyncIO;
     368    /** Async I/O interface callbacks. */
     369    PVDINTERFACEASYNCIO pInterfaceAsyncIOCallbacks;
     370    /**
     371     * Pointer to an array of task handles for task submission.
     372     * This is an optimization because the task number to submit is not known
     373     * and allocating/freeing an array in the read/write functions every time
     374     * is too expensive.
     375     */
     376    void               **apTask;
     377    /** Entries available in the task handle array. */
     378    unsigned             cTask;
    354379
    355380    /** Open flags passed by VBoxHD layer. */
     
    382407    /** Parsed descriptor file content. */
    383408    VMDKDESCRIPTOR  Descriptor;
    384 } VMDKIMAGE, *PVMDKIMAGE;
     409} VMDKIMAGE;
    385410
    386411
     
    408433    va_list va;
    409434    va_start(va, pszFormat);
    410     if (pImage->pfnError)
    411         pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,
    412                          pszFormat, va);
     435    if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
     436        pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
     437                                                   pszFormat, va);
    413438    va_end(va);
    414439    return rc;
     
    419444 * is only opened once - anything else can cause locking problems).
    420445 */
    421 static int vmdkFileOpen(PVMDKIMAGE pImage, PRTFILE pFile,
    422                         const char *pszFilename, unsigned fOpen)
     446static int vmdkFileOpen(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile,
     447                        const char *pszFilename, unsigned fOpen, bool fAsyncIO)
    423448{
    424449    int rc = VINF_SUCCESS;
     
    433458            Assert(fOpen == pVmdkFile->fOpen);
    434459            pVmdkFile->uReferences++;
    435             *pFile = pVmdkFile->File;
     460
     461            *ppVmdkFile = pVmdkFile;
     462
    436463            return rc;
    437464        }
     
    442469    if (!VALID_PTR(pVmdkFile))
    443470    {
    444         *pFile = NIL_RTFILE;
     471        *ppVmdkFile = NULL;
    445472        return VERR_NO_MEMORY;
    446473    }
     
    450477    {
    451478        RTMemFree(pVmdkFile);
    452         *pFile = NIL_RTFILE;
     479        *ppVmdkFile = NULL;
    453480        return VERR_NO_MEMORY;
    454481    }
    455482    pVmdkFile->fOpen = fOpen;
    456     rc = RTFileOpen(&pVmdkFile->File, pszFilename, fOpen);
     483    if ((pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) && (fAsyncIO))
     484    {
     485        rc = pImage->pInterfaceAsyncIOCallbacks->pfnOpen(pImage->pInterfaceAsyncIO->pvUser,
     486                                                         pszFilename,
     487                                                         pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY
     488                                                           ? true
     489                                                           : false,
     490                                                         &pVmdkFile->pStorage);
     491        pVmdkFile->fAsyncIO = true;
     492    }
     493    else
     494    {
     495        rc = RTFileOpen(&pVmdkFile->File, pszFilename, fOpen);
     496        pVmdkFile->fAsyncIO = false;
     497    }
    457498    if (VBOX_SUCCESS(rc))
    458499    {
    459500        pVmdkFile->uReferences = 1;
     501        pVmdkFile->pImage = pImage;
    460502        pVmdkFile->pNext = pImage->pFiles;
     503        if (pImage->pFiles)
     504            pImage->pFiles->pPrev = pVmdkFile;
    461505        pImage->pFiles = pVmdkFile;
    462         *pFile = pVmdkFile->File;
     506        *ppVmdkFile = pVmdkFile;
    463507    }
    464508    else
     
    466510        RTStrFree((char *)(void *)pVmdkFile->pszFilename);
    467511        RTMemFree(pVmdkFile);
    468         *pFile = NIL_RTFILE;
     512        *ppVmdkFile = NULL;
    469513    }
    470514
     
    475519 * Internal: close a file, updating the file descriptor cache.
    476520 */
    477 static int vmdkFileClose(PVMDKIMAGE pImage, PRTFILE pFile, bool fDelete)
     521static int vmdkFileClose(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile, bool fDelete)
    478522{
    479523    int rc = VINF_SUCCESS;
    480     RTFILE File;
    481     PVMDKFILE pVmdkFile, pPrev;
    482 
    483     Assert(VALID_PTR(pFile) && *pFile != NIL_RTFILE);
    484     File = *pFile;
    485 
    486     pPrev = NULL;
    487     for (pVmdkFile = pImage->pFiles;
    488          pVmdkFile != NULL;
    489          pVmdkFile = pVmdkFile->pNext)
    490     {
    491         if (File == pVmdkFile->File)
    492         {
    493             pVmdkFile->fDelete |= fDelete;
    494             Assert(pVmdkFile->uReferences);
    495             pVmdkFile->uReferences--;
    496             if (pVmdkFile->uReferences == 0)
    497             {
    498                 /* Unchain the element from the list. */
    499                 if (pPrev == NULL)
    500                     pImage->pFiles = pVmdkFile->pNext;
    501                 else
    502                     pPrev->pNext = pVmdkFile->pNext;
    503                 rc = RTFileClose(File);
    504                 *pFile = NIL_RTFILE;
    505                 if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete)
    506                     rc = RTFileDelete(pVmdkFile->pszFilename);
    507                 RTStrFree((char *)(void *)pVmdkFile->pszFilename);
    508                 RTMemFree(pVmdkFile);
    509             }
    510             return rc;
    511         }
    512         pPrev = pVmdkFile;
    513     }
    514 
    515     AssertMsgFailed(("trying to close unknown file %#p", File));
    516     return VERR_INVALID_PARAMETER;
     524    PVMDKFILE pVmdkFile = *ppVmdkFile;
     525
     526    Assert(VALID_PTR(pVmdkFile));
     527
     528    pVmdkFile->fDelete |= fDelete;
     529    Assert(pVmdkFile->uReferences);
     530    pVmdkFile->uReferences--;
     531    if (pVmdkFile->uReferences == 0)
     532    {
     533        PVMDKFILE pPrev;
     534        PVMDKFILE pNext;
     535
     536        /* Unchain the element from the list. */
     537        pPrev = pVmdkFile->pPrev;
     538        pNext = pVmdkFile->pNext;
     539
     540        if (pNext)
     541            pNext->pPrev = pPrev;
     542        if (pPrev)
     543            pPrev->pNext = pNext;
     544        else
     545            pImage->pFiles = pNext;
     546
     547        if (pVmdkFile->fAsyncIO)
     548        {
     549            rc = pImage->pInterfaceAsyncIOCallbacks->pfnClose(pImage->pInterfaceAsyncIO->pvUser,
     550                                                              pVmdkFile->pStorage);
     551        }
     552        else
     553        {
     554            rc = RTFileClose(pVmdkFile->File);
     555        }
     556        if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete)
     557            rc = RTFileDelete(pVmdkFile->pszFilename);
     558        RTStrFree((char *)(void *)pVmdkFile->pszFilename);
     559        RTMemFree(pVmdkFile);
     560    }
     561
     562    *ppVmdkFile = NULL;
     563    return rc;
     564}
     565
     566/**
     567 * Internal: read from a file distinguishing between async and normal operation
     568 */
     569DECLINLINE(int) vmdkFileReadAt(PVMDKFILE pVmdkFile,
     570                               uint64_t uOffset, void *pvBuf,
     571                               size_t cbToRead, size_t *pcbRead)
     572{
     573    PVMDKIMAGE pImage = pVmdkFile->pImage;
     574
     575    if (pVmdkFile->fAsyncIO)
     576        return pImage->pInterfaceAsyncIOCallbacks->pfnRead(pImage->pInterfaceAsyncIO->pvUser,
     577                                                           pVmdkFile->pStorage, uOffset,
     578                                                           cbToRead, pvBuf, pcbRead);
     579    else
     580        return RTFileReadAt(pVmdkFile->File, uOffset, pvBuf, cbToRead, pcbRead);
     581}
     582
     583/**
     584 * Internal: write to a file distinguishing between async and normal operation
     585 */
     586DECLINLINE(int) vmdkFileWriteAt(PVMDKFILE pVmdkFile,
     587                                uint64_t uOffset, const void *pvBuf,
     588                                size_t cbToWrite, size_t *pcbWritten)
     589{
     590    PVMDKIMAGE pImage = pVmdkFile->pImage;
     591
     592    if (pVmdkFile->fAsyncIO)
     593        return pImage->pInterfaceAsyncIOCallbacks->pfnWrite(pImage->pInterfaceAsyncIO->pvUser,
     594                                                            pVmdkFile->pStorage, uOffset,
     595                                                            cbToWrite, pvBuf, pcbWritten);
     596    else
     597        return RTFileWriteAt(pVmdkFile->File, uOffset, pvBuf, cbToWrite, pcbWritten);
     598}
     599
     600/**
     601 * Internal: get the size of a file distinguishing beween async and normal operation
     602 */
     603DECLINLINE(int) vmdkFileGetSize(PVMDKFILE pVmdkFile, uint64_t *pcbSize)
     604{
     605    if (pVmdkFile->fAsyncIO)
     606    {
     607        AssertMsgFailed(("TODO\n"));
     608        return 0;
     609    }
     610    else
     611        return RTFileGetSize(pVmdkFile->File, pcbSize);
     612}
     613
     614/**
     615 * Internal: set the size of a file distinguishing beween async and normal operation
     616 */
     617DECLINLINE(int) vmdkFileSetSize(PVMDKFILE pVmdkFile, uint64_t cbSize)
     618{
     619    if (pVmdkFile->fAsyncIO)
     620    {
     621        AssertMsgFailed(("TODO\n"));
     622        return VERR_NOT_SUPPORTED;
     623    }
     624    else
     625        return RTFileSetSize(pVmdkFile->File, cbSize);
     626}
     627
     628/**
     629 * Internal: flush a file distinguishing between async and normal operation
     630 */
     631DECLINLINE(int) vmdkFileFlush(PVMDKFILE pVmdkFile)
     632{
     633    PVMDKIMAGE pImage = pVmdkFile->pImage;
     634
     635    if (pVmdkFile->fAsyncIO)
     636        return pImage->pInterfaceAsyncIOCallbacks->pfnFlush(pImage->pInterfaceAsyncIO->pvUser,
     637                                                            pVmdkFile->pStorage);
     638    else
     639        return RTFileFlush(pVmdkFile->File);
    517640}
    518641
     
    533656                pVmdkFile->pszFilename));
    534657        pImage->pFiles = pVmdkFile->pNext;
    535         rc2 = RTFileClose(pVmdkFile->File);
     658
     659        if (pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
     660            rc2 = pImage->pInterfaceAsyncIOCallbacks->pfnClose(pImage->pInterfaceAsyncIO->pvUser,
     661                                                               pVmdkFile->pStorage);
     662        else
     663            rc2 = RTFileClose(pVmdkFile->File);
     664
    536665        if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete)
    537666            rc2 = RTFileDelete(pVmdkFile->pszFilename);
     
    649778    }
    650779    pExtent->pGD = pGD;
    651     rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD),
    652                       pGD, cbGD, NULL);
     780    rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorGD),
     781                        pGD, cbGD, NULL);
    653782    AssertRC(rc);
    654783    if (VBOX_FAILURE(rc))
     
    669798        }
    670799        pExtent->pRGD = pRGD;
    671         rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
    672                           pRGD, cbGD, NULL);
     800        rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
     801                            pRGD, cbGD, NULL);
    673802        AssertRC(rc);
    674803        if (VBOX_FAILURE(rc))
     
    714843                goto out;
    715844            }
    716             rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pGDTmp),
    717                               pTmpGT1, cbGT, NULL);
     845            rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pGDTmp),
     846                                pTmpGT1, cbGT, NULL);
    718847            if (VBOX_FAILURE(rc))
    719848            {
     
    723852                goto out;
    724853            }
    725             rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pRGDTmp),
    726                               pTmpGT2, cbGT, NULL);
     854            rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pRGDTmp),
     855                                pTmpGT2, cbGT, NULL);
    727856            if (VBOX_FAILURE(rc))
    728857            {
     
    782911
    783912    cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
    784     rc = RTFileSetSize(pExtent->File, cbOverhead);
     913    rc = vmdkFileSetSize(pExtent->pFile, cbOverhead);
    785914    if (VBOX_FAILURE(rc))
    786915        goto out;
     
    799928            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    800929            /* Write the redundant grain directory entry to disk. */
    801             rc = RTFileWriteAt(pExtent->File,
    802                                VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
    803                                &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     930            rc = vmdkFileWriteAt(pExtent->pFile,
     931                                 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
     932                                 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    804933            if (VBOX_FAILURE(rc))
    805934                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
     
    813942            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    814943            /* Write the grain directory entry to disk. */
    815             rc = RTFileWriteAt(pExtent->File,
    816                                VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
    817                                &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     944            rc = vmdkFileWriteAt(pExtent->pFile,
     945                                 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
     946                                 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    818947            if (VBOX_FAILURE(rc))
    819948                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
     
    18191948    uint64_t cbLimit;
    18201949    uint64_t uOffset;
    1821     RTFILE DescFile;
     1950    PVMDKFILE pDescFile;
    18221951
    18231952    if (pImage->pDescData)
     
    18261955        uOffset = 0;
    18271956        cbLimit = 0;
    1828         DescFile = pImage->File;
     1957        pDescFile = pImage->pFile;
    18291958    }
    18301959    else
     
    18341963        cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
    18351964        cbLimit += uOffset;
    1836         DescFile = pImage->pExtents[0].File;
     1965        pDescFile = pImage->pExtents[0].pFile;
    18371966    }
    18381967    for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
     
    18431972        if (cbLimit && uOffset + cb + 1 > cbLimit)
    18441973            return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
    1845         rc = RTFileWriteAt(DescFile, uOffset, psz, cb, NULL);
     1974        rc = vmdkFileWriteAt(pDescFile, uOffset, psz, cb, NULL);
    18461975        if (VBOX_FAILURE(rc))
    18471976            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    18481977        uOffset += cb;
    1849         rc = RTFileWriteAt(DescFile, uOffset, "\n", 1, NULL);
     1978        rc = vmdkFileWriteAt(pDescFile, uOffset, "\n", 1, NULL);
    18501979        if (VBOX_FAILURE(rc))
    18511980            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
     
    18571986        while (uOffset < cbLimit)
    18581987        {
    1859             rc = RTFileWriteAt(DescFile, uOffset, "", 1, NULL);
     1988            rc = vmdkFileWriteAt(pDescFile, uOffset, "", 1, NULL);
    18601989            if (VBOX_FAILURE(rc))
    18611990                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
     
    18651994    else
    18661995    {
    1867         rc = RTFileSetSize(DescFile, uOffset);
     1996        rc = vmdkFileSetSize(pDescFile, uOffset);
    18681997        if (VBOX_FAILURE(rc))
    18691998            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
     
    18812010    uint64_t cbExtentSize, cSectorsPerGDE;
    18822011
    1883     int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
     2012    int rc = vmdkFileReadAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
    18842013    AssertRC(rc);
    18852014    if (VBOX_FAILURE(rc))
     
    18962025    /* The image must be a multiple of a sector in size. If not, it means the
    18972026     * image is at least truncated, or even seriously garbled. */
    1898     rc = RTFileGetSize(pExtent->File, &cbExtentSize);
     2027    rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
    18992028    if (VBOX_FAILURE(rc))
    19002029    {
     
    20052134    Header.doubleEndLineChar2 = '\n';
    20062135
    2007     int rc = RTFileWriteAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
     2136    int rc = vmdkFileWriteAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
    20082137    AssertRC(rc);
    20092138    if (VBOX_FAILURE(rc))
     
    20232152    uint64_t cSectorsPerGDE;
    20242153
    2025     int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
     2154    int rc = vmdkFileReadAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
    20262155    AssertRC(rc);
    20272156    if (VBOX_FAILURE(rc))
     
    20932222        pExtent->pDescData = NULL;
    20942223    }
    2095     if (pExtent->File != NIL_RTFILE)
    2096     {
    2097         vmdkFileClose(pImage, &pExtent->File,
     2224    if (pExtent->pFile != NULL)
     2225    {
     2226        vmdkFileClose(pImage, &pExtent->pFile,
    20982227                         fDelete
    20992228                      && pExtent->pszFullname
     
    21572286        for (unsigned i = 0; i < cExtents; i++)
    21582287        {
    2159             pExtents[i].File = NIL_RTFILE;
     2288            pExtents[i].pFile = NULL;
    21602289            pExtents[i].pszBasename = NULL;
    21612290            pExtents[i].pszFullname = NULL;
     
    21822311    int rc;
    21832312    uint32_t u32Magic;
    2184     RTFILE File;
     2313    PVMDKFILE pFile;
    21852314    PVMDKEXTENT pExtent;
    21862315
     
    21892318    /*
    21902319     * Open the image.
     2320     * We don't have to check for asynchronous access because
     2321     * we only support raw access and the opened file is a description
     2322     * file were no data is stored.
    21912323     */
    2192     rc = vmdkFileOpen(pImage, &File, pImage->pszFilename,
     2324    rc = vmdkFileOpen(pImage, &pFile, pImage->pszFilename,
    21932325                      uOpenFlags & VD_OPEN_FLAGS_READONLY
    21942326                       ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
    2195                        : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2327                       : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
    21962328    if (VBOX_FAILURE(rc))
    21972329    {
     
    22002332        goto out;
    22012333    }
    2202     pImage->File = File;
     2334    pImage->pFile = pFile;
    22032335
    22042336    /* Read magic (if present). */
    2205     rc = RTFileReadAt(File, 0, &u32Magic, sizeof(u32Magic), NULL);
     2337    rc = vmdkFileReadAt(pFile, 0, &u32Magic, sizeof(u32Magic), NULL);
    22062338    if (VBOX_FAILURE(rc))
    22072339    {
     
    22202352         * file, so no need to keep anything open for the image. */
    22212353        pExtent = &pImage->pExtents[0];
    2222         pExtent->File = File;
    2223         pImage->File = NIL_RTFILE;
     2354        pExtent->pFile = pFile;
     2355        pImage->pFile = NULL;
    22242356        pExtent->pszFullname = RTStrDup(pImage->pszFilename);
    22252357        if (!pExtent->pszFullname)
     
    22452377            goto out;
    22462378        }
    2247         rc = RTFileReadAt(pExtent->File,
    2248                           VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
    2249                           pExtent->pDescData,
    2250                           VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);
     2379        rc = vmdkFileReadAt(pExtent->pFile,
     2380                            VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
     2381                            pExtent->pDescData,
     2382                            VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);
    22512383        AssertRC(rc);
    22522384        if (VBOX_FAILURE(rc))
     
    22792411
    22802412        size_t cbRead;
    2281         rc = RTFileReadAt(pImage->File, 0, pImage->pDescData,
    2282                           pImage->cbDescAlloc, &cbRead);
     2413        rc = vmdkFileReadAt(pImage->pFile, 0, pImage->pDescData,
     2414                            pImage->cbDescAlloc, &cbRead);
    22832415        if (VBOX_FAILURE(rc))
    22842416        {
     
    22982430        if (VBOX_FAILURE(rc))
    22992431            goto out;
     2432
     2433        /*
     2434         * We have to check for the asynchronous open flag. The
     2435         * extents are parsed and the type of all are known now.
     2436         * Check if every extent is either FLAT or ZERO.
     2437         */
     2438        if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
     2439        {
     2440            for (unsigned i = 0; i < pImage->cExtents; i++)
     2441            {
     2442                PVMDKEXTENT pExtent = &pImage->pExtents[i];
     2443
     2444                if (   (pExtent->enmType != VMDKETYPE_FLAT)
     2445                    && (pExtent->enmType != VMDKETYPE_ZERO))
     2446                {
     2447                    /*
     2448                     * Opened image contains at least one none flat or zero extent.
     2449                     * Return error but don't set error message as the caller
     2450                     * has the chance to open in non async I/O mode.
     2451                     */
     2452                    rc = VERR_NOT_SUPPORTED;
     2453                    goto out;
     2454                }
     2455            }
     2456        }
    23002457
    23012458        for (unsigned i = 0; i < pImage->cExtents; i++)
     
    23442501            {
    23452502                case VMDKETYPE_HOSTED_SPARSE:
    2346                     rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
     2503                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
    23472504                                      uOpenFlags & VD_OPEN_FLAGS_READONLY
    23482505                                        ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
    2349                                         : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2506                                        : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
    23502507                    if (VBOX_FAILURE(rc))
    23512508                    {
     
    23672524                    break;
    23682525                case VMDKETYPE_FLAT:
    2369                     rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
     2526                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
    23702527                                      uOpenFlags & VD_OPEN_FLAGS_READONLY
    23712528                                        ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
    2372                                         : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2529                                        : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, true);
    23732530                    if (VBOX_FAILURE(rc))
    23742531                    {
     
    24692626        pExtent = &pImage->pExtents[0];
    24702627        /* Create raw disk descriptor file. */
    2471         rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename,
    2472                           RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
     2628        rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
     2629                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
     2630                          false);
    24732631        if (VBOX_FAILURE(rc))
    24742632            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
     
    24922650
    24932651        /* Open flat image, the raw disk. */
    2494         rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
    2495                           RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2652        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     2653                          RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
    24962654        if (VBOX_FAILURE(rc))
    24972655            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
     
    25412699
    25422700        /* Create raw partition descriptor file. */
    2543         rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename,
    2544                           RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
     2701        rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
     2702                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
     2703                          false);
    25452704        if (VBOX_FAILURE(rc))
    25462705            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
     
    26122771
    26132772                /* Create partition table flat image. */
    2614                 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
    2615                                   RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
     2773                rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     2774                                  RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
     2775                                  false);
    26162776                if (VBOX_FAILURE(rc))
    26172777                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
    2618                 rc = RTFileWriteAt(pExtent->File,
    2619                                    VMDK_SECTOR2BYTE(uPartOffset),
    2620                                    pPart->pvPartitionData,
    2621                                    pPart->cbPartitionData, NULL);
     2778                rc = vmdkFileWriteAt(pExtent->pFile,
     2779                                     VMDK_SECTOR2BYTE(uPartOffset),
     2780                                     pPart->pvPartitionData,
     2781                                     pPart->cbPartitionData, NULL);
    26222782                if (VBOX_FAILURE(rc))
    26232783                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
     
    26592819
    26602820                    /* Open flat image, the raw partition. */
    2661                     rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
    2662                                       RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2821                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     2822                                      RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE,
     2823                                      false);
    26632824                    if (VBOX_FAILURE(rc))
    26642825                        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
     
    27312892    if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED)
    27322893    {
    2733         rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename,
    2734                           RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
     2894        rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
     2895                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
     2896                          false);
    27352897        if (VBOX_FAILURE(rc))
    27362898            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename);
     
    27382900    }
    27392901    else
    2740         pImage->File = NIL_RTFILE;
     2902        pImage->pFile = NULL;
    27412903
    27422904    /* Set up all extents. */
     
    28012963
    28022964        /* Create file for extent. */
    2803         rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
    2804                           RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
     2965        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     2966                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
     2967                          false);
    28052968        if (VBOX_FAILURE(rc))
    28062969            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
    28072970        if (enmType == VD_IMAGE_TYPE_FIXED)
    28082971        {
    2809             rc = RTFileSetSize(pExtent->File, cbExtent);
     2972            rc = vmdkFileSetSize(pExtent->pFile, cbExtent);
    28102973            if (VBOX_FAILURE(rc))
    28112974                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
     
    28302993                unsigned cbChunk = (unsigned)RT_MIN(cbExtent, cbBuf);
    28312994
    2832                 rc = RTFileWriteAt(pExtent->File, uOff, pvBuf, cbChunk, NULL);
     2995                rc = vmdkFileWriteAt(pExtent->pFile, uOff, pvBuf, cbChunk, NULL);
    28332996                if (VBOX_FAILURE(rc))
    28342997                {
     
    31403303        pImage->pExtents = NULL;
    31413304    }
    3142     if (pImage->File != NIL_RTFILE)
    3143         vmdkFileClose(pImage, &pImage->File, fDelete);
     3305    if (pImage->pFile != NULL)
     3306        vmdkFileClose(pImage, &pImage->pFile, fDelete);
    31443307    vmdkFileCheckAllClose(pImage);
    31453308}
     
    31643327    {
    31653328        pExtent = &pImage->pExtents[i];
    3166         if (pExtent->File != NIL_RTFILE && pExtent->fMetaDirty)
     3329        if (pExtent->pFile != NULL && pExtent->fMetaDirty)
    31673330        {
    31683331            switch (pExtent->enmType)
     
    31963359            case VMDKETYPE_FLAT:
    31973360                /** @todo implement proper path absolute check. */
    3198                 if (   pExtent->File != NIL_RTFILE
     3361                if (   pExtent->pFile != NULL
    31993362                    && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    32003363                    && !(pExtent->pszBasename[0] == RTPATH_SLASH))
    3201                     rc = RTFileFlush(pExtent->File);
     3364                    rc = vmdkFileFlush(pExtent->pFile);
    32023365                break;
    32033366            case VMDKETYPE_ZERO:
     
    32853448    {
    32863449        /* Cache miss, fetch data from disk. */
    3287         rc = RTFileReadAt(pExtent->File,
    3288                           VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3289                           aGTDataTmp, sizeof(aGTDataTmp), NULL);
     3450        rc = vmdkFileReadAt(pExtent->pFile,
     3451                            VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     3452                            aGTDataTmp, sizeof(aGTDataTmp), NULL);
    32903453        if (VBOX_FAILURE(rc))
    32913454            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
     
    33343497         * entry. So there is absolutely no data in this area. Allocate
    33353498         * a new grain table and put the reference to it in the GDs. */
    3336         rc = RTFileGetSize(pExtent->File, &cbExtentSize);
     3499        rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
    33373500        if (VBOX_FAILURE(rc))
    33383501            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     
    33533516             i++)
    33543517        {
    3355             rc = RTFileWriteAt(pExtent->File,
    3356                                VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
    3357                                aGTDataTmp, sizeof(aGTDataTmp), NULL);
     3518            rc = vmdkFileWriteAt(pExtent->pFile,
     3519                                 VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
     3520                                 aGTDataTmp, sizeof(aGTDataTmp), NULL);
    33583521            if (VBOX_FAILURE(rc))
    33593522                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
     
    33623525        {
    33633526            AssertReturn(!uRGTSector, VERR_VDI_INVALID_HEADER);
    3364             rc = RTFileGetSize(pExtent->File, &cbExtentSize);
     3527            rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
    33653528            if (VBOX_FAILURE(rc))
    33663529                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     
    33803543                 i++)
    33813544            {
    3382                 rc = RTFileWriteAt(pExtent->File,
    3383                                    VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
    3384                                    aGTDataTmp, sizeof(aGTDataTmp), NULL);
     3545                rc = vmdkFileWriteAt(pExtent->pFile,
     3546                                     VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
     3547                                     aGTDataTmp, sizeof(aGTDataTmp), NULL);
    33853548                if (VBOX_FAILURE(rc))
    33863549                    return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
     
    33933556         * some unused sectors in the extent. */
    33943557        uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
    3395         rc = RTFileWriteAt(pExtent->File,
    3396                            VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
    3397                            &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     3558        rc = vmdkFileWriteAt(pExtent->pFile,
     3559                             VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
     3560                             &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    33983561        if (VBOX_FAILURE(rc))
    33993562            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
     
    34013564        {
    34023565            uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
    3403             rc = RTFileWriteAt(pExtent->File,
    3404                                VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
    3405                                &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
     3566            rc = vmdkFileWriteAt(pExtent->pFile,
     3567                                 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
     3568                                 &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
    34063569            if (VBOX_FAILURE(rc))
    34073570                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
     
    34143577    }
    34153578
    3416     rc = RTFileGetSize(pExtent->File, &cbExtentSize);
     3579    rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
    34173580    if (VBOX_FAILURE(rc))
    34183581        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     
    34203583
    34213584    /* Write the data. */
    3422     rc = RTFileWriteAt(pExtent->File, cbExtentSize, pvBuf, cbWrite, NULL);
     3585    rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL);
    34233586    if (VBOX_FAILURE(rc))
    34243587        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
     
    34323595    {
    34333596        /* Cache miss, fetch data from disk. */
    3434         rc = RTFileReadAt(pExtent->File,
    3435                           VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3436                           aGTDataTmp, sizeof(aGTDataTmp), NULL);
     3597        rc = vmdkFileReadAt(pExtent->pFile,
     3598                            VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     3599                            aGTDataTmp, sizeof(aGTDataTmp), NULL);
    34373600        if (VBOX_FAILURE(rc))
    34383601            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
     
    34533616    pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(cbExtentSize);
    34543617    /* Update grain table on disk. */
    3455     rc = RTFileWriteAt(pExtent->File,
    3456                        VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3457                        aGTDataTmp, sizeof(aGTDataTmp), NULL);
     3618    rc = vmdkFileWriteAt(pExtent->pFile,
     3619                         VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     3620                         aGTDataTmp, sizeof(aGTDataTmp), NULL);
    34583621    if (VBOX_FAILURE(rc))
    34593622        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
     
    34613624    {
    34623625        /* Update backup grain table on disk. */
    3463         rc = RTFileWriteAt(pExtent->File,
    3464                            VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3465                            aGTDataTmp, sizeof(aGTDataTmp), NULL);
     3626        rc = vmdkFileWriteAt(pExtent->pFile,
     3627                             VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     3628                             aGTDataTmp, sizeof(aGTDataTmp), NULL);
    34663629        if (VBOX_FAILURE(rc))
    34673630            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
     
    35003663    }
    35013664    pImage->pszFilename = pszFilename;
    3502     pImage->File = NIL_RTFILE;
     3665    pImage->pFile = NULL;
    35033666    pImage->pExtents = NULL;
    35043667    pImage->pFiles = NULL;
    35053668    pImage->pGTCache = NULL;
    35063669    pImage->pDescData = NULL;
    3507     pImage->pfnError = NULL;
    3508     pImage->pvErrorUser = NULL;
     3670    pImage->pInterfaceError = NULL;
     3671    pImage->pInterfaceErrorCallbacks = NULL;
    35093672    /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
    35103673     * much as possible in vmdkOpenImage. */
     
    35193682/** @copydoc VBOXHDDBACKEND::pfnOpen */
    35203683static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
    3521                     PFNVDERROR pfnError, void *pvErrorUser,
     3684                    PVDINTERFACE pInterfaces,
    35223685                    void **ppBackendData)
    35233686{
     
    35503713    }
    35513714    pImage->pszFilename = pszFilename;
    3552     pImage->File = NIL_RTFILE;
     3715    pImage->pFile = NULL;
    35533716    pImage->pExtents = NULL;
    35543717    pImage->pFiles = NULL;
    35553718    pImage->pGTCache = NULL;
    35563719    pImage->pDescData = NULL;
    3557     pImage->pfnError = pfnError;
    3558     pImage->pvErrorUser = pvErrorUser;
     3720    pImage->pInterfaceError = NULL;
     3721    pImage->pInterfaceErrorCallbacks = NULL;
     3722
     3723    /* Try to get error interface. */
     3724    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
     3725    if (pImage->pInterfaceError)
     3726        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks);
     3727
     3728    /* Try to get async I/O interfaec. */
     3729    pImage->pInterfaceAsyncIO = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ASYNCIO);
     3730    if (pImage->pInterfaceAsyncIO)
     3731        pImage->pInterfaceAsyncIOCallbacks = VDGetInterfaceAsyncIO(pImage->pInterfaceAsyncIO->pCallbacks);
     3732
    35593733
    35603734    rc = vmdkOpenImage(pImage, uOpenFlags);
     
    35753749                      unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
    35763750                      void *pvUser, unsigned uPercentStart,
    3577                       unsigned uPercentSpan, PFNVDERROR pfnError,
    3578                       void *pvErrorUser, void **ppBackendData)
    3579 {
    3580     LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
     3751                      unsigned uPercentSpan, PVDINTERFACE pInterfaces,
     3752                      void **ppBackendData)
     3753{
     3754    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData));
    35813755    int rc;
    35823756    PVMDKIMAGE pImage;
     
    36123786    }
    36133787    pImage->pszFilename = pszFilename;
    3614     pImage->File = NIL_RTFILE;
     3788    pImage->pFile = NULL;
    36153789    pImage->pExtents = NULL;
    36163790    pImage->pFiles = NULL;
    36173791    pImage->pGTCache = NULL;
    36183792    pImage->pDescData = NULL;
    3619     pImage->pfnError = pfnError;
    3620     pImage->pvErrorUser = pvErrorUser;
     3793    pImage->pInterfaceError = NULL;
     3794    pImage->pInterfaceErrorCallbacks = NULL;
    36213795    pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
    36223796    pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
     
    36263800        goto out;
    36273801    }
     3802
     3803    /* Get error interface. */
     3804    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
     3805    if (pImage->pInterfaceError)
     3806        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
    36283807
    36293808    rc = vmdkCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
     
    37803959            goto rollback;
    37813960        /* Close the extent file. */
    3782         vmdkFileClose(pImage, &pExtent->File, false);
     3961        vmdkFileClose(pImage, &pExtent->pFile, false);
    37833962        /* Rename the extent file. */
    37843963        rc = RTFileMove(pExtent->pszFullname, apszNewName[i], 0);
     
    38464025        }
    38474026        /* Restore the old descriptor. */
    3848         RTFILE File;
    3849         rrc = RTFileOpen(&File, pszOldDescName,
    3850             RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     4027        PVMDKFILE pFile;
     4028        rrc = vmdkFileOpen(pImage, &pFile, pszOldDescName,
     4029            RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
    38514030        AssertRC(rrc);
    38524031        if (fEmbeddedDesc)
    38534032        {
    3854             ExtentCopy.File   = File;
     4033            ExtentCopy.pFile   = pFile;
    38554034            pImage->pExtents = &ExtentCopy;
    38564035        }
    38574036        else
    3858             pImage->File = File;
     4037            pImage->pFile = pFile;
    38594038        pImage->Descriptor = DescriptorCopy;
    38604039        vmdkWriteDescriptor(pImage);
    3861         RTFileClose(File);
     4040        vmdkFileClose(pImage, &pFile, false);
    38624041        RTStrFree(pszOldDescName);
    38634042        /* Re-open the image back. */
     
    39504129                rc = VERR_VDI_BLOCK_FREE;
    39514130            else
    3952                 rc = RTFileReadAt(pExtent->File,
    3953                                   VMDK_SECTOR2BYTE(uSectorExtentAbs),
    3954                                   pvBuf, cbToRead, NULL);
     4131                rc = vmdkFileReadAt(pExtent->pFile,
     4132                                    VMDK_SECTOR2BYTE(uSectorExtentAbs),
     4133                                    pvBuf, cbToRead, NULL);
    39554134            break;
    39564135        case VMDKETYPE_FLAT:
    3957             rc = RTFileReadAt(pExtent->File,
    3958                               VMDK_SECTOR2BYTE(uSectorExtentRel),
    3959                               pvBuf, cbToRead, NULL);
     4136            rc = vmdkFileReadAt(pExtent->pFile,
     4137                                VMDK_SECTOR2BYTE(uSectorExtentRel),
     4138                                pvBuf, cbToRead, NULL);
    39604139            break;
    39614140        case VMDKETYPE_ZERO:
     
    40574236            }
    40584237            else
    4059                 rc = RTFileWriteAt(pExtent->File,
    4060                                    VMDK_SECTOR2BYTE(uSectorExtentAbs),
    4061                                    pvBuf, cbToWrite, NULL);
     4238                rc = vmdkFileWriteAt(pExtent->pFile,
     4239                                     VMDK_SECTOR2BYTE(uSectorExtentAbs),
     4240                                     pvBuf, cbToWrite, NULL);
    40624241            break;
    40634242        case VMDKETYPE_FLAT:
    40644243            /* Clip write range to remain in this extent. */
    40654244            cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    4066             rc = RTFileWriteAt(pExtent->File,
    4067                                VMDK_SECTOR2BYTE(uSectorExtentRel),
    4068                                pvBuf, cbToWrite, NULL);
     4245            rc = vmdkFileWriteAt(pExtent->pFile,
     4246                                 VMDK_SECTOR2BYTE(uSectorExtentRel),
     4247                                 pvBuf, cbToWrite, NULL);
    40694248            break;
    40704249        case VMDKETYPE_ZERO:
     
    41544333    {
    41554334        uint64_t cbFile;
    4156         if (pImage->File != NIL_RTFILE)
    4157         {
    4158             int rc = RTFileGetSize(pImage->File, &cbFile);
     4335        if (pImage->pFile != NULL)
     4336        {
     4337            int rc = vmdkFileGetSize(pImage->pFile, &cbFile);
    41594338            if (VBOX_SUCCESS(rc))
    41604339                cb += cbFile;
    41614340            for (unsigned i = 0; i <= pImage->cExtents; i++)
    41624341            {
    4163                 rc = RTFileGetSize(pImage->File, &cbFile);
     4342                rc = vmdkFileGetSize(pImage->pFile, &cbFile);
    41644343                if (VBOX_SUCCESS(rc))
    41654344                    cb += cbFile;
     
    43364515    /* Image must be opened and the new flags must be valid. Just readonly flag
    43374516     * is supported. */
    4338     if (!pImage || uOpenFlags & ~VD_OPEN_FLAGS_READONLY)
     4517    if (!pImage || uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_ASYNC_IO))
    43394518    {
    43404519        rc = VERR_INVALID_PARAMETER;
     
    46724851}
    46734852
     4853static bool vmdkIsAsyncIOSupported(void *pvBackendData)
     4854{
     4855    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     4856    bool fAsyncIOSupported = false;
     4857
     4858    if (pImage)
     4859    {
     4860        /* We only support async I/O support if the image only consists of FLAT or ZERO extents. */
     4861        fAsyncIOSupported = true;
     4862        for (unsigned i = 0; i < pImage->cExtents; i++)
     4863        {
     4864            if (   (pImage->pExtents[i].enmType != VMDKETYPE_FLAT)
     4865                && (pImage->pExtents[i].enmType != VMDKETYPE_ZERO))
     4866            {
     4867                fAsyncIOSupported = false;
     4868                break; /* Stop search */
     4869            }
     4870        }
     4871    }
     4872
     4873    return fAsyncIOSupported;
     4874}
     4875
     4876static int vmdkAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
     4877                         PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
     4878{
     4879    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     4880    PVMDKEXTENT pExtent;
     4881    int rc = VINF_SUCCESS;
     4882    unsigned cTasksToSubmit = 0;
     4883    PPDMDATASEG paSegCurrent = paSeg;
     4884    unsigned  cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     4885    unsigned  uOffsetInCurrentSegment = 0;
     4886
     4887    Assert(pImage);
     4888    Assert(uOffset % 512 == 0);
     4889    Assert(cbRead % 512 == 0);
     4890
     4891    if (   uOffset + cbRead > pImage->cbSize
     4892        || cbRead == 0)
     4893    {
     4894        rc = VERR_INVALID_PARAMETER;
     4895        goto out;
     4896    }
     4897
     4898    while (cbRead && cSeg)
     4899    {
     4900        unsigned cbToRead;
     4901        uint64_t uSectorExtentRel;
     4902
     4903        rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
     4904                            &pExtent, &uSectorExtentRel);
     4905        if (VBOX_FAILURE(rc))
     4906            goto out;
     4907
     4908        /* Check access permissions as defined in the extent descriptor. */
     4909        if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
     4910        {
     4911            rc = VERR_VDI_INVALID_STATE;
     4912            goto out;
     4913        }
     4914
     4915        /* Clip read range to remain in this extent. */
     4916        cbToRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     4917        /* Clip read range to remain into current data segment. */
     4918        cbToRead = RT_MIN(cbToRead, cbLeftInCurrentSegment);
     4919
     4920        switch (pExtent->enmType)
     4921        {
     4922            case VMDKETYPE_FLAT:
     4923            {
     4924                /* Setup new task. */
     4925                void *pTask;
     4926                rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareRead(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage,
     4927                                                                       VMDK_SECTOR2BYTE(uSectorExtentRel),
     4928                                                                       (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment,
     4929                                                                       cbToRead, &pTask);
     4930                if (VBOX_FAILURE(rc))
     4931                {
     4932                    AssertMsgFailed(("Preparing read failed rc=%Vrc\n", rc));
     4933                    goto out;
     4934                }
     4935
     4936                /* Check for enough room first. */
     4937                if (cTasksToSubmit >= pImage->cTask)
     4938                {
     4939                    /* We reached maximum, resize array. Try to realloc memory first. */
     4940                    void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *));
     4941
     4942                    if (!apTaskNew)
     4943                    {
     4944                        /* We failed. Allocate completely new. */
     4945                        apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *));
     4946                        if (!apTaskNew)
     4947                        {
     4948                            /* Damn, we are out of memory. */
     4949                            rc = VERR_NO_MEMORY;
     4950                            goto out;
     4951                        }
     4952
     4953                        /* Copy task handles over. */
     4954                        for (unsigned i = 0; i < cTasksToSubmit; i++)
     4955                            apTaskNew[i] = pImage->apTask[i];
     4956
     4957                        /* Free old memory. */
     4958                        RTMemFree(pImage->apTask);
     4959                    }
     4960
     4961                    pImage->cTask = cTasksToSubmit + 10;
     4962                    pImage->apTask = apTaskNew;
     4963                }
     4964
     4965                pImage->apTask[cTasksToSubmit] = pTask;
     4966                cTasksToSubmit++;
     4967                break;
     4968            }
     4969            case VMDKETYPE_ZERO:
     4970                memset((uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 0, cbToRead);
     4971                break;
     4972            default:
     4973                AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType));
     4974        }
     4975
     4976        cbRead  -= cbToRead;
     4977        uOffset += cbToRead;
     4978        cbLeftInCurrentSegment -= cbToRead;
     4979        uOffsetInCurrentSegment += cbToRead;
     4980        /* Go to next extent if there is no space left in current one. */
     4981        if (!cbLeftInCurrentSegment)
     4982        {
     4983            uOffsetInCurrentSegment = 0;
     4984            paSegCurrent++;
     4985            cSeg--;
     4986            cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     4987        }
     4988    }
     4989
     4990    AssertMsg((cSeg >= 0) && (cbRead == 0), ("No segment left but there is still data to read\n"));
     4991
     4992    if (cTasksToSubmit == 0)
     4993    {
     4994        /* The request was completely in a ZERO extent nothing to do. */
     4995        rc = VINF_VDI_ASYNC_IO_FINISHED;
     4996    }
     4997    else
     4998    {
     4999        /* Submit tasks. */
     5000        rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser,
     5001                                                                pImage->apTask, cTasksToSubmit,
     5002                                                                NULL, pvUser,
     5003                                                                NULL /* Nothing required after read. */);
     5004        AssertMsg(VBOX_SUCCESS(rc), ("Failed to enqueue tasks rc=%Vrc\n", rc));
     5005    }
     5006
     5007out:
     5008    LogFlowFunc(("returns %Vrc\n", rc));
     5009    return rc;
     5010}
     5011
     5012static int vmdkAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     5013                          PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
     5014{
     5015    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     5016    PVMDKEXTENT pExtent;
     5017    int rc = VINF_SUCCESS;
     5018    unsigned cTasksToSubmit = 0;
     5019    PPDMDATASEG paSegCurrent = paSeg;
     5020    unsigned  cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     5021    unsigned  uOffsetInCurrentSegment = 0;
     5022
     5023    Assert(pImage);
     5024    Assert(uOffset % 512 == 0);
     5025    Assert(cbWrite % 512 == 0);
     5026
     5027    if (   uOffset + cbWrite > pImage->cbSize
     5028        || cbWrite == 0)
     5029    {
     5030        rc = VERR_INVALID_PARAMETER;
     5031        goto out;
     5032    }
     5033
     5034    while (cbWrite && cSeg)
     5035    {
     5036        unsigned cbToWrite;
     5037        uint64_t uSectorExtentRel;
     5038
     5039        rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
     5040                            &pExtent, &uSectorExtentRel);
     5041        if (VBOX_FAILURE(rc))
     5042            goto out;
     5043
     5044        /* Check access permissions as defined in the extent descriptor. */
     5045        if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
     5046        {
     5047            rc = VERR_VDI_INVALID_STATE;
     5048            goto out;
     5049        }
     5050
     5051        /* Clip write range to remain in this extent. */
     5052        cbToWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     5053        /* Clip write range to remain into current data segment. */
     5054        cbToWrite = RT_MIN(cbToWrite, cbLeftInCurrentSegment);
     5055
     5056        switch (pExtent->enmType)
     5057        {
     5058            case VMDKETYPE_FLAT:
     5059            {
     5060                /* Setup new task. */
     5061                void *pTask;
     5062                rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareWrite(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage,
     5063                                                                         VMDK_SECTOR2BYTE(uSectorExtentRel),
     5064                                                                         (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment,
     5065                                                                         cbToWrite, &pTask);
     5066                if (VBOX_FAILURE(rc))
     5067                {
     5068                    AssertMsgFailed(("Preparing read failed rc=%Vrc\n", rc));
     5069                    goto out;
     5070                }
     5071
     5072                /* Check for enough room first. */
     5073                if (cTasksToSubmit >= pImage->cTask)
     5074                {
     5075                    /* We reached maximum, resize array. Try to realloc memory first. */
     5076                    void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *));
     5077
     5078                    if (!apTaskNew)
     5079                    {
     5080                        /* We failed. Allocate completely new. */
     5081                        apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *));
     5082                        if (!apTaskNew)
     5083                        {
     5084                            /* Damn, we are out of memory. */
     5085                            rc = VERR_NO_MEMORY;
     5086                            goto out;
     5087                        }
     5088
     5089                        /* Copy task handles over. */
     5090                        for (unsigned i = 0; i < cTasksToSubmit; i++)
     5091                            apTaskNew[i] = pImage->apTask[i];
     5092
     5093                        /* Free old memory. */
     5094                        RTMemFree(pImage->apTask);
     5095                    }
     5096
     5097                    pImage->cTask = cTasksToSubmit + 10;
     5098                    pImage->apTask = apTaskNew;
     5099                }
     5100
     5101                pImage->apTask[cTasksToSubmit] = pTask;
     5102                cTasksToSubmit++;
     5103                break;
     5104            }
     5105            case VMDKETYPE_ZERO:
     5106                /* Nothing left to do. */
     5107                break;
     5108            default:
     5109                AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType));
     5110        }
     5111
     5112        cbWrite  -= cbToWrite;
     5113        uOffset  += cbToWrite;
     5114        cbLeftInCurrentSegment -= cbToWrite;
     5115        uOffsetInCurrentSegment += cbToWrite;
     5116        /* Go to next extent if there is no space left in current one. */
     5117        if (!cbLeftInCurrentSegment)
     5118        {
     5119            uOffsetInCurrentSegment = 0;
     5120            paSegCurrent++;
     5121            cSeg--;
     5122            cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     5123        }
     5124    }
     5125
     5126    AssertMsg((cSeg >= 0) && (cbWrite == 0), ("No segment left but there is still data to read\n"));
     5127
     5128    if (cTasksToSubmit == 0)
     5129    {
     5130        /* The request was completely in a ZERO extent nothing to do. */
     5131        rc = VINF_VDI_ASYNC_IO_FINISHED;
     5132    }
     5133    else
     5134    {
     5135        /* Submit tasks. */
     5136        rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser,
     5137                                                                pImage->apTask, cTasksToSubmit,
     5138                                                                NULL, pvUser,
     5139                                                                NULL /* Nothing required after read. */);
     5140        AssertMsg(VBOX_SUCCESS(rc), ("Failed to enqueue tasks rc=%Vrc\n", rc));
     5141    }
     5142
     5143out:
     5144    LogFlowFunc(("returns %Vrc\n", rc));
     5145    return rc;
     5146
     5147}
     5148
     5149
    46745150VBOXHDDBACKEND g_VmdkBackend =
    46755151{
     
    46805156    /* uBackendCaps */
    46815157      VD_CAP_UUID | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC
    4682     | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE,
     5158    | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE |VD_CAP_ASYNC,
    46835159    /* pfnCheckIfValid */
    46845160    vmdkCheckIfValid,
     
    47505226    vmdkGetParentFilename,
    47515227    /* pfnSetParentFilename */
    4752     vmdkSetParentFilename
     5228    vmdkSetParentFilename,
     5229    /* pfnIsAsyncIOSupported */
     5230    vmdkIsAsyncIOSupported,
     5231    /* pfnAsyncRead */
     5232    vmdkAsyncRead,
     5233    /* pfnAsyncWrite */
     5234    vmdkAsyncWrite
    47535235};
  • trunk/src/VBox/Devices/Storage/testcase/tstVD.cpp

    r9734 r10715  
    5656    PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
    5757    PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
     58    VDINTERFACE      VDIError;
     59    VDINTERFACEERROR VDIErrorCallbacks;
    5860
    5961#define CHECK(str) \
     
    6870    } while (0)
    6971
    70     rc = VDCreate(tstVDError, NULL, &pVD);
     72    /* Create error interface. */
     73    VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
     74    VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     75    VDIErrorCallbacks.pfnError = tstVDError;
     76
     77    rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
     78                           NULL, NULL);
     79    AssertRC(rc);
     80
     81    rc = VDCreate(&VDIError, &pVD);
    7182    CHECK("VDCreate()");
    7283
     
    420431    uint64_t u64DiskSize  = 1000 * _1M;
    421432    uint32_t u32SectorSize = 512;
     433    VDINTERFACE      VDIError;
     434    VDINTERFACEERROR VDIErrorCallbacks;
    422435
    423436#define CHECK(str) \
     
    432445    } while (0)
    433446
    434     rc = VDCreate(tstVDError, NULL, &pVD);
     447    /* Create error interface. */
     448    VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
     449    VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     450    VDIErrorCallbacks.pfnError = tstVDError;
     451
     452    rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
     453                           NULL, NULL);
     454    AssertRC(rc);
     455
     456
     457    rc = VDCreate(&VDIError, &pVD);
    435458    CHECK("VDCreate()");
    436459
     
    526549    uint64_t u64DiskSize  = 1000 * _1M;
    527550    uint32_t u32SectorSize = 512;
     551    VDINTERFACE      VDIError;
     552    VDINTERFACEERROR VDIErrorCallbacks;
    528553
    529554#define CHECK(str) \
     
    538563    } while (0)
    539564
    540     rc = VDCreate(tstVDError, NULL, &pVD);
     565    /* Create error interface. */
     566    VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
     567    VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     568    VDIErrorCallbacks.pfnError = tstVDError;
     569
     570    rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
     571                           NULL, NULL);
     572    AssertRC(rc);
     573
     574
     575    rc = VDCreate(&VDIError, &pVD);
    541576    CHECK("VDCreate()");
    542577
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp

    r9387 r10715  
    908908    GEN_CHECK_OFF(AHCIPort, u32TasksFinished);
    909909    GEN_CHECK_OFF(AHCIPort, u32QueuedTasksFinished);
     910    GEN_CHECK_OFF(AHCIPort, StatDMA);
     911    GEN_CHECK_OFF(AHCIPort, StatBytesWritten);
     912    GEN_CHECK_OFF(AHCIPort, StatBytesRead);
     913    GEN_CHECK_OFF(AHCIPort, StatQueueFillRate);
    910914
    911915    GEN_CHECK_SIZE(AHCI);
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