VirtualBox

Changeset 33259 in vbox


Ignore:
Timestamp:
Oct 20, 2010 12:49:55 PM (14 years ago)
Author:
vboxsync
Message:

Storage/VBoxHDD+Main/Snapshot: Implement backward merging of snapshots, needed for live deletion of last remaining snapshot. Required a few minor changes to existing code in paths which so far were untested, to get the details right.

Location:
trunk/src/VBox
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r33094 r33259  
    166166     * The same as pBase if only one image is used. */
    167167    PVDIMAGE            pLast;
     168
     169    /** If a merge to one of the parents is running this may be non-NULL
     170     * to indicate to what image the writes should be additionally relayed. */
     171    PVDIMAGE            pImageRelay;
    168172
    169173    /** Flags representing the modification state. */
     
    15651569 * write optimizations.
    15661570 */
    1567 static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
    1568                          uint64_t uOffset, const void *pvBuf, size_t cbWrite,
     1571static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage,
     1572                         PVDIMAGE pImageParentOverride, uint64_t uOffset,
     1573                         const void *pvBuf, size_t cbWrite,
    15691574                         bool fUpdateCache)
    15701575{
     
    52905295        {
    52915296            /*
    5292              * We may need to update the parent uuid of the child coming after the
    5293              * last image to be merged. We have to reopen it read/write.
     5297             * We may need to update the parent uuid of the child coming after
     5298             * the last image to be merged. We have to reopen it read/write.
    52945299             *
    5295              * This is done before we do the actual merge to prevent an incosistent
    5296              * chain if the mode change fails for some reason.
     5300             * This is done before we do the actual merge to prevent an
     5301             * inconsistent chain if the mode change fails for some reason.
    52975302             */
    52985303            if (pImageFrom->pNext)
     
    53165321                        break;
    53175322                }
     5323
     5324                rc2 = vdThreadFinishWrite(pDisk);
     5325                AssertRC(rc2);
     5326                fLockWrite = false;
     5327            }
     5328
     5329            /* If the merge is from the last image we have to relay all writes
     5330             * to the merge destination as well, so that concurrent writes
     5331             * (in case of a live merge) are handled correctly. */
     5332            if (!pImageFrom->pNext)
     5333            {
     5334                /* Take the write lock. */
     5335                rc2 = vdThreadStartWrite(pDisk);
     5336                AssertRC(rc2);
     5337                fLockWrite = true;
     5338
     5339                pDisk->pImageRelay = pImageTo;
    53185340
    53195341                rc2 = vdThreadFinishWrite(pDisk);
     
    53805402                }
    53815403            } while (uOffset < cbSize);
     5404
     5405            /* In case we set up a "write proxy" image above we must clear
     5406             * this again now to prevent stray writes. Failure or not. */
     5407            if (!pImageFrom->pNext)
     5408            {
     5409                /* Take the write lock. */
     5410                rc2 = vdThreadStartWrite(pDisk);
     5411                AssertRC(rc2);
     5412                fLockWrite = true;
     5413
     5414                pDisk->pImageRelay = NULL;
     5415
     5416                rc2 = vdThreadFinishWrite(pDisk);
     5417                AssertRC(rc2);
     5418                fLockWrite = false;
     5419            }
    53825420        }
    53835421
     
    64756513        rc = vdWriteHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite,
    64766514                           true /* fUpdateCache */);
     6515        if (RT_FAILURE(rc))
     6516            break;
     6517
     6518        /* If there is a merge (in the direction towards a parent) running
     6519         * concurrently then we have to also "relay" the write to this parent,
     6520         * as the merge position might be already past the position where
     6521         * this write is going. The "context" of the write can come from the
     6522         * natural chain, since merging either already did or will take care
     6523         * of the "other" content which is might be needed to fill the block
     6524         * to a full allocation size. The cache doesn't need to be touched
     6525         * as this write is covered by the previous one. */
     6526        if (RT_UNLIKELY(pDisk->pImageRelay))
     6527            rc = vdWriteHelper(pDisk, pDisk->pImageRelay, NULL, uOffset,
     6528                               pvBuf, cbWrite, false /* fUpdateCache */);
    64776529    } while (0);
    64786530
  • trunk/src/VBox/Main/SnapshotImpl.cpp

    r33078 r33259  
    25792579                if (it->mfNeedsOnlineMerge)
    25802580                {
    2581 /// @todo VBoxHDD cannot handle backward merges where source==active disk yet
    2582                     if (!it->mfMergeForward && it->mChildrenToReparent.size() == 0)
    2583                         throw setError(E_NOTIMPL,
    2584                                        tr("Snapshot '%s' of the machine '%ls' cannot be deleted while a VM is running, as this case is not implemented yet. You can delete the snapshot when the VM is powered off"),
    2585                                        aTask.pSnapshot->getName().c_str(),
    2586                                        mUserData->s.strName.c_str());
    2587 
    25882581                    // online medium merge, in the direction decided earlier
    25892582                    rc = onlineMergeMedium(it->mpOnlineMediumAttachment,
     
    26822675                    childSnapshotId = pChildSnapshot->getId();
    26832676                }
    2684                 pAtt = findAttachment(pMachine->mMediaData->mAttachments, it->mpSource);
    2685                 // If no attachment is found do not change anything. The source
    2686                 // medium might not have been attached to the snapshot.
    2687                 if (pAtt)
     2677                // If this is an online deletion the attachment was updated
     2678                // already as it is required to continue execution immediately.
     2679                // Needs a bit of special treatment due to this difference.
     2680                if (it->mfNeedsOnlineMerge)
    26882681                {
    2689                     AutoWriteLock attLock(pAtt COMMA_LOCKVAL_SRC_POS);
    2690                     pAtt->updateMedium(it->mpTarget);
    26912682                    it->mpTarget->addBackReference(pMachine->mData->mUuid, childSnapshotId);
     2683                }
     2684                else
     2685                {
     2686                    pAtt = findAttachment(pMachine->mMediaData->mAttachments, it->mpSource);
     2687                    // If no attachment is found do not change anything. Maybe
     2688                    // the source medium was not attached to the snapshot.
     2689                    if (pAtt)
     2690                    {
     2691                        AutoWriteLock attLock(pAtt COMMA_LOCKVAL_SRC_POS);
     2692                        pAtt->updateMedium(it->mpTarget);
     2693                        it->mpTarget->addBackReference(pMachine->mData->mUuid, childSnapshotId);
     2694                    }
    26922695                }
    26932696            }
     
    32603263    AutoWriteLock treeLock(mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    32613264
     3265    // Declare this here to make sure the object does not get uninitialized
     3266    // before this method completes. Would normally happen as halfway through
     3267    // we delete the last reference to the no longer existing medium object.
     3268    ComObjPtr<Medium> targetChild;
     3269
    32623270    if (aMergeForward)
    32633271    {
     
    32813289    {
    32823290        Assert(pTarget->getChildren().size() == 1);
    3283         Medium *targetChild = pTarget->getChildren().front();
     3291        targetChild = pTarget->getChildren().front();
    32843292
    32853293        // disconnect the deleted branch at the elder end
     
    33203328    /* unregister and uninitialize all hard disks removed by the merge */
    33213329    MediumLockList *pMediumLockList = NULL;
    3322     rc = mData->mSession.mLockedMedia.Get(static_cast<MediumAttachment *>(aMediumAttachment),
    3323                                           pMediumLockList);
     3330    MediumAttachment *pMediumAttachment = static_cast<MediumAttachment *>(aMediumAttachment);
     3331    rc = mData->mSession.mLockedMedia.Get(pMediumAttachment, pMediumLockList);
    33243332    const ComObjPtr<Medium> &pLast = aMergeForward ? pTarget : pSource;
    33253333    AssertReturn(SUCCEEDED(rc) && pMediumLockList, E_FAIL);
     
    33963404    }
    33973405
     3406    /* If this is a backwards merge update the medium associated with the
     3407     * attachment, as the previously associated one is now deleted. */
     3408    if (!aMergeForward)
     3409    {
     3410        AutoWriteLock attLock(pMediumAttachment COMMA_LOCKVAL_SRC_POS);
     3411        pMediumAttachment->updateMedium(pTarget);
     3412    }
    33983413
    33993414    return S_OK;
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