summaryrefslogtreecommitdiff
path: root/src/VBox/Storage/QCOW.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Storage/QCOW.cpp
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-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.cpp670
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
};