VirtualBox

Changeset 48297 in vbox for trunk/src/VBox/Main/src-server


Ignore:
Timestamp:
Sep 5, 2013 9:57:44 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
88714
Message:

Main/Medium: redesign API level medium locking, needed conversions from MediaList to MediumLockLists in several places, forced cleanups elsewhere, too
Main/Token: introduced token objects for controlling the unlocking, will be used as a general concept in the future
Main/Snapshot: snapshot deletion needed significant cleanups as it was still using many shortcuts, directly calling the API to lock media instead of using lock lists. Now much better, and the online snapshot deletion is also a lot cleaner as it no longer passes unnecessary parameters around which are already known in the machine/snapshot code
Main/MediumLock: small improvements, now has a mode which skips locking already locked media, needed by the Snapshot code where we have overlapping lock lists and have to update the original one instead
Main/Console+Session+Machine: follow-up changes for the online snapshot merging parameter passing simplification, plus an unrelated lock order violation fix in Machine which happens only for inaccessible machines
Main/testcase: update correspondingly
doc: update SDK reference

Location:
trunk/src/VBox/Main/src-server
Files:
1 added
5 edited

Legend:

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

    r48295 r48297  
    903903    LogFlowThisFunc(("ENTER\n"));
    904904
     905    /* In some cases (medium registry related), it is necessary to be able to
     906     * go through the list of all machines. Happens when an inaccessible VM
     907     * has a sensible medium registry. */
     908    AutoReadLock mllock(mParent->getMachinesListLockHandle() COMMA_LOCKVAL_SRC_POS);
    905909    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    906910
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r47920 r48297  
    1717
    1818#include "MediumImpl.h"
     19#include "TokenImpl.h"
    1920#include "ProgressImpl.h"
    2021#include "SystemPropertiesImpl.h"
     
    515516              bool fMergeForward,
    516517              Medium *aParentForTarget,
    517               const MediaList &aChildrenToReparent,
     518              MediumLockList *aChildrenToReparent,
    518519              Progress *aProgress,
    519520              MediumLockList *aMediumLockList,
     
    523524          mfMergeForward(fMergeForward),
    524525          mParentForTarget(aParentForTarget),
    525           mChildrenToReparent(aChildrenToReparent),
     526          mpChildrenToReparent(aChildrenToReparent),
    526527          mpMediumLockList(aMediumLockList),
    527528          mTargetCaller(aTarget),
    528529          mParentForTargetCaller(aParentForTarget),
    529           mfChildrenCaller(false),
    530530          mfKeepMediumLockList(fKeepMediumLockList)
    531531    {
    532532        AssertReturnVoidStmt(aMediumLockList != NULL, mRC = E_FAIL);
    533         for (MediaList::const_iterator it = mChildrenToReparent.begin();
    534              it != mChildrenToReparent.end();
    535              ++it)
    536         {
    537             HRESULT rc2 = (*it)->addCaller();
    538             if (FAILED(rc2))
    539             {
    540                 mRC = E_FAIL;
    541                 for (MediaList::const_iterator it2 = mChildrenToReparent.begin();
    542                      it2 != it;
    543                      --it2)
    544                 {
    545                     (*it2)->releaseCaller();
    546                 }
    547                 return;
    548             }
    549         }
    550         mfChildrenCaller = true;
    551533    }
    552534
     
    555537        if (!mfKeepMediumLockList && mpMediumLockList)
    556538            delete mpMediumLockList;
    557         if (mfChildrenCaller)
    558         {
    559             for (MediaList::const_iterator it = mChildrenToReparent.begin();
    560                  it != mChildrenToReparent.end();
    561                  ++it)
    562             {
    563                 (*it)->releaseCaller();
    564             }
    565         }
     539        if (mpChildrenToReparent)
     540            delete mpChildrenToReparent;
    566541    }
    567542
    568543    const ComObjPtr<Medium> mTarget;
    569544    bool mfMergeForward;
    570     /* When mChildrenToReparent is empty then mParentForTarget is non-null.
    571      * In other words: they are used in different cases. */
     545    /* When mpChildrenToReparent is null then mParentForTarget is non-null and
     546     * vice versa. In other words: they are used in different cases. */
    572547    const ComObjPtr<Medium> mParentForTarget;
    573     MediaList mChildrenToReparent;
     548    MediumLockList *mpChildrenToReparent;
    574549    MediumLockList *mpMediumLockList;
    575550
     
    579554    AutoCaller mTargetCaller;
    580555    AutoCaller mParentForTargetCaller;
    581     bool mfChildrenCaller;
    582556    bool mfKeepMediumLockList;
    583557};
     
    21232097}
    21242098
    2125 /**
    2126  * @note @a aState may be NULL if the state value is not needed (only for
    2127  *       in-process calls).
    2128  */
    2129 STDMETHODIMP Medium::LockRead(MediumState_T *aState)
    2130 {
     2099STDMETHODIMP Medium::LockRead(IToken **aToken)
     2100{
     2101    CheckComArgNotNull(aToken);
     2102
    21312103    AutoCaller autoCaller(this);
    21322104    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     
    21522124    }
    21532125
    2154     /* return the current state before */
    2155     if (aState)
    2156         *aState = m->state;
    2157 
    21582126    HRESULT rc = S_OK;
    21592127
     
    21752143            m->state = MediumState_LockedRead;
    21762144
     2145            ComObjPtr<MediumLockToken> pToken;
     2146            rc = pToken.createObject();
     2147            if (SUCCEEDED(rc))
     2148                rc = pToken->init(this, false /* fWrite */);
     2149            if (FAILED(rc))
     2150            {
     2151                --m->readers;
     2152                if (m->readers == 0)
     2153                    m->state = m->preLockState;
     2154                return rc;
     2155            }
     2156
     2157            pToken.queryInterfaceTo(aToken);
    21772158            break;
    21782159        }
     
    21922173 *       in-process calls).
    21932174 */
    2194 STDMETHODIMP Medium::UnlockRead(MediumState_T *aState)
     2175HRESULT Medium::unlockRead(MediumState_T *aState)
    21952176{
    21962177    AutoCaller autoCaller(this);
     
    22392220}
    22402221
    2241 /**
    2242  * @note @a aState may be NULL if the state value is not needed (only for
    2243  *       in-process calls).
    2244  */
    2245 STDMETHODIMP Medium::LockWrite(MediumState_T *aState)
    2246 {
     2222STDMETHODIMP Medium::LockWrite(IToken **aToken)
     2223{
     2224    CheckComArgNotNull(aToken);
     2225
    22472226    AutoCaller autoCaller(this);
    22482227    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     
    22682247    }
    22692248
    2270     /* return the current state before */
    2271     if (aState)
    2272         *aState = m->state;
    2273 
    22742249    HRESULT rc = S_OK;
    22752250
     
    22832258            LogFlowThisFunc(("Okay - prev state=%d locationFull=%s\n", m->state, getLocationFull().c_str()));
    22842259            m->state = MediumState_LockedWrite;
     2260
     2261            ComObjPtr<MediumLockToken> pToken;
     2262            rc = pToken.createObject();
     2263            if (SUCCEEDED(rc))
     2264                rc = pToken->init(this, true /* fWrite */);
     2265            if (FAILED(rc))
     2266            {
     2267                m->state = m->preLockState;
     2268                return rc;
     2269            }
     2270
     2271            pToken.queryInterfaceTo(aToken);
    22852272            break;
    22862273        }
     
    23002287 *       in-process calls).
    23012288 */
    2302 STDMETHODIMP Medium::UnlockWrite(MediumState_T *aState)
     2289HRESULT Medium::unlockWrite(MediumState_T *aState)
    23032290{
    23042291    AutoCaller autoCaller(this);
     
    25382525
    25392526    HRESULT rc = S_OK;
    2540     ComObjPtr <Progress> pProgress;
     2527    ComObjPtr<Progress> pProgress;
    25412528    Medium::Task *pTask = NULL;
    25422529
     
    26942681    alock.release();
    26952682
    2696     ComObjPtr <Progress> pProgress;
     2683    ComObjPtr<Progress> pProgress;
    26972684
    26982685    ULONG mediumVariantFlags = 0;
     
    27282715    bool fMergeForward = false;
    27292716    ComObjPtr<Medium> pParentForTarget;
    2730     MediaList childrenToReparent;
     2717    MediumLockList *pChildrenToReparent = NULL;
    27312718    MediumLockList *pMediumLockList = NULL;
    27322719
     
    27342721
    27352722    rc = prepareMergeTo(pTarget, NULL, NULL, true, fMergeForward,
    2736                         pParentForTarget, childrenToReparent, pMediumLockList);
     2723                        pParentForTarget, pChildrenToReparent, pMediumLockList);
    27372724    if (FAILED(rc)) return rc;
    27382725
    2739     ComObjPtr <Progress> pProgress;
    2740 
    2741     rc = mergeTo(pTarget, fMergeForward, pParentForTarget, childrenToReparent,
     2726    ComObjPtr<Progress> pProgress;
     2727
     2728    rc = mergeTo(pTarget, fMergeForward, pParentForTarget, pChildrenToReparent,
    27422729                 pMediumLockList, &pProgress, false /* aWait */);
    27432730    if (FAILED(rc))
    2744         cancelMergeTo(childrenToReparent, pMediumLockList);
     2731        cancelMergeTo(pChildrenToReparent, pMediumLockList);
    27452732    else
    27462733        pProgress.queryInterfaceTo(aProgress);
     
    29152902
    29162903    HRESULT rc = S_OK;
    2917     ComObjPtr <Progress> pProgress;
     2904    ComObjPtr<Progress> pProgress;
    29182905    Medium::Task *pTask = NULL;
    29192906
     
    29882975
    29892976    HRESULT rc = S_OK;
    2990     ComObjPtr <Progress> pProgress;
     2977    ComObjPtr<Progress> pProgress;
    29912978    Medium::Task *pTask = NULL;
    29922979
     
    30613048
    30623049    HRESULT rc = S_OK;
    3063     ComObjPtr <Progress> pProgress;
     3050    ComObjPtr<Progress> pProgress;
    30643051    Medium::Task *pTask = NULL;
    30653052
     
    46654652 * @param fMergeForward Resulting merge direction (out).
    46664653 * @param pParentForTarget New parent for target medium after merge (out).
    4667  * @param aChildrenToReparent List of children of the source which will have
    4668  *                      to be reparented to the target after merge (out).
     4654 * @param aChildrenToReparent Medium lock list containing all children of the
     4655 *                      source which will have to be reparented to the target
     4656 *                      after merge (out).
    46694657 * @param aMediumLockList Medium locking information (out).
    46704658 *
     
    46784666                               bool &fMergeForward,
    46794667                               ComObjPtr<Medium> &pParentForTarget,
    4680                                MediaList &aChildrenToReparent,
     4668                               MediumLockList * &aChildrenToReparent,
    46814669                               MediumLockList * &aMediumLockList)
    46824670{
     
    46934681    fMergeForward = false;
    46944682    pParentForTarget.setNull();
    4695     aChildrenToReparent.clear();
     4683    Assert(aChildrenToReparent == NULL);
     4684    aChildrenToReparent = NULL;
    46964685    Assert(aMediumLockList == NULL);
    46974686    aMediumLockList = NULL;
     
    48764865        {
    48774866            /* we will need to reparent children of the source */
     4867            aChildrenToReparent = new MediumLockList();
    48784868            for (MediaList::const_iterator it = getChildren().begin();
    48794869                 it != getChildren().end();
     
    48814871            {
    48824872                pMedium = *it;
    4883                 if (fLockMedia)
    4884                 {
    4885                     rc = pMedium->LockWrite(NULL);
    4886                     if (FAILED(rc))
    4887                         throw rc;
    4888                 }
    4889 
    4890                 aChildrenToReparent.push_back(pMedium);
     4873                aChildrenToReparent->Append(pMedium, true /* fLockWrite */);
     4874            }
     4875            if (fLockMedia && aChildrenToReparent)
     4876            {
     4877                treeLock.release();
     4878                rc = aChildrenToReparent->Lock();
     4879                treeLock.acquire();
     4880                if (FAILED(rc))
     4881                    throw rc;
    48914882            }
    48924883        }
     
    49474938    if (FAILED(rc))
    49484939    {
    4949         delete aMediumLockList;
    4950         aMediumLockList = NULL;
     4940        if (aMediumLockList)
     4941        {
     4942            delete aMediumLockList;
     4943            aMediumLockList = NULL;
     4944        }
     4945        if (aChildrenToReparent)
     4946        {
     4947            delete aChildrenToReparent;
     4948            aChildrenToReparent = NULL;
     4949        }
    49514950    }
    49524951
     
    50335032                        bool fMergeForward,
    50345033                        const ComObjPtr<Medium> &pParentForTarget,
    5035                         const MediaList &aChildrenToReparent,
     5034                        MediumLockList *aChildrenToReparent,
    50365035                        MediumLockList *aMediumLockList,
    5037                         ComObjPtr <Progress> *aProgress,
     5036                        ComObjPtr<Progress> *aProgress,
    50385037                        bool aWait)
    50395038{
     
    50505049
    50515050    HRESULT rc = S_OK;
    5052     ComObjPtr <Progress> pProgress;
     5051    ComObjPtr<Progress> pProgress;
    50535052    Medium::Task *pTask = NULL;
    50545053
     
    51225121 * @note Locks the media from the chain for writing.
    51235122 */
    5124 void Medium::cancelMergeTo(const MediaList &aChildrenToReparent,
     5123void Medium::cancelMergeTo(MediumLockList *aChildrenToReparent,
    51255124                           MediumLockList *aMediumLockList)
    51265125{
     
    51545153    delete aMediumLockList;
    51555154
    5156     /* unlock the children which had to be reparented */
    5157     for (MediaList::const_iterator it = aChildrenToReparent.begin();
    5158          it != aChildrenToReparent.end();
    5159          ++it)
    5160     {
    5161         const ComObjPtr<Medium> &pMedium = *it;
    5162 
    5163         AutoWriteLock alock(pMedium COMMA_LOCKVAL_SRC_POS);
    5164         pMedium->UnlockWrite(NULL);
    5165     }
     5155    /* unlock the children which had to be reparented, the destructor will do
     5156     * the work */
     5157    if (aChildrenToReparent)
     5158        delete aChildrenToReparent;
    51665159}
    51675160
     
    51705163 * parent.
    51715164 */
    5172 HRESULT Medium::fixParentUuidOfChildren(const MediaList &childrenToReparent)
     5165HRESULT Medium::fixParentUuidOfChildren(MediumLockList *pChildrenToReparent)
    51735166{
    51745167    Assert(!isWriteLockOnCurrentThread());
     
    52115204            }
    52125205
    5213             for (MediaList::const_iterator it = childrenToReparent.begin();
    5214                  it != childrenToReparent.end();
     5206            MediumLockList::Base::iterator childrenBegin = pChildrenToReparent->GetBegin();
     5207            MediumLockList::Base::iterator childrenEnd = pChildrenToReparent->GetEnd();
     5208            for (MediumLockList::Base::iterator it = childrenBegin;
     5209                 it != childrenEnd;
    52155210                 ++it)
    52165211            {
     5212                Medium *pMedium = it->GetMedium();
    52175213                /* VD_OPEN_FLAGS_INFO since UUID is wrong yet */
    52185214                vrc = VDOpen(hdd,
    5219                              (*it)->m->strFormat.c_str(),
    5220                              (*it)->m->strLocationFull.c_str(),
     5215                             pMedium->m->strFormat.c_str(),
     5216                             pMedium->m->strLocationFull.c_str(),
    52215217                             VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef,
    5222                              (*it)->m->vdImageIfaces);
     5218                             pMedium->m->vdImageIfaces);
    52235219                if (RT_FAILURE(vrc))
    52245220                    throw vrc;
     
    52315227                if (RT_FAILURE(vrc))
    52325228                    throw vrc;
    5233 
    5234                 (*it)->UnlockWrite(NULL);
    52355229            }
    52365230        }
     
    56485642    /* Lock the medium, which makes the behavior much more consistent */
    56495643    alock.release();
     5644    ComPtr<IToken> pToken;
    56505645    if (uOpenFlags & (VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SHAREABLE))
    5651         rc = LockRead(NULL);
     5646        rc = LockRead(pToken.asOutParam());
    56525647    else
    5653         rc = LockWrite(NULL);
     5648        rc = LockWrite(pToken.asOutParam());
    56545649    if (FAILED(rc)) return rc;
    56555650    alock.acquire();
     
    59895984        m->preLockState = MediumState_Inaccessible;
    59905985
    5991     HRESULT rc2;
    5992     if (uOpenFlags & (VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SHAREABLE))
    5993         rc2 = UnlockRead(NULL);
    5994     else
    5995         rc2 = UnlockWrite(NULL);
    5996     if (SUCCEEDED(rc) && FAILED(rc2))
    5997         rc = rc2;
     5986    pToken->Abandon();
     5987    pToken.setNull();
     5988   
    59985989    if (FAILED(rc)) return rc;
    59995990
     
    60065997    if (fRepairImageZeroParentUuid)
    60075998    {
    6008         rc = LockWrite(NULL);
     5999        rc = LockWrite(pToken.asOutParam());
    60096000        if (FAILED(rc)) return rc;
    60106001
     
    60446035        }
    60456036
    6046         rc = UnlockWrite(NULL);
    6047         if (SUCCEEDED(rc) && FAILED(rc2))
    6048             rc = rc2;
     6037        pToken->Abandon();
     6038        pToken.setNull();
    60496039        if (FAILED(rc)) return rc;
    60506040    }
     
    72147204                 * which cannot be part of the container at once so
    72157205                 * add each one in there individually */
    7216                 if (task.mChildrenToReparent.size() > 0)
     7206                if (task.mpChildrenToReparent)
    72177207                {
    7218                     for (MediaList::const_iterator it = task.mChildrenToReparent.begin();
    7219                          it != task.mChildrenToReparent.end();
     7208                    MediumLockList::Base::iterator childrenBegin = task.mpChildrenToReparent->GetBegin();
     7209                    MediumLockList::Base::iterator childrenEnd = task.mpChildrenToReparent->GetEnd();
     7210                    for (MediumLockList::Base::iterator it = childrenBegin;
     7211                         it != childrenEnd;
    72207212                         ++it)
    72217213                    {
     7214                        Medium *pMedium = it->GetMedium();
    72227215                        /* VD_OPEN_FLAGS_INFO since UUID is wrong yet */
    72237216                        vrc = VDOpen(hdd,
    7224                                      (*it)->m->strFormat.c_str(),
    7225                                      (*it)->m->strLocationFull.c_str(),
     7217                                     pMedium->m->strFormat.c_str(),
     7218                                     pMedium->m->strLocationFull.c_str(),
    72267219                                     VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef,
    7227                                      (*it)->m->vdImageIfaces);
     7220                                     pMedium->m->vdImageIfaces);
    72287221                        if (RT_FAILURE(vrc))
    72297222                            throw vrc;
     
    72377230                        if (RT_FAILURE(vrc))
    72387231                            throw vrc;
    7239 
    7240                         (*it)->UnlockWrite(NULL);
    72417232                    }
    72427233                }
     
    73017292            /* reparent source's children and disconnect the deleted
    73027293             * branch at the younger end */
    7303             if (task.mChildrenToReparent.size() > 0)
     7294            if (task.mpChildrenToReparent)
    73047295            {
    73057296                /* obey {parent,child} lock order */
    73067297                AutoWriteLock sourceLock(this COMMA_LOCKVAL_SRC_POS);
    73077298
    7308                 for (MediaList::const_iterator it = task.mChildrenToReparent.begin();
    7309                      it != task.mChildrenToReparent.end();
    7310                      it++)
     7299                MediumLockList::Base::iterator childrenBegin = task.mpChildrenToReparent->GetBegin();
     7300                MediumLockList::Base::iterator childrenEnd = task.mpChildrenToReparent->GetEnd();
     7301                for (MediumLockList::Base::iterator it = childrenBegin;
     7302                     it != childrenEnd;
     7303                     ++it)
    73117304                {
    7312                     Medium *pMedium = *it;
     7305                    Medium *pMedium = it->GetMedium();
    73137306                    AutoWriteLock childLock(pMedium COMMA_LOCKVAL_SRC_POS);
    73147307
     
    73967389         * don't own the merge chain, so release it in this case. */
    73977390        if (task.isAsync())
    7398         {
    7399             Assert(task.mChildrenToReparent.size() == 0);
    7400             cancelMergeTo(task.mChildrenToReparent, task.mpMediumLockList);
    7401         }
     7391            cancelMergeTo(task.mpChildrenToReparent, task.mpMediumLockList);
    74027392    }
    74037393
  • trunk/src/VBox/Main/src-server/MediumLock.cpp

    r45595 r48297  
    55
    66/*
    7  * Copyright (C) 2010 Oracle Corporation
     7 * Copyright (C) 2010-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    7575}
    7676
    77 HRESULT MediumLock::Lock()
     77bool MediumLock::IsLocked() const
     78{
     79    return mIsLocked;
     80}
     81
     82HRESULT MediumLock::Lock(bool aIgnoreLockedMedia)
    7883{
    7984    if (mIsLocked)
     
    102107        default:
    103108            if (mLockWrite)
    104                 rc = mMedium->LockWrite(NULL);
     109            {
     110                if (aIgnoreLockedMedia && (   state == MediumState_LockedRead
     111                                           || state == MediumState_LockedWrite))
     112                    return S_OK;
     113                else
     114                    rc = mMedium->LockWrite(mToken.asOutParam());
     115            }
    105116            else
    106                 rc = mMedium->LockRead(NULL);
     117            {
     118                if (aIgnoreLockedMedia && state == MediumState_LockedWrite)
     119                    return S_OK;
     120                else
     121                    rc = mMedium->LockRead(mToken.asOutParam());
     122            }
    107123    }
    108124    if (SUCCEEDED(rc))
     
    121137{
    122138    HRESULT rc = S_OK;
    123     if (mIsLocked && !mLockSkipped)
    124     {
    125         if (mLockWrite)
    126             rc = mMedium->UnlockWrite(NULL);
    127         else
    128             rc = mMedium->UnlockRead(NULL);
     139    if (mIsLocked && !mLockSkipped && mToken)
     140    {
     141        mToken->Abandon();
     142        mToken.setNull();
    129143    }
    130144    mMediumCaller.attach(NULL);
     
    202216}
    203217
    204 HRESULT MediumLockList::Lock()
     218HRESULT MediumLockList::Lock(bool fSkipOverLockedMedia /* = false */)
    205219{
    206220    if (mIsLocked)
     
    211225         it++)
    212226    {
    213         rc = it->Lock();
     227        rc = it->Lock(fSkipOverLockedMedia);
    214228        if (FAILED(rc))
    215229        {
  • trunk/src/VBox/Main/src-server/SnapshotImpl.cpp

    r47401 r48297  
    21042104
    21052105/**
    2106  * Implementation for IInternalMachineControl::deleteSnapshot().
     2106 * Implementation for IInternalMachineControl::DeleteSnapshot().
    21072107 *
    21082108 * Gets called from Console::DeleteSnapshot(), and that's basically the
     
    22942294                    bool fMergeForward,
    22952295                    const ComObjPtr<Medium> &aParentForTarget,
    2296                     const MediaList &aChildrenToReparent,
     2296                    MediumLockList *aChildrenToReparent,
    22972297                    bool fNeedsOnlineMerge,
    2298                     MediumLockList *aMediumLockList)
     2298                    MediumLockList *aMediumLockList,
     2299                    const ComPtr<IToken> &aHDLockToken)
    22992300        : mpHD(aHd),
    23002301          mpSource(aSource),
     
    23032304          mfMergeForward(fMergeForward),
    23042305          mpParentForTarget(aParentForTarget),
    2305           mChildrenToReparent(aChildrenToReparent),
     2306          mpChildrenToReparent(aChildrenToReparent),
    23062307          mfNeedsOnlineMerge(fNeedsOnlineMerge),
    2307           mpMediumLockList(aMediumLockList)
     2308          mpMediumLockList(aMediumLockList),
     2309          mpHDLockToken(aHDLockToken)
    23082310    {}
    23092311
     
    23142316                    bool fMergeForward,
    23152317                    const ComObjPtr<Medium> &aParentForTarget,
    2316                     const MediaList &aChildrenToReparent,
     2318                    MediumLockList *aChildrenToReparent,
    23172319                    bool fNeedsOnlineMerge,
    23182320                    MediumLockList *aMediumLockList,
     2321                    const ComPtr<IToken> &aHDLockToken,
    23192322                    const Guid &aMachineId,
    23202323                    const Guid &aSnapshotId)
     
    23252328          mfMergeForward(fMergeForward),
    23262329          mpParentForTarget(aParentForTarget),
    2327           mChildrenToReparent(aChildrenToReparent),
     2330          mpChildrenToReparent(aChildrenToReparent),
    23282331          mfNeedsOnlineMerge(fNeedsOnlineMerge),
    23292332          mpMediumLockList(aMediumLockList),
     2333          mpHDLockToken(aHDLockToken),
    23302334          mMachineId(aMachineId),
    23312335          mSnapshotId(aSnapshotId)
     
    23382342    bool mfMergeForward;
    23392343    ComObjPtr<Medium> mpParentForTarget;
    2340     MediaList mChildrenToReparent;
     2344    MediumLockList *mpChildrenToReparent;
    23412345    bool mfNeedsOnlineMerge;
    23422346    MediumLockList *mpMediumLockList;
     2347    /** optional lock token, used only in case mpHD is not merged/deleted */
     2348    ComPtr<IToken> mpHDLockToken;
    23432349    /* these are for reattaching the hard disk in case of a failure: */
    23442350    Guid mMachineId;
     
    24502456            bool fMergeForward = false;
    24512457            ComObjPtr<Medium> pParentForTarget;
    2452             MediaList childrenToReparent;
     2458            MediumLockList *pChildrenToReparent = NULL;
    24532459            bool fNeedsOnlineMerge = false;
    24542460            bool fOnlineMergePossible = aTask.m_fDeleteOnline;
    24552461            MediumLockList *pMediumLockList = NULL;
    24562462            MediumLockList *pVMMALockList = NULL;
     2463            ComPtr<IToken> pHDLockToken;
    24572464            ComObjPtr<MediumAttachment> pOnlineMediumAttachment;
    24582465            if (fOnlineMergePossible)
     
    24872494                                             pVMMALockList, pSource, pTarget,
    24882495                                             fMergeForward, pParentForTarget,
    2489                                              childrenToReparent,
     2496                                             pChildrenToReparent,
    24902497                                             fNeedsOnlineMerge,
    2491                                              pMediumLockList);
     2498                                             pMediumLockList,
     2499                                             pHDLockToken);
    24922500            treeLock.acquire();
    24932501            if (FAILED(rc))
     
    25452553                                                   fMergeForward,
    25462554                                                   pParentForTarget,
    2547                                                    childrenToReparent,
     2555                                                   pChildrenToReparent,
    25482556                                                   fNeedsOnlineMerge,
    25492557                                                   pMediumLockList,
     2558                                                   pHDLockToken,
    25502559                                                   replaceMachineId,
    25512560                                                   replaceSnapshotId));
     
    25562565                                                   fMergeForward,
    25572566                                                   pParentForTarget,
    2558                                                    childrenToReparent,
     2567                                                   pChildrenToReparent,
    25592568                                                   fNeedsOnlineMerge,
    2560                                                    pMediumLockList));
     2569                                                   pMediumLockList,
     2570                                                   pHDLockToken));
    25612571        }
    25622572
     
    27562766                if (it->mfNeedsOnlineMerge)
    27572767                {
     2768                    // Put the medium merge information (MediumDeleteRec) where
     2769                    // SessionMachine::FinishOnlineMergeMedium can get at it.
     2770                    // This callback will arrive while onlineMergeMedium is
     2771                    // still executing, and there can't be two tasks.
     2772                    mConsoleTaskData.mDeleteSnapshotInfo = (void *)&(*it);
    27582773                    // online medium merge, in the direction decided earlier
    27592774                    rc = onlineMergeMedium(it->mpOnlineMediumAttachment,
     
    27622777                                           it->mfMergeForward,
    27632778                                           it->mpParentForTarget,
    2764                                            it->mChildrenToReparent,
     2779                                           it->mpChildrenToReparent,
    27652780                                           it->mpMediumLockList,
    27662781                                           aTask.pProgress,
    27672782                                           &fNeedsSave);
     2783                    mConsoleTaskData.mDeleteSnapshotInfo = NULL;
    27682784                }
    27692785                else
     
    27732789                                               it->mfMergeForward,
    27742790                                               it->mpParentForTarget,
    2775                                                it->mChildrenToReparent,
     2791                                               it->mpChildrenToReparent,
    27762792                                               it->mpMediumLockList,
    27772793                                               &aTask.pProgress,
     
    29122928        {
    29132929            cancelDeleteSnapshotMedium(it->mpHD, it->mpSource,
    2914                                        it->mChildrenToReparent,
     2930                                       it->mpChildrenToReparent,
    29152931                                       it->mfNeedsOnlineMerge,
    2916                                        it->mpMediumLockList, it->mMachineId,
    2917                                        it->mSnapshotId);
     2932                                       it->mpMediumLockList, it->mpHDLockToken,
     2933                                       it->mMachineId, it->mSnapshotId);
    29182934        }
    29192935    }
     
    29662982 * @param aMergeForward Merge direction decision (out).
    29672983 * @param aParentForTarget New parent if target needs to be reparented (out).
    2968  * @param aChildrenToReparent Children which have to be reparented to the
    2969  *                      target (out).
     2984 * @param aChildrenToReparent MediumLockList with children which have to be
     2985 *                      reparented to the target (out).
    29702986 * @param fNeedsOnlineMerge Whether this merge needs to be done online (out).
    29712987 *                      If this is set to @a true then the @a aVMMALockList
     
    29742990 * @param aMediumLockList Where to store the created medium lock list (may
    29752991 *                      return NULL if no real merge is necessary).
     2992 * @param aHDLockToken  Where to store the write lock token for aHD, in case
     2993 *                      it is not merged or deleted (out).
    29762994 *
    29772995 * @note Caller must hold media tree lock for writing. This locks this object
     
    29873005                                                    bool &aMergeForward,
    29883006                                                    ComObjPtr<Medium> &aParentForTarget,
    2989                                                     MediaList &aChildrenToReparent,
     3007                                                    MediumLockList * &aChildrenToReparent,
    29903008                                                    bool &fNeedsOnlineMerge,
    2991                                                     MediumLockList * &aMediumLockList)
     3009                                                    MediumLockList * &aMediumLockList,
     3010                                                    ComPtr<IToken> &aHDLockToken)
    29923011{
    29933012    Assert(!mParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
     
    30023021                 && type != MediumType_Readonly, E_FAIL);
    30033022
     3023    aChildrenToReparent = NULL;
    30043024    aMediumLockList = NULL;
    30053025    fNeedsOnlineMerge = false;
     
    30183038             * is completed */
    30193039            alock.release();
    3020             return aHD->LockWrite(NULL);
     3040            return aHD->LockWrite(aHDLockToken.asOutParam());
    30213041        }
    30223042
     
    30493069            childLock.release();
    30503070            alock.release();
    3051             return aHD->LockWrite(NULL);
     3071            return aHD->LockWrite(aHDLockToken.asOutParam());
    30523072        }
    30533073
     
    31463166            {
    31473167                /* we will lock the children of the source for reparenting */
    3148                 for (MediaList::const_iterator it = aChildrenToReparent.begin();
    3149                      it != aChildrenToReparent.end();
    3150                      ++it)
     3168                if (aChildrenToReparent && !aChildrenToReparent->IsEmpty())
    31513169                {
    3152                     ComObjPtr<Medium> pMedium = *it;
    3153                     AutoReadLock mediumLock(pMedium COMMA_LOCKVAL_SRC_POS);
    3154                     if (pMedium->getState() == MediumState_Created)
     3170                    /* Cannot just call aChildrenToReparent->Lock(), as one of
     3171                     * the children is the one under which the current state of
     3172                     * the VM is located, and this means it is already locked
     3173                     * (for reading). Note that no special unlocking is needed,
     3174                     * because cancelMergeTo will unlock everything locked in
     3175                     * its context (using the unlock on destruction), and both
     3176                     * cancelDeleteSnapshotMedium (in case something fails) and
     3177                     * FinishOnlineMergeMedium re-define the read/write lock
     3178                     * state of everything which the VM need, search for the
     3179                     * UpdateLock method calls. */
     3180                    childLock.release();
     3181                    alock.release();
     3182                    rc = aChildrenToReparent->Lock(true /* fSkipOverLockedMedia */);
     3183                    alock.acquire();
     3184                    childLock.acquire();
     3185                    MediumLockList::Base::iterator childrenToReparentBegin = aChildrenToReparent->GetBegin();
     3186                    MediumLockList::Base::iterator childrenToReparentEnd = aChildrenToReparent->GetEnd();
     3187                    for (MediumLockList::Base::iterator it = childrenToReparentBegin;
     3188                         it != childrenToReparentEnd;
     3189                         ++it)
    31553190                    {
    3156                         mediumLock.release();
    3157                         childLock.release();
    3158                         alock.release();
    3159                         rc = pMedium->LockWrite(NULL);
    3160                         alock.acquire();
    3161                         childLock.acquire();
    3162                         mediumLock.acquire();
    3163                         if (FAILED(rc))
    3164                             throw rc;
    3165                     }
    3166                     else
    3167                     {
    3168                         mediumLock.release();
    3169                         childLock.release();
    3170                         alock.release();
    3171                         rc = aVMMALockList->Update(pMedium, true);
    3172                         alock.acquire();
    3173                         childLock.acquire();
    3174                         mediumLock.acquire();
    3175                         if (FAILED(rc))
     3191                        ComObjPtr<Medium> pMedium = it->GetMedium();
     3192                        AutoReadLock mediumLock(pMedium COMMA_LOCKVAL_SRC_POS);
     3193                        if (!it->IsLocked())
    31763194                        {
    31773195                            mediumLock.release();
    31783196                            childLock.release();
    31793197                            alock.release();
    3180                             rc = pMedium->LockWrite(NULL);
     3198                            rc = aVMMALockList->Update(pMedium, true);
    31813199                            alock.acquire();
    31823200                            childLock.acquire();
     
    32653283 * @param fNeedsOnlineMerge Whether this merge needs to be done online.
    32663284 * @param aMediumLockList Medium locks to cancel.
     3285 * @param aHDLockToken  Optional write lock token for aHD.
    32673286 * @param aMachineId    Machine id to attach the medium to.
    32683287 * @param aSnapshotId   Snapshot id to attach the medium to.
     
    32723291void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr<Medium> &aHD,
    32733292                                                const ComObjPtr<Medium> &aSource,
    3274                                                 const MediaList &aChildrenToReparent,
     3293                                                MediumLockList *aChildrenToReparent,
    32753294                                                bool fNeedsOnlineMerge,
    32763295                                                MediumLockList *aMediumLockList,
     3296                                                const ComPtr<IToken> &aHDLockToken,
    32773297                                                const Guid &aMachineId,
    32783298                                                const Guid &aSnapshotId)
     
    32863306        if (aHD->getParent().isNull())
    32873307        {
    3288             HRESULT rc = aHD->UnlockWrite(NULL);
    3289             AssertComRC(rc);
     3308            Assert(!aHDLockToken.isNull());
     3309            if (!aHDLockToken.isNull())
     3310            {
     3311                HRESULT rc = aHDLockToken->Abandon();
     3312                AssertComRC(rc);
     3313            }
    32903314        }
    32913315        else
     
    33543378 * @param aMergeForward Merge direction.
    33553379 * @param aParentForTarget New parent if target needs to be reparented.
    3356  * @param aChildrenToReparent Children which have to be reparented to the
    3357  *                      target.
     3380 * @param aChildrenToReparent Medium lock list with children which have to be
     3381 *                      reparented to the target.
    33583382 * @param aMediumLockList Where to store the created medium lock list (may
    33593383 *                      return NULL if no real merge is necessary).
     
    33663390                                          bool fMergeForward,
    33673391                                          const ComObjPtr<Medium> &aParentForTarget,
    3368                                           const MediaList &aChildrenToReparent,
     3392                                          MediumLockList *aChildrenToReparent,
    33693393                                          MediumLockList *aMediumLockList,
    33703394                                          ComObjPtr<Progress> &aProgress,
     
    34153439                       && uTargetIdx != (unsigned)-1, E_FAIL);
    34163440
    3417         // For forward merges, tell the VM what images need to have their
    3418         // parent UUID updated. This cannot be done in VBoxSVC, as opening
    3419         // the required parent images is not safe while the VM is running.
    3420         // For backward merges this will be simply an array of size 0.
    3421         com::SafeIfaceArray<IMedium> childrenToReparent(aChildrenToReparent);
    3422 
    34233441        ComPtr<IInternalSessionControl> directControl;
    34243442        {
     
    34363454        rc = directControl->OnlineMergeMedium(aMediumAttachment,
    34373455                                              uSourceIdx, uTargetIdx,
    3438                                               aSource, aTarget,
    3439                                               fMergeForward, aParentForTarget,
    3440                                               ComSafeArrayAsInParam(childrenToReparent),
    34413456                                              aProgress);
    34423457        if (FAILED(rc))
     
    34543469
    34553470/**
    3456  * Implementation for IInternalMachineControl::finishOnlineMergeMedium().
     3471 * Implementation for IInternalMachineControl::FinishOnlineMergeMedium().
    34573472 *
    34583473 * Gets called after the successful completion of an online merge from
     
    34633478 * can continue with the updated state of the medium chain.
    34643479 */
    3465 STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumAttachment,
    3466                                                      IMedium *aSource,
    3467                                                      IMedium *aTarget,
    3468                                                      BOOL aMergeForward,
    3469                                                      IMedium *aParentForTarget,
    3470                                                      ComSafeArrayIn(IMedium *, aChildrenToReparent))
     3480STDMETHODIMP SessionMachine::FinishOnlineMergeMedium()
    34713481{
    34723482    HRESULT rc = S_OK;
    3473     ComObjPtr<Medium> pSource(static_cast<Medium *>(aSource));
    3474     ComObjPtr<Medium> pTarget(static_cast<Medium *>(aTarget));
    3475     ComObjPtr<Medium> pParentForTarget(static_cast<Medium *>(aParentForTarget));
     3483    MediumDeleteRec *pDeleteRec = (MediumDeleteRec *)mConsoleTaskData.mDeleteSnapshotInfo;
     3484    AssertReturn(pDeleteRec, E_FAIL);
    34763485    bool fSourceHasChildren = false;
    34773486
     
    34863495    ComObjPtr<Medium> targetChild;
    34873496
    3488     if (aMergeForward)
     3497    if (pDeleteRec->mfMergeForward)
    34893498    {
    34903499        // first, unregister the target since it may become a base
    34913500        // hard disk which needs re-registration
    3492         rc = mParent->unregisterMedium(pTarget);
     3501        rc = mParent->unregisterMedium(pDeleteRec->mpTarget);
    34933502        AssertComRC(rc);
    34943503
    34953504        // then, reparent it and disconnect the deleted branch at
    34963505        // both ends (chain->parent() is source's parent)
    3497         pTarget->deparent();
    3498         pTarget->setParent(pParentForTarget);
    3499         if (pParentForTarget)
    3500             pSource->deparent();
     3506        pDeleteRec->mpTarget->deparent();
     3507        pDeleteRec->mpTarget->setParent(pDeleteRec->mpParentForTarget);
     3508        if (pDeleteRec->mpParentForTarget)
     3509            pDeleteRec->mpSource->deparent();
    35013510
    35023511        // then, register again
    3503         rc = mParent->registerMedium(pTarget, &pTarget, DeviceType_HardDisk);
     3512        rc = mParent->registerMedium(pDeleteRec->mpTarget, &pDeleteRec->mpTarget, DeviceType_HardDisk);
    35043513        AssertComRC(rc);
    35053514    }
    35063515    else
    35073516    {
    3508         Assert(pTarget->getChildren().size() == 1);
    3509         targetChild = pTarget->getChildren().front();
     3517        Assert(pDeleteRec->mpTarget->getChildren().size() == 1);
     3518        targetChild = pDeleteRec->mpTarget->getChildren().front();
    35103519
    35113520        // disconnect the deleted branch at the elder end
     
    35143523        // Update parent UUIDs of the source's children, reparent them and
    35153524        // disconnect the deleted branch at the younger end
    3516         com::SafeIfaceArray<IMedium> childrenToReparent(ComSafeArrayInArg(aChildrenToReparent));
    3517         if (childrenToReparent.size() > 0)
     3525        if (pDeleteRec->mpChildrenToReparent && !pDeleteRec->mpChildrenToReparent->IsEmpty())
    35183526        {
    35193527            fSourceHasChildren = true;
     
    35233531            // we must continue. The worst possible result is that the images
    35243532            // need manual fixing via VBoxManage to adjust the parent UUID.
    3525             MediaList toReparent;
    3526             for (size_t i = 0; i < childrenToReparent.size(); i++)
     3533            treeLock.release();
     3534            pDeleteRec->mpTarget->fixParentUuidOfChildren(pDeleteRec->mpChildrenToReparent);
     3535            // The childen are still write locked, unlock them now and don't
     3536            // rely on the destructor doing it very late.
     3537            pDeleteRec->mpChildrenToReparent->Unlock();
     3538            treeLock.acquire();
     3539
     3540            // obey {parent,child} lock order
     3541            AutoWriteLock sourceLock(pDeleteRec->mpSource COMMA_LOCKVAL_SRC_POS);
     3542
     3543            MediumLockList::Base::iterator childrenBegin = pDeleteRec->mpChildrenToReparent->GetBegin();
     3544            MediumLockList::Base::iterator childrenEnd = pDeleteRec->mpChildrenToReparent->GetEnd();
     3545            for (MediumLockList::Base::iterator it = childrenBegin;
     3546                 it != childrenEnd;
     3547                 ++it)
    35273548            {
    3528                 Medium *pMedium = static_cast<Medium *>(childrenToReparent[i]);
    3529                 toReparent.push_back(pMedium);
    3530             }
    3531             treeLock.release();
    3532             pTarget->fixParentUuidOfChildren(toReparent);
    3533             treeLock.acquire();
    3534 
    3535             // obey {parent,child} lock order
    3536             AutoWriteLock sourceLock(pSource COMMA_LOCKVAL_SRC_POS);
    3537 
    3538             for (size_t i = 0; i < childrenToReparent.size(); i++)
    3539             {
    3540                 Medium *pMedium = static_cast<Medium *>(childrenToReparent[i]);
     3549                Medium *pMedium = it->GetMedium();
    35413550                AutoWriteLock childLock(pMedium COMMA_LOCKVAL_SRC_POS);
    35423551
    35433552                pMedium->deparent();  // removes pMedium from source
    3544                 pMedium->setParent(pTarget);
     3553                pMedium->setParent(pDeleteRec->mpTarget);
    35453554            }
    35463555        }
     
    35493558    /* unregister and uninitialize all hard disks removed by the merge */
    35503559    MediumLockList *pMediumLockList = NULL;
    3551     MediumAttachment *pMediumAttachment = static_cast<MediumAttachment *>(aMediumAttachment);
    3552     rc = mData->mSession.mLockedMedia.Get(pMediumAttachment, pMediumLockList);
    3553     const ComObjPtr<Medium> &pLast = aMergeForward ? pTarget : pSource;
     3560    rc = mData->mSession.mLockedMedia.Get(pDeleteRec->mpOnlineMediumAttachment, pMediumLockList);
     3561    const ComObjPtr<Medium> &pLast = pDeleteRec->mfMergeForward ? pDeleteRec->mpTarget : pDeleteRec->mpSource;
    35543562    AssertReturn(SUCCEEDED(rc) && pMediumLockList, E_FAIL);
    35553563    MediumLockList::Base::iterator lockListBegin =
     
    35673575
    35683576        /* The target and all images not merged (readonly) are skipped */
    3569         if (   pMedium == pTarget
     3577        if (   pMedium == pDeleteRec->mpTarget
    35703578            || pMedium->getState() == MediumState_LockedRead)
    35713579        {
     
    35893597             * and therefore we cannot uninit() it (it's therefore
    35903598             * the caller's responsibility) */
    3591             if (pMedium == aSource)
     3599            if (pMedium == pDeleteRec->mpSource)
    35923600            {
    3593                 Assert(pSource->getChildren().size() == 0);
    3594                 Assert(pSource->getFirstMachineBackrefId() == NULL);
     3601                Assert(pDeleteRec->mpSource->getChildren().size() == 0);
     3602                Assert(pDeleteRec->mpSource->getFirstMachineBackrefId() == NULL);
    35953603            }
    35963604
     
    36283636     * attachment, as the previously associated one (source) is now deleted.
    36293637     * Without the immediate update the VM could not continue running. */
    3630     if (!aMergeForward && !fSourceHasChildren)
    3631     {
    3632         AutoWriteLock attLock(pMediumAttachment COMMA_LOCKVAL_SRC_POS);
    3633         pMediumAttachment->updateMedium(pTarget);
     3638    if (!pDeleteRec->mfMergeForward && !fSourceHasChildren)
     3639    {
     3640        AutoWriteLock attLock(pDeleteRec->mpOnlineMediumAttachment COMMA_LOCKVAL_SRC_POS);
     3641        pDeleteRec->mpOnlineMediumAttachment->updateMedium(pDeleteRec->mpTarget);
    36343642    }
    36353643
  • trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp

    r47597 r48297  
    47324732
    47334733/**
     4734 * Returns the lock handle which protects the machines list. As opposed
     4735 * to version 3.1 and earlier, these lists are no longer protected by the
     4736 * VirtualBox lock, but by this more specialized lock. Mind the locking
     4737 * order: always request this lock after the VirtualBox object lock but
     4738 * before the locks of any machine object. See AutoLock.h.
     4739 */
     4740RWLockHandle& VirtualBox::getMachinesListLockHandle()
     4741{
     4742    return m->lockMachines;
     4743}
     4744
     4745/**
    47344746 * Returns the lock handle which protects the media trees (hard disks,
    47354747 * DVDs, floppies). As opposed to version 3.1 and earlier, these lists
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