VirtualBox

Changeset 38203 in vbox for trunk/src/VBox/Storage


Ignore:
Timestamp:
Jul 27, 2011 4:13:43 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
73171
Message:

VD: New VDCopyEx() API which can speedup cloning of diff images when cloning a VM

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/VD.cpp

    r37329 r38203  
    809809
    810810/**
    811  * internal: read the specified amount of data in whatever blocks the backend
    812  * will give us.
    813  */
    814 static int vdReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
    815                         uint64_t uOffset, void *pvBuf, size_t cbRead,
    816                         bool fZeroFreeBlocks, bool fUpdateCache)
     811 * Extended version of vdReadHelper(), implementing certain optimizations
     812 * for image cloning.
     813 *
     814 * @returns VBox status code.
     815 * @param   pDisk                   The disk to read from.
     816 * @param   pImage                  The image to start reading from.
     817 * @param   pImageParentOverride    The parent image to read from
     818 *                                  if the starting image returns a free block.
     819 *                                  If NULL is passed the real parent of the image
     820 *                                  in the chain is used.
     821 * @param   uOffset                 Offset in the disk to start reading from.
     822 * @param   pvBuf                   Where to store the read data.
     823 * @param   cbRead                  How much to read.
     824 * @param   fZeroFreeBlocks         Flag whether free blocks should be zeroed.
     825 *                                  If false and no image has data for sepcified
     826 *                                  range VERR_VD_BLOCK_FREE is returned.
     827 *                                  Note that unallocated blocks are still zeroed
     828 *                                  if at least one image has valid data for a part
     829 *                                  of the range.
     830 * @param   fUpdateCache            Flag whether to update the attached cache if
     831 *                                  available.
     832 * @param   cImagesRead             Number of images in the chain to read until
     833 *                                  the read is cut off. A value of 0 disables the cut off.
     834 */
     835static int vdReadHelperEx(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
     836                          uint64_t uOffset, void *pvBuf, size_t cbRead,
     837                          bool fZeroFreeBlocks, bool fUpdateCache, unsigned cImagesRead)
    817838{
    818839    int rc = VINF_SUCCESS;
     
    837858            if (rc == VERR_VD_BLOCK_FREE)
    838859            {
    839                 rc = vdDiskReadHelper(pDisk, pImage, pImageParentOverride,
    840                                       uOffset, pvBuf, cbThisRead, &cbThisRead);
     860                rc = vdDiskReadHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbThisRead,
     861                                      &cbThisRead);
    841862
    842863                /* If the read was successful, write the data back into the cache. */
     
    862883                                          &cbThisRead);
    863884
    864             if (rc == VERR_VD_BLOCK_FREE)
     885            if (   rc == VERR_VD_BLOCK_FREE
     886                && cImagesRead != 1)
    865887            {
     888                unsigned cImagesToProcess = cImagesRead;
     889
    866890                for (PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev;
    867891                     pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE;
     
    871895                                                      uOffset, pvBuf, cbThisRead,
    872896                                                      &cbThisRead);
     897                    if (cImagesToProcess == 1)
     898                        break;
     899                    else if (cImagesToProcess > 0)
     900                        cImagesToProcess--;
    873901                }
    874902            }
     
    904932
    905933    return (!fZeroFreeBlocks && fAllFree) ? VERR_VD_BLOCK_FREE : rc;
     934}
     935
     936/**
     937 * internal: read the specified amount of data in whatever blocks the backend
     938 * will give us.
     939 */
     940static int vdReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, uint64_t uOffset,
     941                        void *pvBuf, size_t cbRead, bool fUpdateCache)
     942{
     943    return vdReadHelperEx(pDisk, pImage, NULL, uOffset, pvBuf, cbRead,
     944                          true /* fZeroFreeBlocks */, fUpdateCache, 0);
    906945}
    907946
     
    13771416{
    13781417    PVDPARENTSTATEDESC pParentState = (PVDPARENTSTATEDESC)pvUser;
    1379     return vdReadHelper(pParentState->pDisk, pParentState->pImage, NULL, uOffset,
    1380                         pvBuf, cbRead, true /* fZeroFreeBlocks */,
    1381                         false /* fUpdateCache */);
     1418    return vdReadHelper(pParentState->pDisk, pParentState->pImage, uOffset,
     1419                        pvBuf, cbRead, false /* fUpdateCache */);
    13821420}
    13831421
     
    14471485         * this will be done after the complete block was written.
    14481486         */
    1449         rc = vdReadHelper(pDisk, pImage, pImageParentOverride,
    1450                           uOffset - cbPreRead, pvTmp, cbPreRead,
    1451                           true /* fZeroFreeBlocks*/,
    1452                           false /* fUpdateCache */);
     1487        rc = vdReadHelperEx(pDisk, pImage, pImageParentOverride,
     1488                            uOffset - cbPreRead, pvTmp, cbPreRead,
     1489                            true /* fZeroFreeBlocks*/,
     1490                            false /* fUpdateCache */, 0);
    14531491        if (RT_FAILURE(rc))
    14541492            return rc;
     
    14841522                   (char *)pvBuf + cbThisWrite, cbWriteCopy);
    14851523        if (cbReadImage)
    1486             rc = vdReadHelper(pDisk, pImage, pImageParentOverride,
    1487                               uOffset + cbThisWrite + cbWriteCopy,
    1488                               (char *)pvTmp + cbPreRead + cbThisWrite + cbWriteCopy,
    1489                               cbReadImage, true /* fZeroFreeBlocks */,
    1490                               false /* fUpdateCache */);
     1524            rc = vdReadHelperEx(pDisk, pImage, pImageParentOverride,
     1525                                uOffset + cbThisWrite + cbWriteCopy,
     1526                                (char *)pvTmp + cbPreRead + cbThisWrite + cbWriteCopy,
     1527                                cbReadImage, true /* fZeroFreeBlocks */,
     1528                                false /* fUpdateCache */, 0);
    14911529        if (RT_FAILURE(rc))
    14921530            return rc;
     
    15211559                                  size_t cbThisWrite, size_t cbPreRead,
    15221560                                  size_t cbPostRead, const void *pvBuf,
    1523                                   void *pvTmp)
     1561                                  void *pvTmp, unsigned cImagesRead)
    15241562{
    15251563    size_t cbFill = 0;
     
    15471585    /* Read the entire data of the block so that we can compare whether it will
    15481586     * be modified by the write or not. */
    1549     rc = vdReadHelper(pDisk, pImage, pImageParentOverride, uOffset - cbPreRead, pvTmp,
    1550                       cbPreRead + cbThisWrite + cbPostRead - cbFill,
    1551                       true /* fZeroFreeBlocks */,
    1552                       false /* fUpdateCache */);
     1587    rc = vdReadHelperEx(pDisk, pImage, pImageParentOverride, uOffset - cbPreRead, pvTmp,
     1588                        cbPreRead + cbThisWrite + cbPostRead - cbFill,
     1589                        true /* fZeroFreeBlocks */, false /* fUpdateCache */,
     1590                        cImagesRead);
    15531591    if (RT_FAILURE(rc))
    15541592        return rc;
     
    15961634 * write optimizations.
    15971635 */
    1598 static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage,
    1599                          PVDIMAGE pImageParentOverride, uint64_t uOffset,
    1600                          const void *pvBuf, size_t cbWrite,
    1601                          bool fUpdateCache)
     1636static int vdWriteHelperEx(PVBOXHDD pDisk, PVDIMAGE pImage,
     1637                           PVDIMAGE pImageParentOverride, uint64_t uOffset,
     1638                           const void *pvBuf, size_t cbWrite,
     1639                           bool fUpdateCache, unsigned cImagesRead)
    16021640{
    16031641    int rc;
     
    16361674                                            uOffsetCur, cbWriteCur,
    16371675                                            cbThisWrite, cbPreRead, cbPostRead,
    1638                                             pcvBufCur, pvTmp);
     1676                                            pcvBufCur, pvTmp, cImagesRead);
    16391677            }
    16401678            else
     
    16651703        rc = vdCacheWriteHelper(pDisk->pCache, uOffset, pvBuf, cbWrite, NULL);
    16661704
     1705    return rc;
     1706}
     1707
     1708/**
     1709 * internal: write buffer to the image, taking care of block boundaries and
     1710 * write optimizations.
     1711 */
     1712static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage, uint64_t uOffset,
     1713                         const void *pvBuf, size_t cbWrite, bool fUpdateCache)
     1714{
     1715    return vdWriteHelperEx(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite,
     1716                           fUpdateCache, 0);
     1717}
     1718
     1719/**
     1720 * Internal: Copies the content of one disk to another one applying optimizations
     1721 * to speed up the copy process if possible.
     1722 */
     1723static int vdCopyHelper(PVBOXHDD pDiskFrom, PVDIMAGE pImageFrom, PVBOXHDD pDiskTo,
     1724                        uint64_t cbSize, unsigned cImagesFromRead, unsigned cImagesToRead,
     1725                        bool fSuppressRedundantIo,
     1726                        PVDINTERFACE pIfProgress, PVDINTERFACEPROGRESS pCbProgress,
     1727                        PVDINTERFACE pDstIfProgress, PVDINTERFACEPROGRESS pDstCbProgress)
     1728{
     1729    int rc = VINF_SUCCESS;
     1730    int rc2;
     1731    uint64_t uOffset = 0;
     1732    uint64_t cbRemaining = cbSize;
     1733    void *pvBuf = NULL;
     1734    bool fLockReadFrom = false;
     1735    bool fLockWriteTo = false;
     1736    bool fBlockwiseCopy = fSuppressRedundantIo || (cImagesFromRead > 0);
     1737    unsigned uProgressOld = 0;
     1738
     1739    LogFlowFunc(("pDiskFrom=%#p pImageFrom=%#p pDiskTo=%#p cbSize=%llu cImagesFromRead=%u cImagesToRead=%u fSuppressRedundantIo=%RTbool pIfProgress=%#p pCbProgress=%#p pDstIfProgress=%#p pDstCbProgress=%#p\n",
     1740                 pDiskFrom, pImageFrom, pDiskTo, cbSize, cImagesFromRead, cImagesToRead, fSuppressRedundantIo, pIfProgress, pCbProgress, pDstIfProgress, pDstCbProgress));
     1741
     1742    /* Allocate tmp buffer. */
     1743    pvBuf = RTMemTmpAlloc(VD_MERGE_BUFFER_SIZE);
     1744    if (!pvBuf)
     1745        return rc;
     1746
     1747    do
     1748    {
     1749        size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining);
     1750
     1751        /* Note that we don't attempt to synchronize cross-disk accesses.
     1752         * It wouldn't be very difficult to do, just the lock order would
     1753         * need to be defined somehow to prevent deadlocks. Postpone such
     1754         * magic as there is no use case for this. */
     1755
     1756        rc2 = vdThreadStartRead(pDiskFrom);
     1757        AssertRC(rc2);
     1758        fLockReadFrom = true;
     1759
     1760        if (fBlockwiseCopy)
     1761        {
     1762            /* Read the source data. */
     1763            rc = pImageFrom->Backend->pfnRead(pImageFrom->pBackendData,
     1764                                              uOffset, pvBuf, cbThisRead,
     1765                                              &cbThisRead);
     1766
     1767            if (   rc == VERR_VD_BLOCK_FREE
     1768                && cImagesFromRead != 1)
     1769            {
     1770                unsigned cImagesToProcess = cImagesFromRead;
     1771
     1772                for (PVDIMAGE pCurrImage = pImageFrom->pPrev;
     1773                     pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE;
     1774                     pCurrImage = pCurrImage->pPrev)
     1775                {
     1776                    rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData,
     1777                                                      uOffset, pvBuf, cbThisRead,
     1778                                                      &cbThisRead);
     1779                    if (cImagesToProcess == 1)
     1780                        break;
     1781                    else if (cImagesToProcess > 0)
     1782                        cImagesToProcess--;
     1783                }
     1784            }
     1785        }
     1786        else
     1787            rc = vdReadHelper(pDiskFrom, pImageFrom, uOffset, pvBuf, cbThisRead,
     1788                              false /* fUpdateCache */);
     1789
     1790        if (RT_FAILURE(rc) && rc != VERR_VD_BLOCK_FREE)
     1791            break;
     1792
     1793        rc2 = vdThreadFinishRead(pDiskFrom);
     1794        AssertRC(rc2);
     1795        fLockReadFrom = false;
     1796
     1797        if (rc != VERR_VD_BLOCK_FREE)
     1798        {
     1799            rc2 = vdThreadStartWrite(pDiskTo);
     1800            AssertRC(rc2);
     1801            fLockWriteTo = true;
     1802
     1803            /* Only do collapsed I/O if we are copying the data blockwise. */
     1804            rc = vdWriteHelperEx(pDiskTo, pDiskTo->pLast, NULL, uOffset, pvBuf,
     1805                                 cbThisRead, false /* fUpdateCache */,
     1806                                 fBlockwiseCopy ? cImagesToRead : 0);
     1807            if (RT_FAILURE(rc))
     1808                break;
     1809
     1810            rc2 = vdThreadFinishWrite(pDiskTo);
     1811            AssertRC(rc2);
     1812            fLockWriteTo = false;
     1813        }
     1814        else /* Don't propagate the error to the outside */
     1815            rc = VINF_SUCCESS;
     1816
     1817        uOffset += cbThisRead;
     1818        cbRemaining -= cbThisRead;
     1819
     1820        unsigned uProgressNew = uOffset * 99 / cbSize;
     1821        if (uProgressNew != uProgressOld)
     1822        {
     1823            uProgressOld = uProgressNew;
     1824
     1825            if (pCbProgress && pCbProgress->pfnProgress)
     1826            {
     1827                rc = pCbProgress->pfnProgress(pIfProgress->pvUser,
     1828                                              uProgressOld);
     1829                if (RT_FAILURE(rc))
     1830                    break;
     1831            }
     1832            if (pDstCbProgress && pDstCbProgress->pfnProgress)
     1833            {
     1834                rc = pDstCbProgress->pfnProgress(pDstIfProgress->pvUser,
     1835                                                 uProgressOld);
     1836                if (RT_FAILURE(rc))
     1837                    break;
     1838            }
     1839        }
     1840    } while (uOffset < cbSize);
     1841
     1842    RTMemFree(pvBuf);
     1843
     1844    if (fLockReadFrom)
     1845    {
     1846        rc2 = vdThreadFinishRead(pDiskFrom);
     1847        AssertRC(rc2);
     1848    }
     1849
     1850    if (fLockWriteTo)
     1851    {
     1852        rc2 = vdThreadFinishWrite(pDiskTo);
     1853        AssertRC(rc2);
     1854    }
     1855
     1856    LogFlowFunc(("returns rc=%Rrc\n", rc));
    16671857    return rc;
    16681858}
     
    55035693                            break;
    55045694                        /* Updating the cache is required because this might be a live merge. */
    5505                         rc = vdWriteHelper(pDisk, pImageTo, pImageFrom->pPrev,
    5506                                            uOffset, pvBuf, cbThisRead,
    5507                                            true /* fUpdateCache */);
     5695                        rc = vdWriteHelperEx(pDisk, pImageTo, pImageFrom->pPrev,
     5696                                             uOffset, pvBuf, cbThisRead,
     5697                                             true /* fUpdateCache */, 0);
    55085698                        if (RT_FAILURE(rc))
    55095699                            break;
     
    56185808                    if (RT_FAILURE(rc))
    56195809                        break;
    5620                     rc = vdWriteHelper(pDisk, pImageTo, NULL, uOffset, pvBuf,
     5810                    rc = vdWriteHelper(pDisk, pImageTo, uOffset, pvBuf,
    56215811                                       cbThisRead, true /* fUpdateCache */);
    56225812                    if (RT_FAILURE(rc))
     
    57685958    if (RT_SUCCESS(rc) && pCbProgress && pCbProgress->pfnProgress)
    57695959        pCbProgress->pfnProgress(pIfProgress->pvUser, 100);
     5960
     5961    LogFlowFunc(("returns %Rrc\n", rc));
     5962    return rc;
     5963}
     5964
     5965/**
     5966 * Copies an image from one HDD container to another - extended version.
     5967 * The copy is opened in the target HDD container.
     5968 * It is possible to convert between different image formats, because the
     5969 * backend for the destination may be different from the source.
     5970 * If both the source and destination reference the same HDD container,
     5971 * then the image is moved (by copying/deleting or renaming) to the new location.
     5972 * The source container is unchanged if the move operation fails, otherwise
     5973 * the image at the new location is opened in the same way as the old one was.
     5974 *
     5975 * @note The read/write accesses across disks are not synchronized, just the
     5976 * accesses to each disk. Once there is a use case which requires a defined
     5977 * read/write behavior in this situation this needs to be extended.
     5978 *
     5979 * @return  VBox status code.
     5980 * @return  VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened.
     5981 * @param   pDiskFrom       Pointer to source HDD container.
     5982 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     5983 * @param   pDiskTo         Pointer to destination HDD container.
     5984 * @param   pszBackend      Name of the image file backend to use (may be NULL to use the same as the source, case insensitive).
     5985 * @param   pszFilename     New name of the image (may be NULL to specify that the
     5986 *                          copy destination is the destination container, or
     5987 *                          if pDiskFrom == pDiskTo, i.e. when moving).
     5988 * @param   fMoveByRename   If true, attempt to perform a move by renaming (if successful the new size is ignored).
     5989 * @param   cbSize          New image size (0 means leave unchanged).
     5990 * @param   nImageSameFrom  todo
     5991 * @param   nImageSameTo    todo
     5992 * @param   uImageFlags     Flags specifying special destination image features.
     5993 * @param   pDstUuid        New UUID of the destination image. If NULL, a new UUID is created.
     5994 *                          This parameter is used if and only if a true copy is created.
     5995 *                          In all rename/move cases or copy to existing image cases the modification UUIDs are copied over.
     5996 * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
     5997 *                          Only used if the destination image is created.
     5998 * @param   pVDIfsOperation Pointer to the per-operation VD interface list.
     5999 * @param   pDstVDIfsImage  Pointer to the per-image VD interface list, for the
     6000 *                          destination image.
     6001 * @param   pDstVDIfsOperation Pointer to the per-operation VD interface list,
     6002 *                          for the destination operation.
     6003 */
     6004VBOXDDU_DECL(int) VDCopyEx(PVBOXHDD pDiskFrom, unsigned nImage, PVBOXHDD pDiskTo,
     6005                           const char *pszBackend, const char *pszFilename,
     6006                           bool fMoveByRename, uint64_t cbSize,
     6007                           unsigned nImageFromSame, unsigned nImageToSame,
     6008                           unsigned uImageFlags, PCRTUUID pDstUuid,
     6009                           unsigned uOpenFlags, PVDINTERFACE pVDIfsOperation,
     6010                           PVDINTERFACE pDstVDIfsImage,
     6011                           PVDINTERFACE pDstVDIfsOperation)
     6012{
     6013    int rc = VINF_SUCCESS;
     6014    int rc2;
     6015    bool fLockReadFrom = false, fLockWriteFrom = false, fLockWriteTo = false;
     6016    PVDIMAGE pImageTo = NULL;
     6017
     6018    LogFlowFunc(("pDiskFrom=%#p nImage=%u pDiskTo=%#p pszBackend=\"%s\" pszFilename=\"%s\" fMoveByRename=%d cbSize=%llu uImageFlags=%#x pDstUuid=%#p uOpenFlags=%#x pVDIfsOperation=%#p pDstVDIfsImage=%#p pDstVDIfsOperation=%#p\n",
     6019                 pDiskFrom, nImage, pDiskTo, pszBackend, pszFilename, fMoveByRename, cbSize, uImageFlags, pDstUuid, uOpenFlags, pVDIfsOperation, pDstVDIfsImage, pDstVDIfsOperation));
     6020
     6021    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     6022                                              VDINTERFACETYPE_PROGRESS);
     6023    PVDINTERFACEPROGRESS pCbProgress = NULL;
     6024    if (pIfProgress)
     6025        pCbProgress = VDGetInterfaceProgress(pIfProgress);
     6026
     6027    PVDINTERFACE pDstIfProgress = VDInterfaceGet(pDstVDIfsOperation,
     6028                                                 VDINTERFACETYPE_PROGRESS);
     6029    PVDINTERFACEPROGRESS pDstCbProgress = NULL;
     6030    if (pDstIfProgress)
     6031        pDstCbProgress = VDGetInterfaceProgress(pDstIfProgress);
     6032
     6033    do {
     6034        /* Check arguments. */
     6035        AssertMsgBreakStmt(VALID_PTR(pDiskFrom), ("pDiskFrom=%#p\n", pDiskFrom),
     6036                           rc = VERR_INVALID_PARAMETER);
     6037        AssertMsg(pDiskFrom->u32Signature == VBOXHDDDISK_SIGNATURE,
     6038                  ("u32Signature=%08x\n", pDiskFrom->u32Signature));
     6039
     6040        rc2 = vdThreadStartRead(pDiskFrom);
     6041        AssertRC(rc2);
     6042        fLockReadFrom = true;
     6043        PVDIMAGE pImageFrom = vdGetImageByNumber(pDiskFrom, nImage);
     6044        AssertPtrBreakStmt(pImageFrom, rc = VERR_VD_IMAGE_NOT_FOUND);
     6045        AssertMsgBreakStmt(VALID_PTR(pDiskTo), ("pDiskTo=%#p\n", pDiskTo),
     6046                           rc = VERR_INVALID_PARAMETER);
     6047        AssertMsg(pDiskTo->u32Signature == VBOXHDDDISK_SIGNATURE,
     6048                  ("u32Signature=%08x\n", pDiskTo->u32Signature));
     6049        AssertMsgBreakStmt(   (nImageFromSame < nImage || nImageFromSame == VD_IMAGE_CONTENT_UNKNOWN)
     6050                           && (nImageToSame < pDiskTo->cImages || nImageToSame == VD_IMAGE_CONTENT_UNKNOWN)
     6051                           && (   (nImageFromSame == VD_IMAGE_CONTENT_UNKNOWN && nImageToSame == VD_IMAGE_CONTENT_UNKNOWN)
     6052                               || (nImageFromSame != VD_IMAGE_CONTENT_UNKNOWN && nImageToSame != VD_IMAGE_CONTENT_UNKNOWN)),
     6053                           ("nImageFromSame=%u nImageToSame=%u\n", nImageFromSame, nImageToSame),
     6054                           rc = VERR_INVALID_PARAMETER);
     6055
     6056        /* Move the image. */
     6057        if (pDiskFrom == pDiskTo)
     6058        {
     6059            /* Rename only works when backends are the same, are file based
     6060             * and the rename method is implemented. */
     6061            if (    fMoveByRename
     6062                &&  !RTStrICmp(pszBackend, pImageFrom->Backend->pszBackendName)
     6063                &&  pImageFrom->Backend->uBackendCaps & VD_CAP_FILE
     6064                &&  pImageFrom->Backend->pfnRename)
     6065            {
     6066                rc2 = vdThreadFinishRead(pDiskFrom);
     6067                AssertRC(rc2);
     6068                fLockReadFrom = false;
     6069
     6070                rc2 = vdThreadStartWrite(pDiskFrom);
     6071                AssertRC(rc2);
     6072                fLockWriteFrom = true;
     6073                rc = pImageFrom->Backend->pfnRename(pImageFrom->pBackendData, pszFilename ? pszFilename : pImageFrom->pszFilename);
     6074                break;
     6075            }
     6076
     6077            /** @todo Moving (including shrinking/growing) of the image is
     6078             * requested, but the rename attempt failed or it wasn't possible.
     6079             * Must now copy image to temp location. */
     6080            AssertReleaseMsgFailed(("VDCopy: moving by copy/delete not implemented\n"));
     6081        }
     6082
     6083        /* pszFilename is allowed to be NULL, as this indicates copy to the existing image. */
     6084        AssertMsgBreakStmt(pszFilename == NULL || (VALID_PTR(pszFilename) && *pszFilename),
     6085                           ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename),
     6086                           rc = VERR_INVALID_PARAMETER);
     6087
     6088        uint64_t cbSizeFrom;
     6089        cbSizeFrom = pImageFrom->Backend->pfnGetSize(pImageFrom->pBackendData);
     6090        if (cbSizeFrom == 0)
     6091        {
     6092            rc = VERR_VD_VALUE_NOT_FOUND;
     6093            break;
     6094        }
     6095
     6096        VDGEOMETRY PCHSGeometryFrom = {0, 0, 0};
     6097        VDGEOMETRY LCHSGeometryFrom = {0, 0, 0};
     6098        pImageFrom->Backend->pfnGetPCHSGeometry(pImageFrom->pBackendData, &PCHSGeometryFrom);
     6099        pImageFrom->Backend->pfnGetLCHSGeometry(pImageFrom->pBackendData, &LCHSGeometryFrom);
     6100
     6101        RTUUID ImageUuid, ImageModificationUuid;
     6102        if (pDiskFrom != pDiskTo)
     6103        {
     6104            if (pDstUuid)
     6105                ImageUuid = *pDstUuid;
     6106            else
     6107                RTUuidCreate(&ImageUuid);
     6108        }
     6109        else
     6110        {
     6111            rc = pImageFrom->Backend->pfnGetUuid(pImageFrom->pBackendData, &ImageUuid);
     6112            if (RT_FAILURE(rc))
     6113                RTUuidCreate(&ImageUuid);
     6114        }
     6115        rc = pImageFrom->Backend->pfnGetModificationUuid(pImageFrom->pBackendData, &ImageModificationUuid);
     6116        if (RT_FAILURE(rc))
     6117            RTUuidClear(&ImageModificationUuid);
     6118
     6119        char szComment[1024];
     6120        rc = pImageFrom->Backend->pfnGetComment(pImageFrom->pBackendData, szComment, sizeof(szComment));
     6121        if (RT_FAILURE(rc))
     6122            szComment[0] = '\0';
     6123        else
     6124            szComment[sizeof(szComment) - 1] = '\0';
     6125
     6126        rc2 = vdThreadFinishRead(pDiskFrom);
     6127        AssertRC(rc2);
     6128        fLockReadFrom = false;
     6129
     6130        rc2 = vdThreadStartRead(pDiskTo);
     6131        AssertRC(rc2);
     6132        unsigned cImagesTo = pDiskTo->cImages;
     6133        rc2 = vdThreadFinishRead(pDiskTo);
     6134        AssertRC(rc2);
     6135
     6136        if (pszFilename)
     6137        {
     6138            if (cbSize == 0)
     6139                cbSize = cbSizeFrom;
     6140
     6141            /* Create destination image with the properties of source image. */
     6142            /** @todo replace the VDCreateDiff/VDCreateBase calls by direct
     6143             * calls to the backend. Unifies the code and reduces the API
     6144             * dependencies. Would also make the synchronization explicit. */
     6145            if (cImagesTo > 0)
     6146            {
     6147                rc = VDCreateDiff(pDiskTo, pszBackend, pszFilename,
     6148                                  uImageFlags, szComment, &ImageUuid,
     6149                                  NULL /* pParentUuid */,
     6150                                  uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
     6151                                  pDstVDIfsImage, NULL);
     6152
     6153                rc2 = vdThreadStartWrite(pDiskTo);
     6154                AssertRC(rc2);
     6155                fLockWriteTo = true;
     6156            } else {
     6157                /** @todo hack to force creation of a fixed image for
     6158                 * the RAW backend, which can't handle anything else. */
     6159                if (!RTStrICmp(pszBackend, "RAW"))
     6160                    uImageFlags |= VD_IMAGE_FLAGS_FIXED;
     6161
     6162                vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize);
     6163                vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize);
     6164
     6165                rc = VDCreateBase(pDiskTo, pszBackend, pszFilename, cbSize,
     6166                                  uImageFlags, szComment,
     6167                                  &PCHSGeometryFrom, &LCHSGeometryFrom,
     6168                                  NULL, uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
     6169                                  pDstVDIfsImage, NULL);
     6170
     6171                rc2 = vdThreadStartWrite(pDiskTo);
     6172                AssertRC(rc2);
     6173                fLockWriteTo = true;
     6174
     6175                if (RT_SUCCESS(rc) && !RTUuidIsNull(&ImageUuid))
     6176                     pDiskTo->pLast->Backend->pfnSetUuid(pDiskTo->pLast->pBackendData, &ImageUuid);
     6177            }
     6178            if (RT_FAILURE(rc))
     6179                break;
     6180
     6181            pImageTo = pDiskTo->pLast;
     6182            AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND);
     6183
     6184            cbSize = RT_MIN(cbSize, cbSizeFrom);
     6185        }
     6186        else
     6187        {
     6188            pImageTo = pDiskTo->pLast;
     6189            AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND);
     6190
     6191            uint64_t cbSizeTo;
     6192            cbSizeTo = pImageTo->Backend->pfnGetSize(pImageTo->pBackendData);
     6193            if (cbSizeTo == 0)
     6194            {
     6195                rc = VERR_VD_VALUE_NOT_FOUND;
     6196                break;
     6197            }
     6198
     6199            if (cbSize == 0)
     6200                cbSize = RT_MIN(cbSizeFrom, cbSizeTo);
     6201
     6202            vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize);
     6203            vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize);
     6204
     6205            /* Update the geometry in the destination image. */
     6206            pImageTo->Backend->pfnSetPCHSGeometry(pImageTo->pBackendData, &PCHSGeometryFrom);
     6207            pImageTo->Backend->pfnSetLCHSGeometry(pImageTo->pBackendData, &LCHSGeometryFrom);
     6208        }
     6209
     6210        rc2 = vdThreadFinishWrite(pDiskTo);
     6211        AssertRC(rc2);
     6212        fLockWriteTo = false;
     6213
     6214        /* Whether we can take the optimized copy path (false) or not.
     6215         * Don't optimize if the image existed or if it is a child image. */
     6216        bool fSuppressRedundantIo = (   !(pszFilename == NULL || cImagesTo > 0)
     6217                                     || (nImageToSame != UINT32_MAX));
     6218
     6219        /* Copy the data. */
     6220        rc = vdCopyHelper(pDiskFrom, pImageFrom, pDiskTo, cbSize,
     6221                          nImageFromSame == VD_IMAGE_CONTENT_UNKNOWN ? 0 : nImage - nImageFromSame,
     6222                          nImageToSame == VD_IMAGE_CONTENT_UNKNOWN ? 0 : pDiskTo->cImages - nImageToSame + 1,
     6223                          fSuppressRedundantIo, pIfProgress, pCbProgress,
     6224                          pDstIfProgress, pDstCbProgress);
     6225
     6226        if (RT_SUCCESS(rc))
     6227        {
     6228            rc2 = vdThreadStartWrite(pDiskTo);
     6229            AssertRC(rc2);
     6230            fLockWriteTo = true;
     6231
     6232            /* Only set modification UUID if it is non-null, since the source
     6233             * backend might not provide a valid modification UUID. */
     6234            if (!RTUuidIsNull(&ImageModificationUuid))
     6235                pImageTo->Backend->pfnSetModificationUuid(pImageTo->pBackendData, &ImageModificationUuid);
     6236
     6237            /* Set the requested open flags if they differ from the value
     6238             * required for creating the image and copying the contents. */
     6239            if (   pImageTo && pszFilename
     6240                && uOpenFlags != (uOpenFlags & ~VD_OPEN_FLAGS_READONLY))
     6241                rc = pImageTo->Backend->pfnSetOpenFlags(pImageTo->pBackendData,
     6242                                                        uOpenFlags);
     6243        }
     6244    } while (0);
     6245
     6246    if (RT_FAILURE(rc) && pImageTo && pszFilename)
     6247    {
     6248        /* Take the write lock only if it is not taken. Not worth making the
     6249         * above code even more complicated. */
     6250        if (RT_UNLIKELY(!fLockWriteTo))
     6251        {
     6252            rc2 = vdThreadStartWrite(pDiskTo);
     6253            AssertRC(rc2);
     6254            fLockWriteTo = true;
     6255        }
     6256        /* Error detected, but new image created. Remove image from list. */
     6257        vdRemoveImageFromList(pDiskTo, pImageTo);
     6258
     6259        /* Close and delete image. */
     6260        rc2 = pImageTo->Backend->pfnClose(pImageTo->pBackendData, true);
     6261        AssertRC(rc2);
     6262        pImageTo->pBackendData = NULL;
     6263
     6264        /* Free remaining resources. */
     6265        if (pImageTo->pszFilename)
     6266            RTStrFree(pImageTo->pszFilename);
     6267
     6268        RTMemFree(pImageTo);
     6269    }
     6270
     6271    if (RT_UNLIKELY(fLockWriteTo))
     6272    {
     6273        rc2 = vdThreadFinishWrite(pDiskTo);
     6274        AssertRC(rc2);
     6275    }
     6276    if (RT_UNLIKELY(fLockWriteFrom))
     6277    {
     6278        rc2 = vdThreadFinishWrite(pDiskFrom);
     6279        AssertRC(rc2);
     6280    }
     6281    else if (RT_UNLIKELY(fLockReadFrom))
     6282    {
     6283        rc2 = vdThreadFinishRead(pDiskFrom);
     6284        AssertRC(rc2);
     6285    }
     6286
     6287    if (RT_SUCCESS(rc))
     6288    {
     6289        if (pCbProgress && pCbProgress->pfnProgress)
     6290            pCbProgress->pfnProgress(pIfProgress->pvUser, 100);
     6291        if (pDstCbProgress && pDstCbProgress->pfnProgress)
     6292            pDstCbProgress->pfnProgress(pDstIfProgress->pvUser, 100);
     6293    }
    57706294
    57716295    LogFlowFunc(("returns %Rrc\n", rc));
     
    58126336                         PVDINTERFACE pDstVDIfsOperation)
    58136337{
    5814     int rc = VINF_SUCCESS;
    5815     int rc2;
    5816     bool fLockReadFrom = false, fLockWriteFrom = false, fLockWriteTo = false;
    5817     void *pvBuf = NULL;
    5818     PVDIMAGE pImageTo = NULL;
    5819 
    5820     LogFlowFunc(("pDiskFrom=%#p nImage=%u pDiskTo=%#p pszBackend=\"%s\" pszFilename=\"%s\" fMoveByRename=%d cbSize=%llu uImageFlags=%#x pDstUuid=%#p uOpenFlags=%#x pVDIfsOperation=%#p pDstVDIfsImage=%#p pDstVDIfsOperation=%#p\n",
    5821                  pDiskFrom, nImage, pDiskTo, pszBackend, pszFilename, fMoveByRename, cbSize, uImageFlags, pDstUuid, uOpenFlags, pVDIfsOperation, pDstVDIfsImage, pDstVDIfsOperation));
    5822 
    5823     PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
    5824                                               VDINTERFACETYPE_PROGRESS);
    5825     PVDINTERFACEPROGRESS pCbProgress = NULL;
    5826     if (pIfProgress)
    5827         pCbProgress = VDGetInterfaceProgress(pIfProgress);
    5828 
    5829     PVDINTERFACE pDstIfProgress = VDInterfaceGet(pDstVDIfsOperation,
    5830                                                  VDINTERFACETYPE_PROGRESS);
    5831     PVDINTERFACEPROGRESS pDstCbProgress = NULL;
    5832     if (pDstIfProgress)
    5833         pDstCbProgress = VDGetInterfaceProgress(pDstIfProgress);
    5834 
    5835     do {
    5836         /* Check arguments. */
    5837         AssertMsgBreakStmt(VALID_PTR(pDiskFrom), ("pDiskFrom=%#p\n", pDiskFrom),
    5838                            rc = VERR_INVALID_PARAMETER);
    5839         AssertMsg(pDiskFrom->u32Signature == VBOXHDDDISK_SIGNATURE,
    5840                   ("u32Signature=%08x\n", pDiskFrom->u32Signature));
    5841 
    5842         rc2 = vdThreadStartRead(pDiskFrom);
    5843         AssertRC(rc2);
    5844         fLockReadFrom = true;
    5845         PVDIMAGE pImageFrom = vdGetImageByNumber(pDiskFrom, nImage);
    5846         AssertPtrBreakStmt(pImageFrom, rc = VERR_VD_IMAGE_NOT_FOUND);
    5847         AssertMsgBreakStmt(VALID_PTR(pDiskTo), ("pDiskTo=%#p\n", pDiskTo),
    5848                            rc = VERR_INVALID_PARAMETER);
    5849         AssertMsg(pDiskTo->u32Signature == VBOXHDDDISK_SIGNATURE,
    5850                   ("u32Signature=%08x\n", pDiskTo->u32Signature));
    5851 
    5852         /* Move the image. */
    5853         if (pDiskFrom == pDiskTo)
    5854         {
    5855             /* Rename only works when backends are the same, are file based
    5856              * and the rename method is implemented. */
    5857             if (    fMoveByRename
    5858                 &&  !RTStrICmp(pszBackend, pImageFrom->Backend->pszBackendName)
    5859                 &&  pImageFrom->Backend->uBackendCaps & VD_CAP_FILE
    5860                 &&  pImageFrom->Backend->pfnRename)
    5861             {
    5862                 rc2 = vdThreadFinishRead(pDiskFrom);
    5863                 AssertRC(rc2);
    5864                 fLockReadFrom = false;
    5865 
    5866                 rc2 = vdThreadStartWrite(pDiskFrom);
    5867                 AssertRC(rc2);
    5868                 fLockWriteFrom = true;
    5869                 rc = pImageFrom->Backend->pfnRename(pImageFrom->pBackendData, pszFilename ? pszFilename : pImageFrom->pszFilename);
    5870                 break;
    5871             }
    5872 
    5873             /** @todo Moving (including shrinking/growing) of the image is
    5874              * requested, but the rename attempt failed or it wasn't possible.
    5875              * Must now copy image to temp location. */
    5876             AssertReleaseMsgFailed(("VDCopy: moving by copy/delete not implemented\n"));
    5877         }
    5878 
    5879         /* pszFilename is allowed to be NULL, as this indicates copy to the existing image. */
    5880         AssertMsgBreakStmt(pszFilename == NULL || (VALID_PTR(pszFilename) && *pszFilename),
    5881                            ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename),
    5882                            rc = VERR_INVALID_PARAMETER);
    5883 
    5884         uint64_t cbSizeFrom;
    5885         cbSizeFrom = pImageFrom->Backend->pfnGetSize(pImageFrom->pBackendData);
    5886         if (cbSizeFrom == 0)
    5887         {
    5888             rc = VERR_VD_VALUE_NOT_FOUND;
    5889             break;
    5890         }
    5891 
    5892         VDGEOMETRY PCHSGeometryFrom = {0, 0, 0};
    5893         VDGEOMETRY LCHSGeometryFrom = {0, 0, 0};
    5894         pImageFrom->Backend->pfnGetPCHSGeometry(pImageFrom->pBackendData, &PCHSGeometryFrom);
    5895         pImageFrom->Backend->pfnGetLCHSGeometry(pImageFrom->pBackendData, &LCHSGeometryFrom);
    5896 
    5897         RTUUID ImageUuid, ImageModificationUuid;
    5898         if (pDiskFrom != pDiskTo)
    5899         {
    5900             if (pDstUuid)
    5901                 ImageUuid = *pDstUuid;
    5902             else
    5903                 RTUuidCreate(&ImageUuid);
    5904         }
    5905         else
    5906         {
    5907             rc = pImageFrom->Backend->pfnGetUuid(pImageFrom->pBackendData, &ImageUuid);
    5908             if (RT_FAILURE(rc))
    5909                 RTUuidCreate(&ImageUuid);
    5910         }
    5911         rc = pImageFrom->Backend->pfnGetModificationUuid(pImageFrom->pBackendData, &ImageModificationUuid);
    5912         if (RT_FAILURE(rc))
    5913             RTUuidClear(&ImageModificationUuid);
    5914 
    5915         char szComment[1024];
    5916         rc = pImageFrom->Backend->pfnGetComment(pImageFrom->pBackendData, szComment, sizeof(szComment));
    5917         if (RT_FAILURE(rc))
    5918             szComment[0] = '\0';
    5919         else
    5920             szComment[sizeof(szComment) - 1] = '\0';
    5921 
    5922         rc2 = vdThreadFinishRead(pDiskFrom);
    5923         AssertRC(rc2);
    5924         fLockReadFrom = false;
    5925 
    5926         rc2 = vdThreadStartRead(pDiskTo);
    5927         AssertRC(rc2);
    5928         unsigned cImagesTo = pDiskTo->cImages;
    5929         rc2 = vdThreadFinishRead(pDiskTo);
    5930         AssertRC(rc2);
    5931 
    5932         if (pszFilename)
    5933         {
    5934             if (cbSize == 0)
    5935                 cbSize = cbSizeFrom;
    5936 
    5937             /* Create destination image with the properties of source image. */
    5938             /** @todo replace the VDCreateDiff/VDCreateBase calls by direct
    5939              * calls to the backend. Unifies the code and reduces the API
    5940              * dependencies. Would also make the synchronization explicit. */
    5941             if (cImagesTo > 0)
    5942             {
    5943                 rc = VDCreateDiff(pDiskTo, pszBackend, pszFilename,
    5944                                   uImageFlags, szComment, &ImageUuid,
    5945                                   NULL /* pParentUuid */,
    5946                                   uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
    5947                                   pDstVDIfsImage, NULL);
    5948 
    5949                 rc2 = vdThreadStartWrite(pDiskTo);
    5950                 AssertRC(rc2);
    5951                 fLockWriteTo = true;
    5952             } else {
    5953                 /** @todo hack to force creation of a fixed image for
    5954                  * the RAW backend, which can't handle anything else. */
    5955                 if (!RTStrICmp(pszBackend, "RAW"))
    5956                     uImageFlags |= VD_IMAGE_FLAGS_FIXED;
    5957 
    5958                 vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize);
    5959                 vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize);
    5960 
    5961                 rc = VDCreateBase(pDiskTo, pszBackend, pszFilename, cbSize,
    5962                                   uImageFlags, szComment,
    5963                                   &PCHSGeometryFrom, &LCHSGeometryFrom,
    5964                                   NULL, uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
    5965                                   pDstVDIfsImage, NULL);
    5966 
    5967                 rc2 = vdThreadStartWrite(pDiskTo);
    5968                 AssertRC(rc2);
    5969                 fLockWriteTo = true;
    5970 
    5971                 if (RT_SUCCESS(rc) && !RTUuidIsNull(&ImageUuid))
    5972                      pDiskTo->pLast->Backend->pfnSetUuid(pDiskTo->pLast->pBackendData, &ImageUuid);
    5973             }
    5974             if (RT_FAILURE(rc))
    5975                 break;
    5976 
    5977             pImageTo = pDiskTo->pLast;
    5978             AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND);
    5979 
    5980             cbSize = RT_MIN(cbSize, cbSizeFrom);
    5981         }
    5982         else
    5983         {
    5984             pImageTo = pDiskTo->pLast;
    5985             AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND);
    5986 
    5987             uint64_t cbSizeTo;
    5988             cbSizeTo = pImageTo->Backend->pfnGetSize(pImageTo->pBackendData);
    5989             if (cbSizeTo == 0)
    5990             {
    5991                 rc = VERR_VD_VALUE_NOT_FOUND;
    5992                 break;
    5993             }
    5994 
    5995             if (cbSize == 0)
    5996                 cbSize = RT_MIN(cbSizeFrom, cbSizeTo);
    5997 
    5998             vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize);
    5999             vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize);
    6000 
    6001             /* Update the geometry in the destination image. */
    6002             pImageTo->Backend->pfnSetPCHSGeometry(pImageTo->pBackendData, &PCHSGeometryFrom);
    6003             pImageTo->Backend->pfnSetLCHSGeometry(pImageTo->pBackendData, &LCHSGeometryFrom);
    6004         }
    6005 
    6006         rc2 = vdThreadFinishWrite(pDiskTo);
    6007         AssertRC(rc2);
    6008         fLockWriteTo = false;
    6009 
    6010         /* Allocate tmp buffer. */
    6011         pvBuf = RTMemTmpAlloc(VD_MERGE_BUFFER_SIZE);
    6012         if (!pvBuf)
    6013         {
    6014             rc = VERR_NO_MEMORY;
    6015             break;
    6016         }
    6017 
    6018         /* Whether we can take the optimized copy path (false) or not.
    6019          * Don't optimize if the image existed or if it is a child image. */
    6020         bool fRegularRead = (pszFilename == NULL) || (cImagesTo > 0);
    6021 
    6022         /* Copy the data. */
    6023         uint64_t uOffset = 0;
    6024         uint64_t cbRemaining = cbSize;
    6025 
    6026         do
    6027         {
    6028             size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining);
    6029 
    6030             /* Note that we don't attempt to synchronize cross-disk accesses.
    6031              * It wouldn't be very difficult to do, just the lock order would
    6032              * need to be defined somehow to prevent deadlocks. Postpone such
    6033              * magic as there is no use case for this. */
    6034 
    6035             rc2 = vdThreadStartRead(pDiskFrom);
    6036             AssertRC(rc2);
    6037             fLockReadFrom = true;
    6038 
    6039             /*
    6040              * Updating the cache doesn't make any sense
    6041              * as we are looping once through the image.
    6042              */
    6043             rc = vdReadHelper(pDiskFrom, pImageFrom, NULL, uOffset, pvBuf,
    6044                               cbThisRead, fRegularRead,
    6045                               false /* fUpdateCache */);
    6046             if (RT_FAILURE(rc) && rc != VERR_VD_BLOCK_FREE)
    6047                 break;
    6048 
    6049             rc2 = vdThreadFinishRead(pDiskFrom);
    6050             AssertRC(rc2);
    6051             fLockReadFrom = false;
    6052 
    6053             if (rc != VERR_VD_BLOCK_FREE)
    6054             {
    6055                 rc2 = vdThreadStartWrite(pDiskTo);
    6056                 AssertRC(rc2);
    6057                 fLockWriteTo = true;
    6058 
    6059                 rc = vdWriteHelper(pDiskTo, pImageTo, NULL, uOffset, pvBuf,
    6060                                    cbThisRead, false /* fUpdateCache */);
    6061                 if (RT_FAILURE(rc))
    6062                     break;
    6063 
    6064                 rc2 = vdThreadFinishWrite(pDiskTo);
    6065                 AssertRC(rc2);
    6066                 fLockWriteTo = false;
    6067             }
    6068             else /* Don't propagate the error to the outside */
    6069                 rc = VINF_SUCCESS;
    6070 
    6071             uOffset += cbThisRead;
    6072             cbRemaining -= cbThisRead;
    6073 
    6074             if (pCbProgress && pCbProgress->pfnProgress)
    6075             {
    6076                 /** @todo r=klaus: this can update the progress to the same
    6077                  * percentage over and over again if the image format makes
    6078                  * relatively small increments. */
    6079                 rc = pCbProgress->pfnProgress(pIfProgress->pvUser,
    6080                                               uOffset * 99 / cbSize);
    6081                 if (RT_FAILURE(rc))
    6082                     break;
    6083             }
    6084             if (pDstCbProgress && pDstCbProgress->pfnProgress)
    6085             {
    6086                 /** @todo r=klaus: this can update the progress to the same
    6087                  * percentage over and over again if the image format makes
    6088                  * relatively small increments. */
    6089                 rc = pDstCbProgress->pfnProgress(pDstIfProgress->pvUser,
    6090                                                  uOffset * 99 / cbSize);
    6091                 if (RT_FAILURE(rc))
    6092                     break;
    6093             }
    6094         } while (uOffset < cbSize);
    6095 
    6096         if (RT_SUCCESS(rc))
    6097         {
    6098             rc2 = vdThreadStartWrite(pDiskTo);
    6099             AssertRC(rc2);
    6100             fLockWriteTo = true;
    6101 
    6102             /* Only set modification UUID if it is non-null, since the source
    6103              * backend might not provide a valid modification UUID. */
    6104             if (!RTUuidIsNull(&ImageModificationUuid))
    6105                 pImageTo->Backend->pfnSetModificationUuid(pImageTo->pBackendData, &ImageModificationUuid);
    6106 
    6107             /* Set the requested open flags if they differ from the value
    6108              * required for creating the image and copying the contents. */
    6109             if (   pImageTo && pszFilename
    6110                 && uOpenFlags != (uOpenFlags & ~VD_OPEN_FLAGS_READONLY))
    6111                 rc = pImageTo->Backend->pfnSetOpenFlags(pImageTo->pBackendData,
    6112                                                         uOpenFlags);
    6113         }
    6114     } while (0);
    6115 
    6116     if (RT_FAILURE(rc) && pImageTo && pszFilename)
    6117     {
    6118         /* Take the write lock only if it is not taken. Not worth making the
    6119          * above code even more complicated. */
    6120         if (RT_UNLIKELY(!fLockWriteTo))
    6121         {
    6122             rc2 = vdThreadStartWrite(pDiskTo);
    6123             AssertRC(rc2);
    6124             fLockWriteTo = true;
    6125         }
    6126         /* Error detected, but new image created. Remove image from list. */
    6127         vdRemoveImageFromList(pDiskTo, pImageTo);
    6128 
    6129         /* Close and delete image. */
    6130         rc2 = pImageTo->Backend->pfnClose(pImageTo->pBackendData, true);
    6131         AssertRC(rc2);
    6132         pImageTo->pBackendData = NULL;
    6133 
    6134         /* Free remaining resources. */
    6135         if (pImageTo->pszFilename)
    6136             RTStrFree(pImageTo->pszFilename);
    6137 
    6138         RTMemFree(pImageTo);
    6139     }
    6140 
    6141     if (RT_UNLIKELY(fLockWriteTo))
    6142     {
    6143         rc2 = vdThreadFinishWrite(pDiskTo);
    6144         AssertRC(rc2);
    6145     }
    6146     if (RT_UNLIKELY(fLockWriteFrom))
    6147     {
    6148         rc2 = vdThreadFinishWrite(pDiskFrom);
    6149         AssertRC(rc2);
    6150     }
    6151     else if (RT_UNLIKELY(fLockReadFrom))
    6152     {
    6153         rc2 = vdThreadFinishRead(pDiskFrom);
    6154         AssertRC(rc2);
    6155     }
    6156 
    6157     if (pvBuf)
    6158         RTMemTmpFree(pvBuf);
    6159 
    6160     if (RT_SUCCESS(rc))
    6161     {
    6162         if (pCbProgress && pCbProgress->pfnProgress)
    6163             pCbProgress->pfnProgress(pIfProgress->pvUser, 100);
    6164         if (pDstCbProgress && pDstCbProgress->pfnProgress)
    6165             pDstCbProgress->pfnProgress(pDstIfProgress->pvUser, 100);
    6166     }
    6167 
    6168     LogFlowFunc(("returns %Rrc\n", rc));
    6169     return rc;
     6338    return VDCopyEx(pDiskFrom, nImage, pDiskTo, pszBackend, pszFilename, fMoveByRename,
     6339                    cbSize, VD_IMAGE_CONTENT_UNKNOWN, VD_IMAGE_CONTENT_UNKNOWN,
     6340                    uImageFlags, pDstUuid, uOpenFlags, pVDIfsOperation,
     6341                    pDstVDIfsImage, pDstVDIfsOperation);
    61706342}
    61716343
     
    66866858        AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
    66876859
    6688         rc = vdReadHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbRead,
    6689                           true /* fZeroFreeBlocks */,
     6860        rc = vdReadHelper(pDisk, pImage, uOffset, pvBuf, cbRead,
    66906861                          true /* fUpdateCache */);
    66916862    } while (0);
     
    67486919
    67496920        vdSetModifiedFlag(pDisk);
    6750         rc = vdWriteHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite,
     6921        rc = vdWriteHelper(pDisk, pImage, uOffset, pvBuf, cbWrite,
    67516922                           true /* fUpdateCache */);
    67526923        if (RT_FAILURE(rc))
     
    67626933         * as this write is covered by the previous one. */
    67636934        if (RT_UNLIKELY(pDisk->pImageRelay))
    6764             rc = vdWriteHelper(pDisk, pDisk->pImageRelay, NULL, uOffset,
     6935            rc = vdWriteHelper(pDisk, pDisk->pImageRelay, uOffset,
    67656936                               pvBuf, cbWrite, false /* fUpdateCache */);
    67666937    } while (0);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette