VirtualBox

Ignore:
Timestamp:
Jul 16, 2008 10:38:23 PM (16 years ago)
Author:
vboxsync
Message:

Merge async I/O for VMDK backend from private branch

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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};
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