VirtualBox

Changeset 54624 in vbox for trunk/src


Ignore:
Timestamp:
Mar 4, 2015 2:35:32 PM (10 years ago)
Author:
vboxsync
Message:

Storage/VD: Add API to prepare a chain of images for use with filters

File:
1 edited

Legend:

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

    r54591 r54624  
    86518651}
    86528652
     8653VBOXDDU_DECL(int) VDPrepareWithFilters(PVBOXHDD pDisk, PVDINTERFACE pVDIfsOperation)
     8654{
     8655    int rc = VINF_SUCCESS;
     8656    int rc2;
     8657    bool fLockRead = false, fLockWrite = false;
     8658
     8659    LogFlowFunc(("pDisk=%#p pVDIfsOperation=%#p\n", pDisk, pVDIfsOperation));
     8660
     8661    PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
     8662
     8663    do {
     8664        /* Check arguments. */
     8665        AssertMsgBreakStmt(VALID_PTR(pDisk), ("pDisk=%#p\n", pDisk),
     8666                           rc = VERR_INVALID_PARAMETER);
     8667        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE,
     8668                  ("u32Signature=%08x\n", pDisk->u32Signature));
     8669
     8670        rc2 = vdThreadStartRead(pDisk);
     8671        AssertRC(rc2);
     8672        fLockRead = true;
     8673
     8674        /* Must have at least one image in the chain. */
     8675        AssertMsgBreakStmt(pDisk->cImages >= 1, ("cImages=%u\n", pDisk->cImages),
     8676                           rc = VERR_VD_NOT_OPENED);
     8677
     8678        unsigned uOpenFlags = pDisk->pLast->Backend->pfnGetOpenFlags(pDisk->pLast->pBackendData);
     8679        AssertMsgBreakStmt(!(uOpenFlags & VD_OPEN_FLAGS_READONLY),
     8680                           ("Last image should be read write"),
     8681                           rc = VERR_VD_IMAGE_READ_ONLY);
     8682
     8683        rc2 = vdThreadFinishRead(pDisk);
     8684        AssertRC(rc2);
     8685        fLockRead = false;
     8686
     8687        rc2 = vdThreadStartWrite(pDisk);
     8688        AssertRC(rc2);
     8689        fLockWrite = true;
     8690
     8691        /*
     8692         * Open all images in the chain in read write mode first to avoid running
     8693         * into an error in the middle of the process.
     8694         */
     8695        PVDIMAGE pImage = pDisk->pBase;
     8696
     8697        while (pImage)
     8698        {
     8699            uOpenFlags = pImage->Backend->pfnGetOpenFlags(pImage->pBackendData);
     8700            if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
     8701            {
     8702                /*
     8703                 * Clear skip consistency checks because the image is made writable now and
     8704                 * skipping consistency checks is only possible for readonly images.
     8705                 */
     8706                uOpenFlags &= ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS);
     8707                rc = pImage->Backend->pfnSetOpenFlags(pImage->pBackendData, uOpenFlags);
     8708                if (RT_FAILURE(rc))
     8709                    break;
     8710            }
     8711            pImage = pImage->pNext;
     8712        }
     8713
     8714        if (RT_SUCCESS(rc))
     8715        {
     8716            unsigned cImgCur = 0;
     8717            unsigned uPercentStart = 0;
     8718            unsigned uPercentSpan = 100 / pDisk->cImages - 1;
     8719
     8720            /* Allocate tmp buffer. */
     8721            void *pvBuf = RTMemTmpAlloc(VD_MERGE_BUFFER_SIZE);
     8722            if (!pvBuf)
     8723            {
     8724                rc = VERR_NO_MEMORY;
     8725                break;
     8726            }
     8727
     8728            pImage = pDisk->pBase;
     8729            pDisk->fLocked = true;
     8730
     8731            while (   pImage
     8732                   && RT_SUCCESS(rc))
     8733            {
     8734                /* Get size of image. */
     8735                uint64_t cbSize = pImage->Backend->pfnGetSize(pImage->pBackendData);
     8736                uint64_t uOffset = 0;
     8737                uint64_t cbRemaining = cbSize;
     8738
     8739                do
     8740                {
     8741                    size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining);
     8742                    RTSGSEG SegmentBuf;
     8743                    RTSGBUF SgBuf;
     8744                    VDIOCTX IoCtx;
     8745
     8746                    SegmentBuf.pvSeg = pvBuf;
     8747                    SegmentBuf.cbSeg = VD_MERGE_BUFFER_SIZE;
     8748                    RTSgBufInit(&SgBuf, &SegmentBuf, 1);
     8749                    vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_READ, 0, 0, NULL,
     8750                                &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC);
     8751
     8752                    rc = pImage->Backend->pfnRead(pImage->pBackendData, uOffset,
     8753                                                  cbThisRead, &IoCtx, &cbThisRead);
     8754                    if (rc != VERR_VD_BLOCK_FREE)
     8755                    {
     8756                        if (RT_FAILURE(rc))
     8757                            break;
     8758
     8759                        /* Apply filter chains. */
     8760                        rc = vdFilterChainApplyRead(pDisk, uOffset, cbThisRead, &IoCtx);
     8761                        if (RT_FAILURE(rc))
     8762                            break;
     8763
     8764                        rc = vdFilterChainApplyWrite(pDisk, uOffset, cbThisRead, &IoCtx);
     8765                        if (RT_FAILURE(rc))
     8766                            break;
     8767
     8768                        RTSgBufReset(&SgBuf);
     8769                        size_t cbThisWrite = 0;
     8770                        size_t cbPreRead = 0;
     8771                        size_t cbPostRead = 0;
     8772                        rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffset,
     8773                                                       cbThisRead, &IoCtx, &cbThisWrite,
     8774                                                       &cbPreRead, &cbPostRead, VD_WRITE_NO_ALLOC);
     8775                        if (RT_FAILURE(rc))
     8776                            break;
     8777                        Assert(cbThisWrite == cbThisRead);
     8778                    }
     8779                    else
     8780                        rc = VINF_SUCCESS;
     8781
     8782                    uOffset += cbThisRead;
     8783                    cbRemaining -= cbThisRead;
     8784
     8785                    if (pIfProgress && pIfProgress->pfnProgress)
     8786                    {
     8787                        rc2 = pIfProgress->pfnProgress(pIfProgress->Core.pvUser,
     8788                                                       uPercentStart + uOffset * uPercentSpan / cbSize);
     8789                        AssertRC(rc2); /* Cancelling this operation without leaving an inconsistent state is not possible. */
     8790                    }
     8791                } while (uOffset < cbSize);
     8792
     8793                pImage = pImage->pNext;
     8794                cImgCur++;
     8795                uPercentStart += uPercentSpan;
     8796            }
     8797
     8798            pDisk->fLocked = false;
     8799            if (pvBuf)
     8800                RTMemTmpFree(pvBuf);
     8801        }
     8802
     8803        /* Change images except last one back to readonly. */
     8804        pImage = pDisk->pBase;
     8805        while (   pImage != pDisk->pLast
     8806               && pImage)
     8807        {
     8808            uOpenFlags = pImage->Backend->pfnGetOpenFlags(pImage->pBackendData);
     8809            uOpenFlags |= VD_OPEN_FLAGS_READONLY;
     8810            rc2 = pImage->Backend->pfnSetOpenFlags(pImage->pBackendData, uOpenFlags);
     8811            if (RT_FAILURE(rc2))
     8812            {
     8813                if (RT_SUCCESS(rc))
     8814                    rc = rc2;
     8815                break;
     8816            }
     8817            pImage = pImage->pNext;
     8818        }
     8819    } while (0);
     8820
     8821    if (RT_UNLIKELY(fLockWrite))
     8822    {
     8823        rc2 = vdThreadFinishWrite(pDisk);
     8824        AssertRC(rc2);
     8825    }
     8826    else if (RT_UNLIKELY(fLockRead))
     8827    {
     8828        rc2 = vdThreadFinishRead(pDisk);
     8829        AssertRC(rc2);
     8830    }
     8831
     8832    if (   RT_SUCCESS(rc)
     8833        && pIfProgress
     8834        && pIfProgress->pfnProgress)
     8835        pIfProgress->pfnProgress(pIfProgress->Core.pvUser, 100);
     8836
     8837    LogFlowFunc(("returns %Rrc\n", rc));
     8838    return rc;
     8839}
     8840
    86538841/**
    86548842 * Closes the last opened image file in HDD container.
     
    88469034        if (fFlags & VD_FILTER_FLAGS_READ)
    88479035        {
    8848             AssertPtrBreakStmt(!RTListIsEmpty(&pDisk->ListFilterChainRead), rc = VERR_VD_NOT_OPENED);
     9036            AssertBreakStmt(!RTListIsEmpty(&pDisk->ListFilterChainRead), rc = VERR_VD_NOT_OPENED);
    88499037            pFilter = RTListGetLast(&pDisk->ListFilterChainRead, VDFILTER, ListNodeChainRead);
    88509038            AssertPtr(pFilter);
Note: See TracChangeset for help on using the changeset viewer.

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