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/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};
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