diff options
Diffstat (limited to 'src/VBox/Storage/QED.cpp')
-rw-r--r-- | src/VBox/Storage/QED.cpp | 598 |
1 files changed, 183 insertions, 415 deletions
diff --git a/src/VBox/Storage/QED.cpp b/src/VBox/Storage/QED.cpp index f27957d0..681a8a56 100644 --- a/src/VBox/Storage/QED.cpp +++ b/src/VBox/Storage/QED.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -580,7 +580,7 @@ static int qedL2TblCacheFetch(PQEDIMAGE pImage, uint64_t offL2Tbl, PQEDL2CACHEEN /* Read from the image. */ pL2Entry->offL2Tbl = offL2Tbl; rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offL2Tbl, - pL2Entry->paL2Tbl, pImage->cbTable, NULL); + pL2Entry->paL2Tbl, pImage->cbTable); if (RT_SUCCESS(rc)) { #if defined(RT_BIG_ENDIAN) @@ -632,10 +632,10 @@ static int qedL2TblCacheFetchAsync(PQEDIMAGE pImage, PVDIOCTX pIoCtx, PVDMETAXFER pMetaXfer; pL2Entry->offL2Tbl = offL2Tbl; - rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pImage->pStorage, - offL2Tbl, pL2Entry->paL2Tbl, - pImage->cbTable, pIoCtx, - &pMetaXfer, NULL, NULL); + rc = vdIfIoIntFileReadMeta(pImage->pIfIo, pImage->pStorage, + offL2Tbl, pL2Entry->paL2Tbl, + pImage->cbTable, pIoCtx, + &pMetaXfer, NULL, NULL); if (RT_SUCCESS(rc)) { vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer); @@ -702,7 +702,7 @@ static void qedTableMasksInit(PQEDIMAGE pImage) } /** - * Converts a given logical offset into the + * Converts a given logical offset into the * * @returns nothing. * @param pImage The image instance data. @@ -771,59 +771,15 @@ DECLINLINE(uint64_t) qedClusterAllocate(PQEDIMAGE pImage, uint32_t cClusters) * @returns VBox status code. * VERR_VD_BLOCK_FREE if the cluster is not yet allocated. * @param pImage The image instance data. - * @param idxL1 The L1 index. - * @param idxL2 The L2 index. - * @param offCluster Offset inside the cluster. - * @param poffImage Where to store the image offset on success; - */ -static int qedConvertToImageOffset(PQEDIMAGE pImage, uint32_t idxL1, uint32_t idxL2, - uint32_t offCluster, uint64_t *poffImage) -{ - int rc = VERR_VD_BLOCK_FREE; - LogFlowFunc(("pImage=%#p idxL1=%u idxL2=%u offCluster=%u poffImage=%#p\n", - pImage, idxL1, idxL2, offCluster, poffImage)); - - AssertReturn(idxL1 < pImage->cTableEntries, VERR_INVALID_PARAMETER); - AssertReturn(idxL2 < pImage->cTableEntries, VERR_INVALID_PARAMETER); - - if (pImage->paL1Table[idxL1]) - { - PQEDL2CACHEENTRY pL2Entry; - - rc = qedL2TblCacheFetch(pImage, pImage->paL1Table[idxL1], &pL2Entry); - if (RT_SUCCESS(rc)) - { - LogFlowFunc(("cluster start offset %llu\n", pL2Entry->paL2Tbl[idxL2])); - /* Get real file offset. */ - if (pL2Entry->paL2Tbl[idxL2]) - *poffImage = pL2Entry->paL2Tbl[idxL2] + offCluster; - else - rc = VERR_VD_BLOCK_FREE; - - qedL2TblCacheEntryRelease(pL2Entry); - } - } - - LogFlowFunc(("returns rc=%Rrc\n", rc)); - return rc; -} - -/** - * Returns the real image offset for a given cluster or an error if the cluster is not - * yet allocated- version for async I/O. - * - * @returns VBox status code. - * VERR_VD_BLOCK_FREE if the cluster is not yet allocated. - * @param pImage The image instance data. * @param pIoCtx The I/O context. * @param idxL1 The L1 index. * @param idxL2 The L2 index. * @param offCluster Offset inside the cluster. * @param poffImage Where to store the image offset on success; */ -static int qedConvertToImageOffsetAsync(PQEDIMAGE pImage, PVDIOCTX pIoCtx, - uint32_t idxL1, uint32_t idxL2, - uint32_t offCluster, uint64_t *poffImage) +static int qedConvertToImageOffset(PQEDIMAGE pImage, PVDIOCTX pIoCtx, + uint32_t idxL1, uint32_t idxL2, + uint32_t offCluster, uint64_t *poffImage) { int rc = VERR_VD_BLOCK_FREE; @@ -881,14 +837,14 @@ static int qedFlushImage(PQEDIMAGE pImage) #else /* Write L1 table directly. */ rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->offL1Table, - pImage->paL1Table, pImage->cbTable, NULL); + pImage->paL1Table, pImage->cbTable); #endif if (RT_SUCCESS(rc)) { /* Write header. */ qedHdrConvertFromHostEndianess(pImage, &Header); rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0, &Header, - sizeof(Header), NULL); + sizeof(Header)); if (RT_SUCCESS(rc)) rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage); } @@ -920,29 +876,29 @@ static int qedFlushImageAsync(PQEDIMAGE pImage, PVDIOCTX pIoCtx) { qedTableConvertFromHostEndianess(paL1TblImg, pImage->paL1Table, pImage->cTableEntries); - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - pImage->offL1Table, paL1TblImg, - pImage->cbTable, pIoCtx, NULL, NULL); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->offL1Table, paL1TblImg, + pImage->cbTable, pIoCtx, NULL, NULL); RTMemFree(paL1TblImg); } else rc = VERR_NO_MEMORY; #else /* Write L1 table directly. */ - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - pImage->offL1Table, pImage->paL1Table, - pImage->cbTable, pIoCtx, NULL, NULL); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->offL1Table, pImage->paL1Table, + pImage->cbTable, pIoCtx, NULL, NULL); #endif if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) { /* Write header. */ qedHdrConvertFromHostEndianess(pImage, &Header); - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - 0, &Header, sizeof(Header), - pIoCtx, NULL, NULL); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + 0, &Header, sizeof(Header), + pIoCtx, NULL, NULL); if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) - rc = vdIfIoIntFileFlushAsync(pImage->pIfIo, pImage->pStorage, - pIoCtx, NULL, NULL); + rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, + pIoCtx, NULL, NULL); } } @@ -1076,7 +1032,7 @@ static int qedCheckImage(PQEDIMAGE pImage, PQedHeader pHeader) /* Read L1 table. */ rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, - pHeader->u64OffL1Table, paL1Tbl, cbTable, NULL); + pHeader->u64OffL1Table, paL1Tbl, cbTable); if (RT_FAILURE(rc)) { rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS, @@ -1120,7 +1076,7 @@ static int qedCheckImage(PQEDIMAGE pImage, PQedHeader pHeader) /* Read the linked L2 table and check it. */ rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, - paL1Tbl[iL1], paL2Tbl, cbTable, NULL); + paL1Tbl[iL1], paL2Tbl, cbTable); if (RT_FAILURE(rc)) { rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, @@ -1185,7 +1141,7 @@ static int qedFreeImage(PQEDIMAGE pImage, bool fDelete) if (!fDelete) qedFlushImage(pImage); - vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage); + rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage); pImage->pStorage = NULL; } @@ -1193,7 +1149,10 @@ static int qedFreeImage(PQEDIMAGE pImage, bool fDelete) RTMemFree(pImage->paL1Table); if (pImage->pszBackingFilename) + { RTMemFree(pImage->pszBackingFilename); + pImage->pszBackingFilename = NULL; + } qedL2TblCacheDestroy(pImage); @@ -1239,7 +1198,7 @@ static int qedOpenImage(PQEDIMAGE pImage, unsigned uOpenFlags) goto out; if (cbFile > sizeof(Header)) { - rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0, &Header, sizeof(Header), NULL); + rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0, &Header, sizeof(Header)); if ( RT_SUCCESS(rc) && qedHdrConvertToHostEndianess(&Header)) { @@ -1261,14 +1220,14 @@ static int qedOpenImage(PQEDIMAGE pImage, unsigned uOpenFlags) && (Header.u64FeatureFlags & QED_FEATURE_BACKING_FILE)) { /* Load backing filename from image. */ - pImage->pszFilename = (char *)RTMemAllocZ(Header.u32BackingFilenameSize + 1); /* +1 for \0 terminator. */ - if (pImage->pszFilename) + pImage->pszBackingFilename = (char *)RTMemAllocZ(Header.u32BackingFilenameSize + 1); /* +1 for \0 terminator. */ + if (pImage->pszBackingFilename) { pImage->cbBackingFilename = Header.u32BackingFilenameSize; pImage->offBackingFilename = Header.u32OffBackingFilename; rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, Header.u32OffBackingFilename, pImage->pszBackingFilename, - Header.u32BackingFilenameSize, NULL); + Header.u32BackingFilenameSize); } else rc = VERR_NO_MEMORY; @@ -1291,7 +1250,7 @@ static int qedOpenImage(PQEDIMAGE pImage, unsigned uOpenFlags) /* Read from the image. */ rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, pImage->offL1Table, pImage->paL1Table, - pImage->cbTable, NULL); + pImage->cbTable); if (RT_SUCCESS(rc)) { qedTableConvertToHostEndianess(pImage->paL1Table, pImage->cTableEntries); @@ -1482,10 +1441,10 @@ static DECLCALLBACK(int) qedAsyncClusterAllocUpdate(void *pBackendData, PVDIOCTX /* Update the link in the on disk L1 table now. */ pClusterAlloc->enmAllocState = QEDCLUSTERASYNCALLOCSTATE_L2_LINK; - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - pImage->offL1Table + pClusterAlloc->idxL1*sizeof(uint64_t), - &offUpdateLe, sizeof(uint64_t), pIoCtx, - qedAsyncClusterAllocUpdate, pClusterAlloc); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->offL1Table + pClusterAlloc->idxL1*sizeof(uint64_t), + &offUpdateLe, sizeof(uint64_t), pIoCtx, + qedAsyncClusterAllocUpdate, pClusterAlloc); if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; else if (RT_FAILURE(rc)) @@ -1510,9 +1469,9 @@ static DECLCALLBACK(int) qedAsyncClusterAllocUpdate(void *pBackendData, PVDIOCTX pClusterAlloc->offClusterNew = offData; /* Write data. */ - rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pImage->pStorage, - offData, pIoCtx, pClusterAlloc->cbToWrite, - qedAsyncClusterAllocUpdate, pClusterAlloc); + rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, + offData, pIoCtx, pClusterAlloc->cbToWrite, + qedAsyncClusterAllocUpdate, pClusterAlloc); if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; else if (RT_FAILURE(rc)) @@ -1529,10 +1488,10 @@ static DECLCALLBACK(int) qedAsyncClusterAllocUpdate(void *pBackendData, PVDIOCTX pClusterAlloc->enmAllocState = QEDCLUSTERASYNCALLOCSTATE_USER_LINK; /* Link L2 table and update it. */ - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - pImage->paL1Table[pClusterAlloc->idxL1] + pClusterAlloc->idxL2*sizeof(uint64_t), - &offUpdateLe, sizeof(uint64_t), pIoCtx, - qedAsyncClusterAllocUpdate, pClusterAlloc); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->paL1Table[pClusterAlloc->idxL1] + pClusterAlloc->idxL2*sizeof(uint64_t), + &offUpdateLe, sizeof(uint64_t), pIoCtx, + qedAsyncClusterAllocUpdate, pClusterAlloc); if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; else if (RT_FAILURE(rc)) @@ -1594,7 +1553,7 @@ static int qedCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk, { QedHeader Header; - rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &Header, sizeof(Header), NULL); + rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &Header, sizeof(Header)); if ( RT_SUCCESS(rc) && qedHdrConvertToHostEndianess(&Header)) { @@ -1800,12 +1759,11 @@ static int qedClose(void *pBackendData, bool fDelete) return rc; } -/** @copydoc VBOXHDDBACKEND::pfnRead */ -static int qedRead(void *pBackendData, uint64_t uOffset, void *pvBuf, - size_t cbToRead, size_t *pcbActuallyRead) +static int qedRead(void *pBackendData, uint64_t uOffset, size_t cbToRead, + PVDIOCTX pIoCtx, size_t *pcbActuallyRead) { - LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", - pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead)); + LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n", + pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead)); PQEDIMAGE pImage = (PQEDIMAGE)pBackendData; uint32_t offCluster = 0; uint32_t idxL1 = 0; @@ -1817,6 +1775,12 @@ static int qedRead(void *pBackendData, uint64_t uOffset, void *pvBuf, Assert(uOffset % 512 == 0); Assert(cbToRead % 512 == 0); + if (!VALID_PTR(pIoCtx) || !cbToRead) + { + rc = VERR_INVALID_PARAMETER; + goto out; + } + if ( uOffset + cbToRead > pImage->cbSize || cbToRead == 0) { @@ -1825,21 +1789,19 @@ static int qedRead(void *pBackendData, uint64_t uOffset, void *pvBuf, } qedConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster); - LogFlowFunc(("idxL1=%u idxL2=%u offCluster=%u\n", idxL1, idxL2, offCluster)); /* Clip read size to remain in the cluster. */ cbToRead = RT_MIN(cbToRead, pImage->cbCluster - offCluster); /* Get offset in image. */ - rc = qedConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offFile); + rc = qedConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offFile); if (RT_SUCCESS(rc)) - { - LogFlowFunc(("offFile=%llu\n", offFile)); - rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offFile, - pvBuf, cbToRead, NULL); - } + rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, offFile, + pIoCtx, cbToRead); - if ( (RT_SUCCESS(rc) || rc == VERR_VD_BLOCK_FREE) + if ( ( RT_SUCCESS(rc) + || rc == VERR_VD_BLOCK_FREE + || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) && pcbActuallyRead) *pcbActuallyRead = cbToRead; @@ -1848,23 +1810,22 @@ out: return rc; } -/** @copydoc VBOXHDDBACKEND::pfnWrite */ -static int qedWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, - size_t cbToWrite, size_t *pcbWriteProcess, - size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite) +static int qedWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite, + PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead, + size_t *pcbPostRead, unsigned fWrite) { - LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", - pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead)); + LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", + pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead)); PQEDIMAGE pImage = (PQEDIMAGE)pBackendData; uint32_t offCluster = 0; uint32_t idxL1 = 0; uint32_t idxL2 = 0; uint64_t offImage = 0; - int rc; + int rc = VINF_SUCCESS; AssertPtr(pImage); - Assert(uOffset % 512 == 0); - Assert(cbToWrite % 512 == 0); + Assert(!(uOffset % 512)); + Assert(!(cbToWrite % 512)); if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) { @@ -1872,6 +1833,12 @@ static int qedWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, goto out; } + if (!VALID_PTR(pIoCtx) || !cbToWrite) + { + rc = VERR_INVALID_PARAMETER; + goto out; + } + if ( uOffset + cbToWrite > pImage->cbSize || cbToWrite == 0) { @@ -1887,10 +1854,10 @@ static int qedWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, Assert(!(cbToWrite % 512)); /* Get offset in image. */ - rc = qedConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offImage); + rc = qedConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offImage); if (RT_SUCCESS(rc)) - rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, offImage, - pvBuf, cbToWrite, NULL); + rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, + offImage, pIoCtx, cbToWrite, NULL, NULL); else if (rc == VERR_VD_BLOCK_FREE) { if ( cbToWrite == pImage->cbCluster @@ -1909,59 +1876,98 @@ static int qedWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, /* Check if we have to allocate a new cluster for L2 tables. */ if (!pImage->paL1Table[idxL1]) { - uint64_t offL2Tbl = qedClusterAllocate(pImage, qedByte2Cluster(pImage, pImage->cbTable)); + uint64_t offL2Tbl; + PQEDCLUSTERASYNCALLOC pL2ClusterAlloc = NULL; + + /* Allocate new async cluster allocation state. */ + pL2ClusterAlloc = (PQEDCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QEDCLUSTERASYNCALLOC)); + if (RT_UNLIKELY(!pL2ClusterAlloc)) + { + rc = VERR_NO_MEMORY; + break; + } pL2Entry = qedL2TblCacheEntryAlloc(pImage); if (!pL2Entry) { rc = VERR_NO_MEMORY; + RTMemFree(pL2ClusterAlloc); break; } + offL2Tbl = qedClusterAllocate(pImage, qedByte2Cluster(pImage, pImage->cbTable)); pL2Entry->offL2Tbl = offL2Tbl; memset(pL2Entry->paL2Tbl, 0, pImage->cbTable); - qedL2TblCacheEntryInsert(pImage, pL2Entry); + + pL2ClusterAlloc->enmAllocState = QEDCLUSTERASYNCALLOCSTATE_L2_ALLOC; + pL2ClusterAlloc->cbImageOld = offL2Tbl; + pL2ClusterAlloc->offClusterNew = offL2Tbl; + pL2ClusterAlloc->idxL1 = idxL1; + pL2ClusterAlloc->idxL2 = idxL2; + pL2ClusterAlloc->cbToWrite = cbToWrite; + pL2ClusterAlloc->pL2Entry = pL2Entry; /* * Write the L2 table first and link to the L1 table afterwards. * If something unexpected happens the worst case which can happen * is a leak of some clusters. */ - rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, offL2Tbl, - pL2Entry->paL2Tbl, pImage->cbTable, NULL); - if (RT_FAILURE(rc)) + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + offL2Tbl, pL2Entry->paL2Tbl, pImage->cbTable, pIoCtx, + qedAsyncClusterAllocUpdate, pL2ClusterAlloc); + if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; - - /* Write the L1 link now. */ - pImage->paL1Table[idxL1] = offL2Tbl; - idxUpdateLe = RT_H2LE_U64(offL2Tbl); - rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, - pImage->offL1Table + idxL1*sizeof(uint64_t), - &idxUpdateLe, sizeof(uint64_t), NULL); - if (RT_FAILURE(rc)) + else if (RT_FAILURE(rc)) + { + RTMemFree(pL2ClusterAlloc); + qedL2TblCacheEntryFree(pImage, pL2Entry); break; + } + + rc = qedAsyncClusterAllocUpdate(pImage, pIoCtx, pL2ClusterAlloc, rc); } else - rc = qedL2TblCacheFetch(pImage, pImage->paL1Table[idxL1], &pL2Entry); - - if (RT_SUCCESS(rc)) { - /* Allocate new cluster for the data. */ - uint64_t offData = qedClusterAllocate(pImage, 1); + rc = qedL2TblCacheFetchAsync(pImage, pIoCtx, pImage->paL1Table[idxL1], + &pL2Entry); - /* Write data. */ - rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, - offData, pvBuf, cbToWrite, NULL); - if (RT_FAILURE(rc)) - break; + if (RT_SUCCESS(rc)) + { + PQEDCLUSTERASYNCALLOC pDataClusterAlloc = NULL; - /* Link L2 table and update it. */ - pL2Entry->paL2Tbl[idxL2] = offData; - idxUpdateLe = RT_H2LE_U64(offData); - rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, - pImage->paL1Table[idxL1] + idxL2*sizeof(uint64_t), - &idxUpdateLe, sizeof(uint64_t), NULL); - qedL2TblCacheEntryRelease(pL2Entry); + /* Allocate new async cluster allocation state. */ + pDataClusterAlloc = (PQEDCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QEDCLUSTERASYNCALLOC)); + if (RT_UNLIKELY(!pDataClusterAlloc)) + { + rc = VERR_NO_MEMORY; + break; + } + + /* Allocate new cluster for the data. */ + uint64_t offData = qedClusterAllocate(pImage, 1); + + pDataClusterAlloc->enmAllocState = QEDCLUSTERASYNCALLOCSTATE_USER_ALLOC; + pDataClusterAlloc->cbImageOld = offData; + pDataClusterAlloc->offClusterNew = offData; + pDataClusterAlloc->idxL1 = idxL1; + pDataClusterAlloc->idxL2 = idxL2; + pDataClusterAlloc->cbToWrite = cbToWrite; + pDataClusterAlloc->pL2Entry = pL2Entry; + + /* Write data. */ + rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, + offData, pIoCtx, cbToWrite, + qedAsyncClusterAllocUpdate, pDataClusterAlloc); + if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) + break; + else if (RT_FAILURE(rc)) + { + RTMemFree(pDataClusterAlloc); + break; + } + + rc = qedAsyncClusterAllocUpdate(pImage, pIoCtx, pDataClusterAlloc, rc); + } } } while (0); @@ -1981,19 +1987,25 @@ static int qedWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, if (pcbWriteProcess) *pcbWriteProcess = cbToWrite; + out: LogFlowFunc(("returns %Rrc\n", rc)); return rc; } -/** @copydoc VBOXHDDBACKEND::pfnFlush */ -static int qedFlush(void *pBackendData) +static int qedFlush(void *pBackendData, PVDIOCTX pIoCtx) { LogFlowFunc(("pBackendData=%#p\n", pBackendData)); PQEDIMAGE pImage = (PQEDIMAGE)pBackendData; - int rc; + int rc = VINF_SUCCESS; + + Assert(pImage); + + if (VALID_PTR(pIoCtx)) + rc = qedFlushImageAsync(pImage, pIoCtx); + else + rc = VERR_INVALID_PARAMETER; - rc = qedFlushImage(pImage); LogFlowFunc(("returns %Rrc\n", rc)); return rc; } @@ -2012,6 +2024,22 @@ static unsigned qedGetVersion(void *pBackendData) return 0; } +/** @copydoc VBOXHDDBACKEND::pfnGetSectorSize */ +static uint32_t qedGetSectorSize(void *pBackendData) +{ + LogFlowFunc(("pBackendData=%#p\n", pBackendData)); + PQEDIMAGE pImage = (PQEDIMAGE)pBackendData; + uint32_t cb = 0; + + AssertPtr(pImage); + + if (pImage && pImage->pStorage) + cb = 512; + + LogFlowFunc(("returns %u\n", cb)); + return cb; +} + /** @copydoc VBOXHDDBACKEND::pfnGetSize */ static uint64_t qedGetSize(void *pBackendData) { @@ -2208,7 +2236,8 @@ static int qedSetOpenFlags(void *pBackendData, unsigned uOpenFlags) int rc; /* Image must be opened and the new flags must be valid. */ - if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO))) + if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO + | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS))) { rc = VERR_INVALID_PARAMETER; goto out; @@ -2455,7 +2484,7 @@ static int qedGetParentFilename(void *pBackendData, char **ppszParentFilename) AssertPtr(pImage); if (pImage) - if (pImage->pszFilename) + if (pImage->pszBackingFilename) *ppszParentFilename = RTStrDup(pImage->pszBackingFilename); else rc = VERR_NOT_SUPPORTED; @@ -2496,7 +2525,7 @@ static int qedSetParentFilename(void *pBackendData, const char *pszParentFilenam Assert((offData & UINT32_MAX) == offData); pImage->offBackingFilename = (uint32_t)offData; - pImage->cbBackingFilename = strlen(pszParentFilename); + pImage->cbBackingFilename = (uint32_t)strlen(pszParentFilename); rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, offData + pImage->cbCluster); } @@ -2505,8 +2534,7 @@ static int qedSetParentFilename(void *pBackendData, const char *pszParentFilenam rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->offBackingFilename, pImage->pszBackingFilename, - strlen(pImage->pszBackingFilename), - NULL); + strlen(pImage->pszBackingFilename)); } } } @@ -2517,260 +2545,6 @@ static int qedSetParentFilename(void *pBackendData, const char *pszParentFilenam return rc; } -static int qedAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead, - PVDIOCTX pIoCtx, size_t *pcbActuallyRead) -{ - LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n", - pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead)); - PQEDIMAGE pImage = (PQEDIMAGE)pBackendData; - uint32_t offCluster = 0; - uint32_t idxL1 = 0; - uint32_t idxL2 = 0; - uint64_t offFile = 0; - int rc; - - AssertPtr(pImage); - Assert(uOffset % 512 == 0); - Assert(cbToRead % 512 == 0); - - if (!VALID_PTR(pIoCtx) || !cbToRead) - { - rc = VERR_INVALID_PARAMETER; - goto out; - } - - if ( uOffset + cbToRead > pImage->cbSize - || cbToRead == 0) - { - rc = VERR_INVALID_PARAMETER; - goto out; - } - - qedConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster); - - /* Clip read size to remain in the cluster. */ - cbToRead = RT_MIN(cbToRead, pImage->cbCluster - offCluster); - - /* Get offset in image. */ - rc = qedConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster, - &offFile); - if (RT_SUCCESS(rc)) - rc = vdIfIoIntFileReadUserAsync(pImage->pIfIo, pImage->pStorage, offFile, - pIoCtx, cbToRead); - - if ( ( RT_SUCCESS(rc) - || rc == VERR_VD_BLOCK_FREE - || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) - && pcbActuallyRead) - *pcbActuallyRead = cbToRead; - -out: - LogFlowFunc(("returns %Rrc\n", rc)); - return rc; -} - -static int qedAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite, - PVDIOCTX pIoCtx, - size_t *pcbWriteProcess, size_t *pcbPreRead, - size_t *pcbPostRead, unsigned fWrite) -{ - LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", - pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead)); - PQEDIMAGE pImage = (PQEDIMAGE)pBackendData; - uint32_t offCluster = 0; - uint32_t idxL1 = 0; - uint32_t idxL2 = 0; - uint64_t offImage = 0; - int rc = VINF_SUCCESS; - - AssertPtr(pImage); - Assert(!(uOffset % 512)); - Assert(!(cbToWrite % 512)); - - if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) - { - rc = VERR_VD_IMAGE_READ_ONLY; - goto out; - } - - if (!VALID_PTR(pIoCtx) || !cbToWrite) - { - rc = VERR_INVALID_PARAMETER; - goto out; - } - - if ( uOffset + cbToWrite > pImage->cbSize - || cbToWrite == 0) - { - rc = VERR_INVALID_PARAMETER; - goto out; - } - - /* Convert offset to L1, L2 index and cluster offset. */ - qedConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster); - - /* Clip write size to remain in the cluster. */ - cbToWrite = RT_MIN(cbToWrite, pImage->cbCluster - offCluster); - Assert(!(cbToWrite % 512)); - - /* Get offset in image. */ - rc = qedConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster, - &offImage); - if (RT_SUCCESS(rc)) - rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pImage->pStorage, - offImage, pIoCtx, cbToWrite, NULL, NULL); - else if (rc == VERR_VD_BLOCK_FREE) - { - if ( cbToWrite == pImage->cbCluster - && !(fWrite & VD_WRITE_NO_ALLOC)) - { - PQEDL2CACHEENTRY pL2Entry = NULL; - - /* Full cluster write to previously unallocated cluster. - * Allocate cluster and write data. */ - Assert(!offCluster); - - do - { - uint64_t idxUpdateLe = 0; - - /* Check if we have to allocate a new cluster for L2 tables. */ - if (!pImage->paL1Table[idxL1]) - { - uint64_t offL2Tbl; - PQEDCLUSTERASYNCALLOC pL2ClusterAlloc = NULL; - - /* Allocate new async cluster allocation state. */ - pL2ClusterAlloc = (PQEDCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QEDCLUSTERASYNCALLOC)); - if (RT_UNLIKELY(!pL2ClusterAlloc)) - { - rc = VERR_NO_MEMORY; - break; - } - - pL2Entry = qedL2TblCacheEntryAlloc(pImage); - if (!pL2Entry) - { - rc = VERR_NO_MEMORY; - RTMemFree(pL2ClusterAlloc); - break; - } - - offL2Tbl = qedClusterAllocate(pImage, qedByte2Cluster(pImage, pImage->cbTable)); - pL2Entry->offL2Tbl = offL2Tbl; - memset(pL2Entry->paL2Tbl, 0, pImage->cbTable); - - pL2ClusterAlloc->enmAllocState = QEDCLUSTERASYNCALLOCSTATE_L2_ALLOC; - pL2ClusterAlloc->cbImageOld = offL2Tbl; - pL2ClusterAlloc->offClusterNew = offL2Tbl; - pL2ClusterAlloc->idxL1 = idxL1; - pL2ClusterAlloc->idxL2 = idxL2; - pL2ClusterAlloc->cbToWrite = cbToWrite; - pL2ClusterAlloc->pL2Entry = pL2Entry; - - /* - * Write the L2 table first and link to the L1 table afterwards. - * If something unexpected happens the worst case which can happen - * is a leak of some clusters. - */ - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - offL2Tbl, pL2Entry->paL2Tbl, pImage->cbTable, pIoCtx, - qedAsyncClusterAllocUpdate, pL2ClusterAlloc); - if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) - break; - else if (RT_FAILURE(rc)) - { - RTMemFree(pL2ClusterAlloc); - qedL2TblCacheEntryFree(pImage, pL2Entry); - break; - } - - rc = qedAsyncClusterAllocUpdate(pImage, pIoCtx, pL2ClusterAlloc, rc); - } - else - { - rc = qedL2TblCacheFetchAsync(pImage, pIoCtx, pImage->paL1Table[idxL1], - &pL2Entry); - - if (RT_SUCCESS(rc)) - { - PQEDCLUSTERASYNCALLOC pDataClusterAlloc = NULL; - - /* Allocate new async cluster allocation state. */ - pDataClusterAlloc = (PQEDCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QEDCLUSTERASYNCALLOC)); - if (RT_UNLIKELY(!pDataClusterAlloc)) - { - rc = VERR_NO_MEMORY; - break; - } - - /* Allocate new cluster for the data. */ - uint64_t offData = qedClusterAllocate(pImage, 1); - - pDataClusterAlloc->enmAllocState = QEDCLUSTERASYNCALLOCSTATE_USER_ALLOC; - pDataClusterAlloc->cbImageOld = offData; - pDataClusterAlloc->offClusterNew = offData; - pDataClusterAlloc->idxL1 = idxL1; - pDataClusterAlloc->idxL2 = idxL2; - pDataClusterAlloc->cbToWrite = cbToWrite; - pDataClusterAlloc->pL2Entry = pL2Entry; - - /* Write data. */ - rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pImage->pStorage, - offData, pIoCtx, cbToWrite, - qedAsyncClusterAllocUpdate, pDataClusterAlloc); - if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) - break; - else if (RT_FAILURE(rc)) - { - RTMemFree(pDataClusterAlloc); - break; - } - - rc = qedAsyncClusterAllocUpdate(pImage, pIoCtx, pDataClusterAlloc, rc); - } - } - - } while (0); - - *pcbPreRead = 0; - *pcbPostRead = 0; - } - else - { - /* Trying to do a partial write to an unallocated cluster. Don't do - * anything except letting the upper layer know what to do. */ - *pcbPreRead = offCluster; - *pcbPostRead = pImage->cbCluster - cbToWrite - *pcbPreRead; - } - } - - if (pcbWriteProcess) - *pcbWriteProcess = cbToWrite; - - -out: - LogFlowFunc(("returns %Rrc\n", rc)); - return rc; -} - -static int qedAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx) -{ - LogFlowFunc(("pBackendData=%#p\n", pBackendData)); - PQEDIMAGE pImage = (PQEDIMAGE)pBackendData; - int rc = VINF_SUCCESS; - - Assert(pImage); - - if (VALID_PTR(pIoCtx)) - rc = qedFlushImageAsync(pImage, pIoCtx); - else - rc = VERR_INVALID_PARAMETER; - - LogFlowFunc(("returns %Rrc\n", rc)); - return rc; -} - /** @copydoc VBOXHDDBACKEND::pfnResize */ static int qedResize(void *pBackendData, uint64_t cbSize, PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry, @@ -2853,8 +2627,12 @@ VBOXHDDBACKEND g_QedBackend = qedWrite, /* pfnFlush */ qedFlush, + /* pfnDiscard */ + NULL, /* pfnGetVersion */ qedGetVersion, + /* pfnGetSectorSize */ + qedGetSectorSize, /* pfnGetSize */ qedGetSize, /* pfnGetFileSize */ @@ -2905,12 +2683,6 @@ VBOXHDDBACKEND g_QedBackend = qedGetParentFilename, /* pfnSetParentFilename */ qedSetParentFilename, - /* pfnAsyncRead */ - qedAsyncRead, - /* pfnAsyncWrite */ - qedAsyncWrite, - /* pfnAsyncFlush */ - qedAsyncFlush, /* pfnComposeLocation */ genericFileComposeLocation, /* pfnComposeName */ @@ -2919,10 +2691,6 @@ VBOXHDDBACKEND g_QedBackend = NULL, /* pfnResize */ qedResize, - /* pfnDiscard */ - NULL, - /* pfnAsyncDiscard */ - NULL, /* pfnRepair */ NULL }; |