VirtualBox

Changeset 15375 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Dec 12, 2008 3:07:32 PM (16 years ago)
Author:
vboxsync
Message:

Main: #3382: When discarding the first snapshot in the snapshot chain, the hard disk reference of the next snapshot was not properly updated in the machine XML file on disk.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/MachineImpl.cpp

    r15334 r15375  
    61126112
    61136113        /* quick path: recreate the whole tree of the snapshots */
    6114         if (op == SaveSS_UpdateAllOp && !aSnapshot)
     6114        if (op == SaveSS_UpdateAllOp && aSnapshot == NULL)
    61156115        {
    61166116            /* first, delete the entire root snapshot node if it exists */
     
    95969596
    95979597/**
     9598 * Helper struct for SessionMachine::discardSnapshotHandler().
     9599 */
     9600struct HardDiskDiscardRec
     9601{
     9602    HardDiskDiscardRec() : chain (NULL) {}
     9603
     9604    HardDiskDiscardRec (const ComObjPtr <HardDisk2> &aHd,
     9605                HardDisk2::MergeChain *aChain = NULL)
     9606        : hd (aHd), chain (aChain) {}
     9607
     9608    HardDiskDiscardRec (const ComObjPtr <HardDisk2> &aHd,
     9609                        HardDisk2::MergeChain *aChain,
     9610                        const ComObjPtr <HardDisk2> &aReplaceHd,
     9611                        const ComObjPtr <HardDisk2Attachment> &aReplaceHda,
     9612                        const Guid &aSnapshotId)
     9613        : hd (aHd), chain (aChain)
     9614        , replaceHd (aReplaceHd), replaceHda (aReplaceHda)
     9615        , snapshotId (aSnapshotId) {}
     9616
     9617    ComObjPtr <HardDisk2> hd;
     9618    HardDisk2::MergeChain *chain;
     9619    /* these are for the replace hard disk case: */
     9620    ComObjPtr <HardDisk2> replaceHd;
     9621    ComObjPtr <HardDisk2Attachment> replaceHda;
     9622    Guid snapshotId;
     9623};
     9624
     9625typedef std::list <HardDiskDiscardRec> HardDiskDiscardRecList;
     9626
     9627/**
    95989628 * Discard snapshot task handler. Must be called only by
    95999629 * DiscardSnapshotTask::handler()!
     
    96459675    Guid snapshotId = aTask.snapshot->data().mId;
    96469676
    9647     typedef std::list <std::pair <ComObjPtr <HardDisk2>,
    9648                        HardDisk2::MergeChain *> > ToDiscard;
    9649     ToDiscard toDiscard;
     9677    HardDiskDiscardRecList toDiscard;
    96509678
    96519679    bool settingsChanged = false;
     
    96889716            CheckComRCThrowRC (rc);
    96899717
    9690             toDiscard.push_back (std::make_pair (hd, chain));
     9718            if (hd->parent().isNull() && chain != NULL)
     9719            {
     9720                /* it's a base hard disk so it will be a backward merge of its
     9721                 * only child to it (prepareDiscard() does necessary checks). We
     9722                 * need then to update the attachment that refers to the child
     9723                 * to refer to the parent insead. Don't forget to detach the
     9724                 * child (otherwise mergeTo() called by discard() will assert
     9725                 * because it will be going to delete the child) */
     9726
     9727                /* The below assert would be nice but I don't want to move
     9728                 * HardDisk2::MergeChain to the header just for that
     9729                /* Assert (!chain->isForward()); */
     9730
     9731                Assert (hd->children().size() == 1);
     9732
     9733                ComObjPtr <HardDisk2> replaceHd = hd->children().front();
     9734
     9735                Assert (replaceHd->backRefs().front().machineId == mData->mUuid);
     9736                Assert (replaceHd->backRefs().front().snapshotIds.size() <= 1);
     9737
     9738                Guid snapshotId;
     9739                if (replaceHd->backRefs().front().snapshotIds.size() == 1)
     9740                    snapshotId = replaceHd->backRefs().front().snapshotIds.front();
     9741
     9742                HRESULT rc2 = S_OK;
     9743
     9744                /* adjust back references */
     9745                rc2 = replaceHd->detachFrom (mData->mUuid, snapshotId);
     9746                AssertComRC (rc2);
     9747
     9748                rc2 = hd->attachTo (mData->mUuid, snapshotId);
     9749                AssertComRC (rc2);
     9750
     9751                /* replace the hard disk in the attachment object */
     9752                HDData::AttachmentList::iterator it;
     9753                if (snapshotId.isEmpty())
     9754                {
     9755                    /* in current state */
     9756                    it = std::find_if (mHDData->mAttachments.begin(),
     9757                                       mHDData->mAttachments.end(),
     9758                                       HardDisk2Attachment::RefersTo (replaceHd));
     9759                    AssertBreak (it != mHDData->mAttachments.end());
     9760                }
     9761                else
     9762                {
     9763                    /* in snapshot */
     9764                    ComObjPtr <Snapshot> snapshot;
     9765                    rc2 = findSnapshot (snapshotId, snapshot);
     9766                    AssertComRC (rc2);
     9767
     9768                    /* don't lock the snapshot; cannot be modified outside */
     9769                    HDData::AttachmentList &snapAtts =
     9770                        snapshot->data().mMachine->mHDData->mAttachments;
     9771                    it = std::find_if (snapAtts.begin(),
     9772                                       snapAtts.end(),
     9773                                       HardDisk2Attachment::RefersTo (replaceHd));
     9774                    AssertBreak (it != snapAtts.end());
     9775                }
     9776
     9777                AutoWriteLock attLock (*it);
     9778                (*it)->updateHardDisk (hd, false /* aImplicit */);
     9779
     9780                toDiscard.push_back (HardDiskDiscardRec (hd, chain, replaceHd,
     9781                                                         *it, snapshotId));
     9782                continue;
     9783            }
     9784
     9785            toDiscard.push_back (HardDiskDiscardRec (hd, chain));
    96919786        }
    96929787
     
    97349829                if (aTask.snapshot->children().size() == 1)
    97359830                {
    9736                     ComObjPtr <Snapshot> childSnapshot = aTask.snapshot->children().front();
     9831                    ComObjPtr <Snapshot> childSnapshot =
     9832                        aTask.snapshot->children().front();
    97379833                    ComAssertThrow (
    97389834                        childSnapshot->data().mMachine->mData->mUuid == mData->mUuid,
     
    97919887        /// warnings properly on the GUI side)
    97929888
    9793         for (ToDiscard::iterator it = toDiscard.begin();
     9889        for (HardDiskDiscardRecList::iterator it = toDiscard.begin();
    97949890             it != toDiscard.end();)
    97959891        {
    9796             ComObjPtr <HardDisk2> replaceHd;
    9797             Guid snapshotId;
    9798 
    9799             if (it->first->parent().isNull() && it->second != NULL)
    9800             {
    9801                 /* it's a base hard disk so it will be a backward merge of its
    9802                  * only child to it. We need then to update the attachment that
    9803                  * refers to the child so get it and detach the child
    9804                  * (otherwise mergeTo() called by discard() will assert because
    9805                  * it will be going to delete the child) */
    9806 
    9807                 Assert (it->first->children().size() == 1);
    9808                 replaceHd = it->first->children().front();
    9809 
    9810                 Assert (replaceHd->backRefs().front().machineId == mData->mUuid);
    9811                 Assert (replaceHd->backRefs().front().snapshotIds.size() <= 1);
    9812                 if (replaceHd->backRefs().front().snapshotIds.size() == 1)
    9813                     snapshotId = replaceHd->backRefs().front().snapshotIds.front();
    9814 
    9815                 HRESULT rc2 = replaceHd->detachFrom (mData->mUuid, snapshotId);
    9816                 AssertComRC (rc2);
    9817             }
    9818 
    9819             rc = it->first->discard (aTask.progress, it->second);
    9820 
    9821             if (FAILED (rc))
    9822             {
    9823                 /* attach the detached child again */
    9824                 if (!replaceHd.isNull())
    9825                     replaceHd->attachTo (mData->mUuid, snapshotId);
    9826                 break;
    9827             }
    9828 
    9829             if (SUCCEEDED (rc) && !replaceHd.isNull())
    9830             {
    9831                 /* replace the attachment on success */
    9832                 alock.enter();
    9833 
    9834                 HDData::AttachmentList::iterator jt;
    9835                 if (snapshotId.isEmpty())
    9836                 {
    9837                     /* in current state */
    9838                         jt = std::find_if (mHDData->mAttachments.begin(),
    9839                                            mHDData->mAttachments.end(),
    9840                                            HardDisk2Attachment::RefersTo (replaceHd));
    9841                         AssertBreakStmt (jt != mHDData->mAttachments.end(),
    9842                                          rc = E_FAIL);
    9843                 }
    9844                 else
    9845                 {
    9846                     /* in snapshot */
    9847                     ComObjPtr <Snapshot> snapshot;
    9848                     findSnapshot (snapshotId, snapshot);
    9849                     AssertBreakStmt (!snapshot.isNull(), rc = E_FAIL);
    9850 
    9851                     /* don't lock the snapshot; cannot be modified outside */
    9852                     HDData::AttachmentList &snapAtts =
    9853                         snapshot->data().mMachine->mHDData->mAttachments;
    9854                     jt = std::find_if (snapAtts.begin(),
    9855                                        snapAtts.end(),
    9856                                        HardDisk2Attachment::RefersTo (replaceHd));
    9857                     AssertBreakStmt (jt != snapAtts.end(), rc = E_FAIL);
    9858                 }
    9859 
    9860                 {
    9861                     AutoWriteLock attLock (*jt);
    9862                     (*jt)->updateHardDisk (it->first, false /* aImplicit */);
    9863                 }
    9864 
    9865                 HRESULT rc2 = it->first->attachTo (mData->mUuid, snapshotId);
    9866                 AssertComRC (rc2);
    9867 
    9868                 alock.leave();
    9869             }
     9892            rc = it->hd->discard (aTask.progress, it->chain);
     9893            CheckComRCBreakRC (rc);
    98709894
    98719895            /* prevent from calling cancelDiscard() */
     
    98819905    if FAILED (rc)
    98829906    {
     9907        HRESULT rc2 = S_OK;
     9908
    98839909        /* un-prepare the remaining hard disks */
    9884         for (ToDiscard::const_iterator it = toDiscard.begin();
     9910        for (HardDiskDiscardRecList::const_iterator it = toDiscard.begin();
    98859911             it != toDiscard.end(); ++ it)
    9886             it->first->cancelDiscard (it->second);
     9912        {
     9913            it->hd->cancelDiscard (it->chain);
     9914
     9915            if (!it->replaceHd.isNull())
     9916            {
     9917                /* undo hard disk replacement */
     9918
     9919                rc2 = it->replaceHd->attachTo (mData->mUuid, it->snapshotId);
     9920                AssertComRC (rc2);
     9921
     9922                rc2 = it->hd->detachFrom (mData->mUuid, it->snapshotId);
     9923                AssertComRC (rc2);
     9924
     9925                AutoWriteLock attLock (it->replaceHda);
     9926                it->replaceHda->updateHardDisk (it->replaceHd, false /* aImplicit */);
     9927            }
     9928        }
    98879929    }
    98889930
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