diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Storage/QCOW.cpp | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-master.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Storage/QCOW.cpp')
-rw-r--r-- | src/VBox/Storage/QCOW.cpp | 670 |
1 files changed, 183 insertions, 487 deletions
diff --git a/src/VBox/Storage/QCOW.cpp b/src/VBox/Storage/QCOW.cpp index 9572e1dc..c90d1558 100644 --- a/src/VBox/Storage/QCOW.cpp +++ b/src/VBox/Storage/QCOW.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; @@ -683,64 +683,12 @@ static void qcowL2TblCacheEntryInsert(PQCOWIMAGE pImage, PQCOWL2CACHEENTRY pL2En * * @returns VBox status code. * @param pImage Image instance data. - * @param offL2Tbl The offset of the L2 table in the image. - * @param ppL2Entry Where to store the L2 table on success. - */ -static int qcowL2TblCacheFetch(PQCOWIMAGE pImage, uint64_t offL2Tbl, PQCOWL2CACHEENTRY *ppL2Entry) -{ - int rc = VINF_SUCCESS; - - LogFlowFunc(("pImage=%#p offL2Tbl=%llu ppL2Entry=%#p\n", pImage, offL2Tbl, ppL2Entry)); - - /* Try to fetch the L2 table from the cache first. */ - PQCOWL2CACHEENTRY pL2Entry = qcowL2TblCacheRetain(pImage, offL2Tbl); - if (!pL2Entry) - { - LogFlowFunc(("Reading L2 table from image\n")); - pL2Entry = qcowL2TblCacheEntryAlloc(pImage); - - if (pL2Entry) - { - /* Read from the image. */ - pL2Entry->offL2Tbl = offL2Tbl; - rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offL2Tbl, - pL2Entry->paL2Tbl, pImage->cbL2Table, NULL); - if (RT_SUCCESS(rc)) - { -#if defined(RT_LITTLE_ENDIAN) - qcowTableConvertToHostEndianess(pL2Entry->paL2Tbl, pImage->cL2TableEntries); -#endif - qcowL2TblCacheEntryInsert(pImage, pL2Entry); - } - else - { - qcowL2TblCacheEntryRelease(pL2Entry); - qcowL2TblCacheEntryFree(pImage, pL2Entry); - } - } - else - rc = VERR_NO_MEMORY; - } - - if (RT_SUCCESS(rc)) - *ppL2Entry = pL2Entry; - - LogFlowFunc(("returns rc=%Rrc\n", rc)); - return rc; -} - -/** - * Fetches the L2 from the given offset trying the LRU cache first and - * reading it from the image after a cache miss - version for async I/O. - * - * @returns VBox status code. - * @param pImage Image instance data. * @param pIoCtx The I/O context. * @param offL2Tbl The offset of the L2 table in the image. * @param ppL2Entry Where to store the L2 table on success. */ -static int qcowL2TblCacheFetchAsync(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, - uint64_t offL2Tbl, PQCOWL2CACHEENTRY *ppL2Entry) +static int qcowL2TblCacheFetch(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, uint64_t offL2Tbl, + PQCOWL2CACHEENTRY *ppL2Entry) { int rc = VINF_SUCCESS; @@ -756,10 +704,10 @@ static int qcowL2TblCacheFetchAsync(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, PVDMETAXFER pMetaXfer; pL2Entry->offL2Tbl = offL2Tbl; - rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pImage->pStorage, - offL2Tbl, pL2Entry->paL2Tbl, - pImage->cbL2Table, pIoCtx, - &pMetaXfer, NULL, NULL); + rc = vdIfIoIntFileReadMeta(pImage->pIfIo, pImage->pStorage, + offL2Tbl, pL2Entry->paL2Tbl, + pImage->cbL2Table, pIoCtx, + &pMetaXfer, NULL, NULL); if (RT_SUCCESS(rc)) { vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer); @@ -875,79 +823,15 @@ DECLINLINE(uint64_t) qcowClusterAllocate(PQCOWIMAGE 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 qcowConvertToImageOffset(PQCOWIMAGE 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->cL1TableEntries, VERR_INVALID_PARAMETER); - AssertReturn(idxL2 < pImage->cL2TableEntries, VERR_INVALID_PARAMETER); - - if (pImage->paL1Table[idxL1]) - { - PQCOWL2CACHEENTRY pL2Entry; - - rc = qcowL2TblCacheFetch(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]) - { - uint64_t off = pL2Entry->paL2Tbl[idxL2]; - - /* Strip flags */ - if (pImage->uVersion == 2) - { - if (RT_UNLIKELY(off & QCOW_V2_COMPRESSED_FLAG)) - rc = VERR_NOT_SUPPORTED; - else - off &= ~(QCOW_V2_COMPRESSED_FLAG | QCOW_V2_COPIED_FLAG); - } - else - { - if (RT_UNLIKELY(off & QCOW_V1_COMPRESSED_FLAG)) - rc = VERR_NOT_SUPPORTED; - else - off &= ~QCOW_V1_COMPRESSED_FLAG; - } - - *poffImage = off + offCluster; - } - else - rc = VERR_VD_BLOCK_FREE; - - qcowL2TblCacheEntryRelease(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 qcowConvertToImageOffsetAsync(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, - uint32_t idxL1, uint32_t idxL2, - uint32_t offCluster, uint64_t *poffImage) +static int qcowConvertToImageOffset(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, + uint32_t idxL1, uint32_t idxL2, + uint32_t offCluster, uint64_t *poffImage) { int rc = VERR_VD_BLOCK_FREE; @@ -958,8 +842,7 @@ static int qcowConvertToImageOffsetAsync(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, { PQCOWL2CACHEENTRY pL2Entry; - rc = qcowL2TblCacheFetchAsync(pImage, pIoCtx, pImage->paL1Table[idxL1], - &pL2Entry); + rc = qcowL2TblCacheFetch(pImage, pIoCtx, pImage->paL1Table[idxL1], &pL2Entry); if (RT_SUCCESS(rc)) { /* Get real file offset. */ @@ -1017,7 +900,7 @@ static int qcowFlushImage(PQCOWIMAGE pImage) pImage->cL1TableEntries); rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->offL1Table, paL1TblImg, - pImage->cbL1Table, NULL); + pImage->cbL1Table); RTMemFree(paL1TblImg); } else @@ -1025,7 +908,7 @@ static int qcowFlushImage(PQCOWIMAGE pImage) #else /* Write L1 table directly. */ rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->offL1Table, - pImage->paL1Table, pImage->cbL1Table, NULL); + pImage->paL1Table, pImage->cbL1Table); #endif if (RT_SUCCESS(rc)) { @@ -1033,7 +916,7 @@ static int qcowFlushImage(PQCOWIMAGE pImage) size_t cbHeader = 0; qcowHdrConvertFromHostEndianess(pImage, &Header, &cbHeader); rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0, &Header, - cbHeader, NULL); + cbHeader); if (RT_SUCCESS(rc)) rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage); } @@ -1064,30 +947,30 @@ static int qcowFlushImageAsync(PQCOWIMAGE pImage, PVDIOCTX pIoCtx) { qcowTableConvertFromHostEndianess(paL1TblImg, pImage->paL1Table, pImage->cL1TableEntries); - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - pImage->offL1Table, paL1TblImg, - pImage->cbL1Table, pIoCtx, NULL, NULL); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->offL1Table, paL1TblImg, + pImage->cbL1Table, 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->cbL1Table, pIoCtx, NULL, NULL); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->offL1Table, pImage->paL1Table, + pImage->cbL1Table, pIoCtx, NULL, NULL); #endif if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) { /* Write header. */ size_t cbHeader = 0; qcowHdrConvertFromHostEndianess(pImage, &Header, &cbHeader); - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - 0, &Header, cbHeader, - pIoCtx, NULL, NULL); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + 0, &Header, cbHeader, + 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); } } @@ -1112,7 +995,7 @@ static int qcowFreeImage(PQCOWIMAGE pImage, bool fDelete) if (!fDelete) qcowFlushImage(pImage); - vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage); + rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage); pImage->pStorage = NULL; } @@ -1120,7 +1003,10 @@ static int qcowFreeImage(PQCOWIMAGE pImage, bool fDelete) RTMemFree(pImage->paL1Table); if (pImage->pszBackingFilename) + { RTMemFree(pImage->pszBackingFilename); + pImage->pszBackingFilename = NULL; + } qcowL2TblCacheDestroy(pImage); @@ -1166,7 +1052,7 @@ static int qcowOpenImage(PQCOWIMAGE 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) && qcowHdrConvertToHostEndianess(&Header)) { @@ -1241,12 +1127,12 @@ static int qcowOpenImage(PQCOWIMAGE pImage, unsigned uOpenFlags) && pImage->offBackingFilename) { /* Load backing filename from image. */ - pImage->pszFilename = (char *)RTMemAllocZ(pImage->cbBackingFilename + 1); /* +1 for \0 terminator. */ - if (pImage->pszFilename) + pImage->pszBackingFilename = (char *)RTMemAllocZ(pImage->cbBackingFilename + 1); /* +1 for \0 terminator. */ + if (pImage->pszBackingFilename) { rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, pImage->offBackingFilename, pImage->pszBackingFilename, - pImage->cbBackingFilename, NULL); + pImage->cbBackingFilename); } else rc = VERR_NO_MEMORY; @@ -1263,7 +1149,7 @@ static int qcowOpenImage(PQCOWIMAGE pImage, unsigned uOpenFlags) { rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, pImage->offRefcountTable, pImage->paRefcountTable, - pImage->cbRefcountTable, NULL); + pImage->cbRefcountTable); if (RT_SUCCESS(rc)) qcowTableConvertToHostEndianess(pImage->paRefcountTable, pImage->cRefcountTableEntries); @@ -1289,7 +1175,7 @@ static int qcowOpenImage(PQCOWIMAGE pImage, unsigned uOpenFlags) /* Read from the image. */ rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, pImage->offL1Table, pImage->paL1Table, - pImage->cbL1Table, NULL); + pImage->cbL1Table); if (RT_SUCCESS(rc)) qcowTableConvertToHostEndianess(pImage->paL1Table, pImage->cL1TableEntries); else @@ -1468,10 +1354,10 @@ static DECLCALLBACK(int) qcowAsyncClusterAllocUpdate(void *pBackendData, PVDIOCT /* Update the link in the on disk L1 table now. */ pClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_L2_LINK; - rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, - pImage->offL1Table + pClusterAlloc->idxL1*sizeof(uint64_t), - &offUpdateLe, sizeof(uint64_t), pIoCtx, - qcowAsyncClusterAllocUpdate, pClusterAlloc); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->offL1Table + pClusterAlloc->idxL1*sizeof(uint64_t), + &offUpdateLe, sizeof(uint64_t), pIoCtx, + qcowAsyncClusterAllocUpdate, pClusterAlloc); if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; else if (RT_FAILURE(rc)) @@ -1496,9 +1382,9 @@ static DECLCALLBACK(int) qcowAsyncClusterAllocUpdate(void *pBackendData, PVDIOCT pClusterAlloc->offClusterNew = offData; /* Write data. */ - rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pImage->pStorage, - offData, pIoCtx, pClusterAlloc->cbToWrite, - qcowAsyncClusterAllocUpdate, pClusterAlloc); + rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, + offData, pIoCtx, pClusterAlloc->cbToWrite, + qcowAsyncClusterAllocUpdate, pClusterAlloc); if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; else if (RT_FAILURE(rc)) @@ -1515,10 +1401,10 @@ static DECLCALLBACK(int) qcowAsyncClusterAllocUpdate(void *pBackendData, PVDIOCT pClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_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, - qcowAsyncClusterAllocUpdate, pClusterAlloc); + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + pImage->paL1Table[pClusterAlloc->idxL1] + pClusterAlloc->idxL2*sizeof(uint64_t), + &offUpdateLe, sizeof(uint64_t), pIoCtx, + qcowAsyncClusterAllocUpdate, pClusterAlloc); if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; else if (RT_FAILURE(rc)) @@ -1580,7 +1466,7 @@ static int qcowCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk, { QCowHeader Header; - rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &Header, sizeof(Header), NULL); + rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &Header, sizeof(Header)); if ( RT_SUCCESS(rc) && qcowHdrConvertToHostEndianess(&Header)) { @@ -1786,12 +1672,11 @@ static int qcowClose(void *pBackendData, bool fDelete) return rc; } -/** @copydoc VBOXHDDBACKEND::pfnRead */ -static int qcowRead(void *pBackendData, uint64_t uOffset, void *pvBuf, - size_t cbToRead, size_t *pcbActuallyRead) +static int qcowRead(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)); PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData; uint32_t offCluster = 0; uint32_t idxL1 = 0; @@ -1803,6 +1688,12 @@ static int qcowRead(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) { @@ -1811,21 +1702,19 @@ static int qcowRead(void *pBackendData, uint64_t uOffset, void *pvBuf, } qcowConvertLogicalOffset(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 = qcowConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offFile); + rc = qcowConvertToImageOffset(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; @@ -1834,23 +1723,22 @@ out: return rc; } -/** @copydoc VBOXHDDBACKEND::pfnWrite */ -static int qcowWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, - size_t cbToWrite, size_t *pcbWriteProcess, - size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite) +static int qcowWrite(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)); PQCOWIMAGE pImage = (PQCOWIMAGE)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) { @@ -1858,6 +1746,12 @@ static int qcowWrite(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) { @@ -1873,10 +1767,10 @@ static int qcowWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, Assert(!(cbToWrite % 512)); /* Get offset in image. */ - rc = qcowConvertToImageOffset(pImage, idxL1, idxL2, offCluster, &offImage); + rc = qcowConvertToImageOffset(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 @@ -1895,59 +1789,97 @@ static int qcowWrite(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 = qcowClusterAllocate(pImage, qcowByte2Cluster(pImage, pImage->cbL2Table)); + uint64_t offL2Tbl; + PQCOWCLUSTERASYNCALLOC pL2ClusterAlloc = NULL; + + /* Allocate new async cluster allocation state. */ + pL2ClusterAlloc = (PQCOWCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QCOWCLUSTERASYNCALLOC)); + if (RT_UNLIKELY(!pL2ClusterAlloc)) + { + rc = VERR_NO_MEMORY; + break; + } pL2Entry = qcowL2TblCacheEntryAlloc(pImage); if (!pL2Entry) { rc = VERR_NO_MEMORY; + RTMemFree(pL2ClusterAlloc); break; } + offL2Tbl = qcowClusterAllocate(pImage, qcowByte2Cluster(pImage, pImage->cbL2Table)); pL2Entry->offL2Tbl = offL2Tbl; memset(pL2Entry->paL2Tbl, 0, pImage->cbL2Table); - qcowL2TblCacheEntryInsert(pImage, pL2Entry); + + pL2ClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC; + pL2ClusterAlloc->offNextClusterOld = 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->cbL2Table, NULL); - if (RT_FAILURE(rc)) + rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage, + offL2Tbl, pL2Entry->paL2Tbl, pImage->cbL2Table, pIoCtx, + qcowAsyncClusterAllocUpdate, pL2ClusterAlloc); + if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) break; - - /* Write the L1 link now. */ - pImage->paL1Table[idxL1] = offL2Tbl; - idxUpdateLe = RT_H2BE_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); + qcowL2TblCacheEntryFree(pImage, pL2Entry); break; + } + + rc = qcowAsyncClusterAllocUpdate(pImage, pIoCtx, pL2ClusterAlloc, rc); } else - rc = qcowL2TblCacheFetch(pImage, pImage->paL1Table[idxL1], &pL2Entry); - - if (RT_SUCCESS(rc)) { - /* Allocate new cluster for the data. */ - uint64_t offData = qcowClusterAllocate(pImage, 1); + rc = qcowL2TblCacheFetch(pImage, pIoCtx, pImage->paL1Table[idxL1], + &pL2Entry); + if (RT_SUCCESS(rc)) + { + PQCOWCLUSTERASYNCALLOC pDataClusterAlloc = NULL; - /* Write data. */ - rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, - offData, pvBuf, cbToWrite, NULL); - if (RT_FAILURE(rc)) - break; + /* Allocate new async cluster allocation state. */ + pDataClusterAlloc = (PQCOWCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QCOWCLUSTERASYNCALLOC)); + if (RT_UNLIKELY(!pDataClusterAlloc)) + { + rc = VERR_NO_MEMORY; + break; + } - /* Link L2 table and update it. */ - pL2Entry->paL2Tbl[idxL2] = offData; - idxUpdateLe = RT_H2BE_U64(offData); - rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, - pImage->paL1Table[idxL1] + idxL2*sizeof(uint64_t), - &idxUpdateLe, sizeof(uint64_t), NULL); - qcowL2TblCacheEntryRelease(pL2Entry); + /* Allocate new cluster for the data. */ + uint64_t offData = qcowClusterAllocate(pImage, 1); + + pDataClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC; + pDataClusterAlloc->offNextClusterOld = 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, + qcowAsyncClusterAllocUpdate, pDataClusterAlloc); + if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) + break; + else if (RT_FAILURE(rc)) + { + RTMemFree(pDataClusterAlloc); + break; + } + + rc = qcowAsyncClusterAllocUpdate(pImage, pIoCtx, pDataClusterAlloc, rc); + } } } while (0); @@ -1967,19 +1899,25 @@ static int qcowWrite(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 qcowFlush(void *pBackendData) +static int qcowFlush(void *pBackendData, PVDIOCTX pIoCtx) { LogFlowFunc(("pBackendData=%#p\n", pBackendData)); PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData; - int rc; + int rc = VINF_SUCCESS; + + Assert(pImage); + + if (VALID_PTR(pIoCtx)) + rc = qcowFlushImageAsync(pImage, pIoCtx); + else + rc = VERR_INVALID_PARAMETER; - rc = qcowFlushImage(pImage); LogFlowFunc(("returns %Rrc\n", rc)); return rc; } @@ -1998,6 +1936,22 @@ static unsigned qcowGetVersion(void *pBackendData) return 0; } +/** @copydoc VBOXHDDBACKEND::pfnGetSectorSize */ +static uint32_t qcowGetSectorSize(void *pBackendData) +{ + LogFlowFunc(("pBackendData=%#p\n", pBackendData)); + PQCOWIMAGE pImage = (PQCOWIMAGE)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 qcowGetSize(void *pBackendData) { @@ -2194,7 +2148,8 @@ static int qcowSetOpenFlags(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; @@ -2441,7 +2396,7 @@ static int qcowGetParentFilename(void *pBackendData, char **ppszParentFilename) AssertPtr(pImage); if (pImage) - if (pImage->pszFilename) + if (pImage->pszBackingFilename) *ppszParentFilename = RTStrDup(pImage->pszBackingFilename); else rc = VERR_NOT_SUPPORTED; @@ -2482,7 +2437,7 @@ static int qcowSetParentFilename(void *pBackendData, const char *pszParentFilena 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); } @@ -2491,8 +2446,7 @@ static int qcowSetParentFilename(void *pBackendData, const char *pszParentFilena rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->offBackingFilename, pImage->pszBackingFilename, - strlen(pImage->pszBackingFilename), - NULL); + strlen(pImage->pszBackingFilename)); } } } @@ -2503,259 +2457,7 @@ static int qcowSetParentFilename(void *pBackendData, const char *pszParentFilena return rc; } -static int qcowAsyncRead(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)); - PQCOWIMAGE pImage = (PQCOWIMAGE)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; - } - - qcowConvertLogicalOffset(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 = qcowConvertToImageOffsetAsync(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 qcowAsyncWrite(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)); - PQCOWIMAGE pImage = (PQCOWIMAGE)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. */ - qcowConvertLogicalOffset(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 = qcowConvertToImageOffsetAsync(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)) - { - PQCOWL2CACHEENTRY 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; - PQCOWCLUSTERASYNCALLOC pL2ClusterAlloc = NULL; - - /* Allocate new async cluster allocation state. */ - pL2ClusterAlloc = (PQCOWCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QCOWCLUSTERASYNCALLOC)); - if (RT_UNLIKELY(!pL2ClusterAlloc)) - { - rc = VERR_NO_MEMORY; - break; - } - - pL2Entry = qcowL2TblCacheEntryAlloc(pImage); - if (!pL2Entry) - { - rc = VERR_NO_MEMORY; - RTMemFree(pL2ClusterAlloc); - break; - } - - offL2Tbl = qcowClusterAllocate(pImage, qcowByte2Cluster(pImage, pImage->cbL2Table)); - pL2Entry->offL2Tbl = offL2Tbl; - memset(pL2Entry->paL2Tbl, 0, pImage->cbL2Table); - - pL2ClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC; - pL2ClusterAlloc->offNextClusterOld = 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->cbL2Table, pIoCtx, - qcowAsyncClusterAllocUpdate, pL2ClusterAlloc); - if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) - break; - else if (RT_FAILURE(rc)) - { - RTMemFree(pL2ClusterAlloc); - qcowL2TblCacheEntryFree(pImage, pL2Entry); - break; - } - - rc = qcowAsyncClusterAllocUpdate(pImage, pIoCtx, pL2ClusterAlloc, rc); - } - else - { - rc = qcowL2TblCacheFetchAsync(pImage, pIoCtx, pImage->paL1Table[idxL1], - &pL2Entry); - - if (RT_SUCCESS(rc)) - { - PQCOWCLUSTERASYNCALLOC pDataClusterAlloc = NULL; - - /* Allocate new async cluster allocation state. */ - pDataClusterAlloc = (PQCOWCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QCOWCLUSTERASYNCALLOC)); - if (RT_UNLIKELY(!pDataClusterAlloc)) - { - rc = VERR_NO_MEMORY; - break; - } - - /* Allocate new cluster for the data. */ - uint64_t offData = qcowClusterAllocate(pImage, 1); - - pDataClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC; - pDataClusterAlloc->offNextClusterOld = 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, - qcowAsyncClusterAllocUpdate, pDataClusterAlloc); - if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) - break; - else if (RT_FAILURE(rc)) - { - RTMemFree(pDataClusterAlloc); - break; - } - - rc = qcowAsyncClusterAllocUpdate(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 qcowAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx) -{ - LogFlowFunc(("pBackendData=%#p\n", pBackendData)); - PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData; - int rc = VINF_SUCCESS; - - Assert(pImage); - - if (VALID_PTR(pIoCtx)) - rc = qcowFlushImageAsync(pImage, pIoCtx); - else - rc = VERR_INVALID_PARAMETER; - - LogFlowFunc(("returns %Rrc\n", rc)); - return rc; -} VBOXHDDBACKEND g_QCowBackend = { @@ -2787,8 +2489,12 @@ VBOXHDDBACKEND g_QCowBackend = qcowWrite, /* pfnFlush */ qcowFlush, + /* pfnDiscard */ + NULL, /* pfnGetVersion */ qcowGetVersion, + /* pfnGetSectorSize */ + qcowGetSectorSize, /* pfnGetSize */ qcowGetSize, /* pfnGetFileSize */ @@ -2839,12 +2545,6 @@ VBOXHDDBACKEND g_QCowBackend = qcowGetParentFilename, /* pfnSetParentFilename */ qcowSetParentFilename, - /* pfnAsyncRead */ - qcowAsyncRead, - /* pfnAsyncWrite */ - qcowAsyncWrite, - /* pfnAsyncFlush */ - qcowAsyncFlush, /* pfnComposeLocation */ genericFileComposeLocation, /* pfnComposeName */ @@ -2853,10 +2553,6 @@ VBOXHDDBACKEND g_QCowBackend = NULL, /* pfnResize */ NULL, - /* pfnDiscard */ - NULL, - /* pfnAsyncDiscard */ - NULL, /* pfnRepair */ NULL }; |