VirtualBox

Changeset 25903 in vbox


Ignore:
Timestamp:
Jan 18, 2010 6:15:43 PM (15 years ago)
Author:
vboxsync
Message:

Main: make restoreSnapshot() work with the lock validator; take saveSettings() out of a lot of functions and instead return a flag to the caller so the caller can make that call; as a side effect, this no longer calls saveSettings multiple times in several code paths (e.g. restoreSnapshot()) and cleans up locking in medium tasks

Location:
trunk/src/VBox/Main
Files:
8 edited

Legend:

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

    r25902 r25903  
    17521752    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    17531753
    1754     AutoWriteLock alock(this);
     1754    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    17551755
    17561756    if (   mMachineState != MachineState_Running
     
    19051905    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    19061906
    1907     AutoWriteLock alock(this);
     1907    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    19081908
    19091909    if (   mMachineState != MachineState_Running
  • trunk/src/VBox/Main/MachineImpl.cpp

    r25901 r25903  
    11291129    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    11301130
    1131     AutoReadLock alock(this);
     1131    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11321132
    11331133    *enabled = mHWData->mCPUHotPlugEnabled;
     
    11431143    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    11441144
    1145     AutoWriteLock alock(this);
     1145    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    11461146
    11471147    rc = checkStateDependency(MutableStateDep);
     
    24262426    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    24272427
    2428     /* VirtualBox::findHardDisk() and the corresponding other methods for
    2429      * DVD and floppy media need *write* lock (for getting rid of unneeded
    2430      * host drives which got enumerated); also we want to make sure the
    2431      * media object we pick up doesn't get unregistered before we finish. */
    2432     AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
     2428    // if this becomes true then we need to call saveSettings in the end
     2429    // @todo r=dj there is no error handling so far...
     2430    bool fNeedsSaveSettings = false;
     2431
     2432    /* protect the media tree all the while we're in here, as well as our member variables */
     2433    AutoMultiWriteLock2 alock(this->lockHandle(), &mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    24332434
    24342435    HRESULT rc = checkStateDependency(MutableStateDep);
     
    25052506            break;
    25062507
    2507         case DeviceType_DVD:
     2508        case DeviceType_DVD: // @todo r=dj eliminate this, replace with findDVDImage
    25082509            if (!uuid.isEmpty())
    25092510            {
     
    25382539            break;
    25392540
    2540         case DeviceType_Floppy:
     2541        case DeviceType_Floppy: // @todo r=dj eliminate this, replace with findFloppyImage
    25412542            if (!uuid.isEmpty())
    25422543            {
     
    25822583    AutoWriteLock mediumLock(medium COMMA_LOCKVAL_SRC_POS);
    25832584
    2584     if (   (pAttachTemp = findAttachment(mMediaData->mAttachments, medium))
    2585         && !medium.isNull())
    2586     {
     2585    if (    (pAttachTemp = findAttachment(mMediaData->mAttachments, medium))
     2586         && !medium.isNull()
     2587       )
    25872588        return setError(VBOX_E_OBJECT_IN_USE,
    25882589                        tr("Medium '%s' is already attached to this virtual machine"),
    25892590                        medium->getLocationFull().raw());
    2590     }
    25912591
    25922592    bool indirect = false;
     
    27742774                        medium->preferredDiffFormat().raw(),
    27752775                        BstrFmt("%ls"RTPATH_SLASH_STR,
    2776                                  mUserData->mSnapshotFolderFull.raw()).raw());
     2776                                 mUserData->mSnapshotFolderFull.raw()).raw(),
     2777                        &fNeedsSaveSettings);
    27772778        if (FAILED(rc)) return rc;
    27782779
     
    27892790        alock.leave();
    27902791
    2791         rc = medium->createDiffStorageAndWait(diff, MediumVariant_Standard);
     2792        rc = medium->createDiffStorageAndWait(diff, MediumVariant_Standard, &fNeedsSaveSettings);
    27922793
    27932794        alock.enter();
     
    28262827    mMediaData->mAttachments.push_back(attachment);
    28272828
     2829    if (fNeedsSaveSettings)
     2830    {
     2831        mediumLock.release();
     2832        alock.release();
     2833
     2834        AutoWriteLock(mParent COMMA_LOCKVAL_SRC_POS);
     2835        mParent->saveSettings();
     2836    }
     2837
    28282838    return rc;
    28292839}
     
    28392849    AutoCaller autoCaller(this);
    28402850    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     2851
     2852    bool fNeedsSaveSettings = false;
    28412853
    28422854    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    28812893        alock.leave();
    28822894
    2883         rc = oldmedium->deleteStorageAndWait();
     2895        rc = oldmedium->deleteStorageAndWait(NULL /*aProgress*/, &fNeedsSaveSettings);
    28842896
    28852897        alock.enter();
     
    29002912    if (mediumType != DeviceType_HardDisk && !oldmedium.isNull())
    29012913        oldmedium->detachFrom(mData->mUuid);
     2914
     2915    if (fNeedsSaveSettings)
     2916    {
     2917        alock.release();
     2918        AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS);
     2919        saveSettings();
     2920    }
    29022921
    29032922    return S_OK;
     
    43604379    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    43614380
    4362     AutoWriteLock alock(this);
     4381    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    43634382
    43644383    if (!mHWData->mCPUHotPlugEnabled)
     
    43944413    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    43954414
    4396     AutoWriteLock alock(this);
     4415    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    43974416
    43984417    if (!mHWData->mCPUHotPlugEnabled)
     
    44374456    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    44384457
    4439     AutoReadLock alock(this);
     4458    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    44404459
    44414460    /* If hotplug is enabled the CPU is always enabled. */
     
    69666985 *  - SaveS_InformCallbacksAnyway: Callbacks will be informed even if
    69676986 *    #isReallyModified() returns false. This is necessary for cases when we
    6968  *    change machine data diectly, not through the backup()/commit() mechanism.
     6987 *    change machine data directly, not through the backup()/commit() mechanism.
    69696988 *
    69706989 * @note Must be called from under mParent write lock (sometimes needed by
     
    75207539 *                          attached).
    75217540 * @param aOnline           Whether the VM was online prior to this operation.
     7541 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     7542 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
    75227543 *
    75237544 * @note The progress object is not marked as completed, neither on success nor
     
    75297550                                     IProgress *aProgress,
    75307551                                     ULONG aWeight,
    7531                                      bool aOnline)
     7552                                     bool aOnline,
     7553                                     bool *pfNeedsSaveSettings)
    75327554{
    75337555    AssertReturn(!aFolder.isEmpty(), E_FAIL);
     
    76257647                            medium->preferredDiffFormat().raw(),
    76267648                            BstrFmt("%ls"RTPATH_SLASH_STR,
    7627                                     mUserData->mSnapshotFolderFull.raw()).raw());
     7649                                    mUserData->mSnapshotFolderFull.raw()).raw(),
     7650                            pfNeedsSaveSettings);
    76287651            if (FAILED(rc)) throw rc;
    76297652
     
    76337656            rc = medium->createDiffStorageAndWait(diff,
    76347657                                                  MediumVariant_Standard,
    7635                                                   NULL);
     7658                                                  pfNeedsSaveSettings);
    76367659
    76377660            /** @todo r=bird: How is the locking and diff image cleaned up if we fail before
     
    76937716        MultiResultRef mrc (rc);
    76947717
    7695         mrc = deleteImplicitDiffs();
     7718        mrc = deleteImplicitDiffs(pfNeedsSaveSettings);
    76967719    }
    76977720
     
    77067729 * called from #fixupMedia() when the changes are rolled back.
    77077730 *
     7731 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     7732 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     7733 *
    77087734 * @note Locks this object for writing.
    77097735 */
    7710 HRESULT Machine::deleteImplicitDiffs()
     7736HRESULT Machine::deleteImplicitDiffs(bool *pfNeedsSaveSettings)
    77117737{
    77127738    AutoCaller autoCaller(this);
     
    77837809            ComObjPtr<Medium> hd = (*it)->getMedium();
    77847810
    7785             rc = hd->deleteStorageAndWait();
     7811            rc = hd->deleteStorageAndWait(NULL /*aProgress*/, pfNeedsSaveSettings);
    77867812#if 1 /* HACK ALERT: Just make it kind of work */ /** @todo Fix this hack properly. The LockWrite / UnlockWrite / LockRead changes aren't undone! */
    77877813            if (rc == VBOX_E_INVALID_OBJECT_STATE)
     
    77897815                LogFlowFunc(("Applying unlock hack on '%s'! FIXME!\n", (*it)->getLogName()));
    77907816                hd->UnlockWrite(NULL);
    7791                 rc = hd->deleteStorageAndWait();
     7817                rc = hd->deleteStorageAndWait(NULL /*aProgress*/, pfNeedsSaveSettings);
    77927818            }
    77937819#endif
     
    78907916
    78917917/**
    7892  * Perform deferred hard disk detachments on success and deletion of implicitly
    7893  * created diffs on failure.
     7918 * Perform deferred hard disk detachments.
    78947919 *
    78957920 * Does nothing if the hard disk attachment data (mMediaData) is not changed (not
    78967921 * backed up).
    78977922 *
    7898  * When the data is backed up, this method will commit mMediaData if @a aCommit is
    7899  * @c true and rollback it otherwise before returning.
    7900  *
    7901  * If @a aOnline is @c true then this method called with @a aCommit = @c true
    7902  * will also unlock the old hard disks for which the new implicit diffs were
    7903  * created and will lock these new diffs for writing. When @a aCommit is @c
    7904  * false, this argument is ignored.
    7905  *
    7906  * @param aCommit       @c true if called on success.
     7923 * If @a aOnline is @c true then this method will also unlock the old hard disks
     7924 * for which the new implicit diffs were created and will lock these new diffs for
     7925 * writing.
     7926 *
    79077927 * @param aOnline       Whether the VM was online prior to this operation.
    79087928 *
    79097929 * @note Locks this object for writing!
    79107930 */
    7911 void Machine::fixupMedia(bool aCommit, bool aOnline /*= false*/)
     7931void Machine::commitMedia(bool aOnline /*= false*/)
    79127932{
    79137933    AutoCaller autoCaller(this);
     
    79167936    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    79177937
    7918     LogFlowThisFunc(("Entering, aCommit=%d, aOnline=%d\n", aCommit, aOnline));
     7938    LogFlowThisFunc(("Entering, aOnline=%d\n", aOnline));
    79197939
    79207940    HRESULT rc = S_OK;
     
    79247944        return;
    79257945
    7926     if (aCommit)
    7927     {
    7928         MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
    7929 
    7930         /* enumerate new attachments */
    7931         for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    7932              it != mMediaData->mAttachments.end();
    7933              ++it)
    7934         {
    7935             MediumAttachment *pAttach = *it;
    7936 
    7937             pAttach->commit();
    7938 
     7946    MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
     7947
     7948    /* enumerate new attachments */
     7949    for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
     7950            it != mMediaData->mAttachments.end();
     7951            ++it)
     7952    {
     7953        MediumAttachment *pAttach = *it;
     7954
     7955        pAttach->commit();
     7956
     7957        Medium* pMedium = pAttach->getMedium();
     7958        bool fImplicit = pAttach->isImplicit();
     7959
     7960        LogFlowThisFunc(("Examining current medium '%s' (implicit: %d)\n",
     7961                            (pMedium) ? pMedium->getName().raw() : "NULL",
     7962                            fImplicit));
     7963
     7964        /** @todo convert all this Machine-based voodoo to MediumAttachment
     7965        * based commit logic. */
     7966        if (fImplicit)
     7967        {
     7968            /* convert implicit attachment to normal */
     7969            pAttach->setImplicit(false);
     7970
     7971            if (    aOnline
     7972                    && pMedium
     7973                    && pAttach->getType() == DeviceType_HardDisk
     7974                )
     7975            {
     7976                rc = pMedium->LockWrite(NULL);
     7977                AssertComRC(rc);
     7978
     7979                mData->mSession.mLockedMedia.push_back(
     7980                    Data::Session::LockedMedia::value_type(
     7981                        ComPtr<IMedium>(pMedium), true));
     7982
     7983                /* also, relock the old hard disk which is a base for the
     7984                * new diff for reading if the VM is online */
     7985
     7986                ComObjPtr<Medium> parent = pMedium->getParent();
     7987                /* make the relock atomic */
     7988                AutoWriteLock parentLock(parent COMMA_LOCKVAL_SRC_POS);
     7989                rc = parent->UnlockWrite(NULL);
     7990                AssertComRC(rc);
     7991                rc = parent->LockRead(NULL);
     7992                AssertComRC(rc);
     7993
     7994                /* XXX actually we should replace the old entry in that
     7995                * vector (write lock => read lock) but this would take
     7996                * some effort. So lets just ignore the error code in
     7997                * SessionMachine::unlockMedia(). */
     7998                mData->mSession.mLockedMedia.push_back(
     7999                    Data::Session::LockedMedia::value_type (
     8000                        ComPtr<IMedium>(parent), false));
     8001            }
     8002
     8003            continue;
     8004        }
     8005
     8006        if (pMedium)
     8007        {
     8008            /* was this medium attached before? */
     8009            for (MediaData::AttachmentList::iterator oldIt = oldAtts.begin();
     8010                    oldIt != oldAtts.end();
     8011                    ++oldIt)
     8012            {
     8013                MediumAttachment *pOldAttach = *oldIt;
     8014                if (pOldAttach->getMedium().equalsTo(pMedium))
     8015                {
     8016                    LogFlowThisFunc(("--> medium '%s' was attached before, will not remove\n", pMedium->getName().raw()));
     8017
     8018                    /* yes: remove from old to avoid de-association */
     8019                    oldAtts.erase(oldIt);
     8020                    break;
     8021                }
     8022            }
     8023        }
     8024    }
     8025
     8026    /* enumerate remaining old attachments and de-associate from the
     8027        * current machine state */
     8028    for (MediaData::AttachmentList::const_iterator it = oldAtts.begin();
     8029            it != oldAtts.end();
     8030            ++it)
     8031    {
     8032        MediumAttachment *pAttach = *it;
     8033        Medium* pMedium = pAttach->getMedium();
     8034
     8035        /* Detach only hard disks, since DVD/floppy media is detached
     8036            * instantly in MountMedium. */
     8037        if (pAttach->getType() == DeviceType_HardDisk && pMedium)
     8038        {
     8039            LogFlowThisFunc(("detaching medium '%s' from machine\n", pMedium->getName().raw()));
     8040
     8041            /* now de-associate from the current machine state */
     8042            rc = pMedium->detachFrom(mData->mUuid);
     8043            AssertComRC(rc);
     8044
     8045            if (    aOnline
     8046                    && pAttach->getType() == DeviceType_HardDisk)
     8047            {
     8048                /* unlock since not used anymore */
     8049                MediumState_T state;
     8050                rc = pMedium->UnlockWrite(&state);
     8051                /* the disk may be alredy relocked for reading above */
     8052                Assert (SUCCEEDED(rc) || state == MediumState_LockedRead);
     8053            }
     8054        }
     8055    }
     8056
     8057    /* commit the hard disk changes */
     8058    mMediaData.commit();
     8059
     8060    if (getClassID() == clsidSessionMachine)
     8061    {
     8062        /* attach new data to the primary machine and reshare it */
     8063        mPeer->mMediaData.attach(mMediaData);
     8064    }
     8065
     8066    return;
     8067}
     8068
     8069/**
     8070 * Perform deferred deletion of implicitly created diffs.
     8071 *
     8072 * Does nothing if the hard disk attachment data (mMediaData) is not changed (not
     8073 * backed up).
     8074 *
     8075 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     8076 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     8077 *
     8078 * @note Locks this object for writing!
     8079 */
     8080void Machine::rollbackMedia()
     8081{
     8082    AutoCaller autoCaller(this);
     8083    AssertComRCReturnVoid (autoCaller.rc());
     8084
     8085    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     8086
     8087    LogFlowThisFunc(("Entering\n"));
     8088
     8089    HRESULT rc = S_OK;
     8090
     8091    /* no attach/detach operations -- nothing to do */
     8092    if (!mMediaData.isBackedUp())
     8093        return;
     8094
     8095    /* enumerate new attachments */
     8096    for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
     8097            it != mMediaData->mAttachments.end();
     8098            ++it)
     8099    {
     8100        MediumAttachment *pAttach = *it;
     8101        /* Fix up the backrefs for DVD/floppy media. */
     8102        if (pAttach->getType() != DeviceType_HardDisk)
     8103        {
    79398104            Medium* pMedium = pAttach->getMedium();
    7940             bool fImplicit = pAttach->isImplicit();
    7941 
    7942             LogFlowThisFunc(("Examining current medium '%s' (implicit: %d)\n",
    7943                              (pMedium) ? pMedium->getName().raw() : "NULL",
    7944                              fImplicit));
    7945 
    7946             /** @todo convert all this Machine-based voodoo to MediumAttachment
    7947             * based commit logic. */
    7948             if (fImplicit)
    7949             {
    7950                 /* convert implicit attachment to normal */
    7951                 pAttach->setImplicit(false);
    7952 
    7953                 if (    aOnline
    7954                      && pMedium
    7955                      && pAttach->getType() == DeviceType_HardDisk
    7956                    )
    7957                 {
    7958                     rc = pMedium->LockWrite(NULL);
    7959                     AssertComRC(rc);
    7960 
    7961                     mData->mSession.mLockedMedia.push_back(
    7962                         Data::Session::LockedMedia::value_type(
    7963                             ComPtr<IMedium>(pMedium), true));
    7964 
    7965                     /* also, relock the old hard disk which is a base for the
    7966                     * new diff for reading if the VM is online */
    7967 
    7968                     ComObjPtr<Medium> parent = pMedium->getParent();
    7969                     /* make the relock atomic */
    7970                     AutoWriteLock parentLock(parent COMMA_LOCKVAL_SRC_POS);
    7971                     rc = parent->UnlockWrite(NULL);
    7972                     AssertComRC(rc);
    7973                     rc = parent->LockRead(NULL);
    7974                     AssertComRC(rc);
    7975 
    7976                     /* XXX actually we should replace the old entry in that
    7977                     * vector (write lock => read lock) but this would take
    7978                     * some effort. So lets just ignore the error code in
    7979                     * SessionMachine::unlockMedia(). */
    7980                     mData->mSession.mLockedMedia.push_back(
    7981                         Data::Session::LockedMedia::value_type (
    7982                             ComPtr<IMedium>(parent), false));
    7983                 }
    7984 
    7985                 continue;
    7986             }
    7987 
    79888105            if (pMedium)
    79898106            {
    7990                 /* was this medium attached before? */
    7991                 for (MediaData::AttachmentList::iterator oldIt = oldAtts.begin();
    7992                      oldIt != oldAtts.end();
    7993                      ++oldIt)
    7994                 {
    7995                     MediumAttachment *pOldAttach = *oldIt;
    7996                     if (pOldAttach->getMedium().equalsTo(pMedium))
    7997                     {
    7998                         LogFlowThisFunc(("--> medium '%s' was attached before, will not remove\n", pMedium->getName().raw()));
    7999 
    8000                         /* yes: remove from old to avoid de-association */
    8001                         oldAtts.erase(oldIt);
    8002                         break;
    8003                     }
    8004                 }
    8005             }
    8006         }
    8007 
    8008         /* enumerate remaining old attachments and de-associate from the
    8009          * current machine state */
    8010         for (MediaData::AttachmentList::const_iterator it = oldAtts.begin();
    8011              it != oldAtts.end();
    8012              ++it)
    8013         {
    8014             MediumAttachment *pAttach = *it;
    8015             Medium* pMedium = pAttach->getMedium();
    8016 
    8017             /* Detach only hard disks, since DVD/floppy media is detached
    8018              * instantly in MountMedium. */
    8019             if (pAttach->getType() == DeviceType_HardDisk && pMedium)
    8020             {
    8021                 LogFlowThisFunc(("detaching medium '%s' from machine\n", pMedium->getName().raw()));
    8022 
    8023                 /* now de-associate from the current machine state */
    80248107                rc = pMedium->detachFrom(mData->mUuid);
    80258108                AssertComRC(rc);
    8026 
    8027                 if (    aOnline
    8028                      && pAttach->getType() == DeviceType_HardDisk)
    8029                 {
    8030                     /* unlock since not used anymore */
    8031                     MediumState_T state;
    8032                     rc = pMedium->UnlockWrite(&state);
    8033                     /* the disk may be alredy relocked for reading above */
    8034                     Assert (SUCCEEDED(rc) || state == MediumState_LockedRead);
    8035                 }
    80368109            }
    80378110        }
    80388111
    8039         /* commit the hard disk changes */
    8040         mMediaData.commit();
    8041 
    8042         if (getClassID() == clsidSessionMachine)
    8043         {
    8044             /* attach new data to the primary machine and reshare it */
    8045             mPeer->mMediaData.attach(mMediaData);
    8046         }
    8047     }
    8048     else
    8049     {
    8050         /* enumerate new attachments */
    8051         for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    8052              it != mMediaData->mAttachments.end();
    8053              ++it)
    8054         {
    8055             MediumAttachment *pAttach = *it;
    8056             /* Fix up the backrefs for DVD/floppy media. */
    8057             if (pAttach->getType() != DeviceType_HardDisk)
     8112        (*it)->rollback();
     8113
     8114        pAttach = *it;
     8115        /* Fix up the backrefs for DVD/floppy media. */
     8116        if (pAttach->getType() != DeviceType_HardDisk)
     8117        {
     8118            Medium* pMedium = pAttach->getMedium();
     8119            if (pMedium)
    80588120            {
    8059                 Medium* pMedium = pAttach->getMedium();
    8060                 if (pMedium)
    8061                 {
    8062                     rc = pMedium->detachFrom(mData->mUuid);
    8063                     AssertComRC(rc);
    8064                 }
     8121                rc = pMedium->attachTo(mData->mUuid);
     8122                AssertComRC(rc);
    80658123            }
    8066 
    8067             (*it)->rollback();
    8068 
    8069             pAttach = *it;
    8070             /* Fix up the backrefs for DVD/floppy media. */
    8071             if (pAttach->getType() != DeviceType_HardDisk)
    8072             {
    8073                 Medium* pMedium = pAttach->getMedium();
    8074                 if (pMedium)
    8075                 {
    8076                     rc = pMedium->attachTo(mData->mUuid);
    8077                     AssertComRC(rc);
    8078                 }
    8079             }
    8080         }
    8081 
    8082         /** @todo convert all this Machine-based voodoo to MediumAttachment
    8083          * based rollback logic. */
    8084         // @todo r=dj the below totally fails if this gets called from Machine::rollback(),
    8085         // which gets called if Machine::registeredInit() fails...
    8086         deleteImplicitDiffs();
    8087     }
     8124        }
     8125    }
     8126
     8127    /** @todo convert all this Machine-based voodoo to MediumAttachment
     8128     * based rollback logic. */
     8129    // @todo r=dj the below totally fails if this gets called from Machine::rollback(),
     8130    // which gets called if Machine::registeredInit() fails...
     8131    deleteImplicitDiffs(NULL /*pfNeedsSaveSettings*/);
    80888132
    80898133    return;
     
    83078351
    83088352    if (mMediaData.isBackedUp())
    8309         fixupMedia(false /* aCommit */);
     8353        rollbackMedia();
    83108354
    83118355    /* check for changes in child objects */
     
    84028446
    84038447    if (mMediaData.isBackedUp())
    8404         fixupMedia(true /* aCommit */);
     8448        commitMedia();
    84058449
    84068450    mBIOSSettings->commit();
     
    89138957    {
    89148958        LogWarningThisFunc(("canceling failed save state request!\n"));
    8915         endSavingState (FALSE /* aSuccess  */);
     8959        endSavingState(FALSE /* aSuccess  */);
    89168960    }
    89178961    else if (!mSnapshotData.mSnapshot.isNull())
    89188962    {
    89198963        LogWarningThisFunc(("canceling untaken snapshot!\n"));
    8920         endTakingSnapshot (FALSE /* aSuccess  */);
     8964
     8965        /* delete all differencing hard disks created (this will also attach
     8966         * their parents back by rolling back mMediaData) */
     8967        rollbackMedia();
     8968        /* delete the saved state file (it might have been already created) */
     8969        if (mSnapshotData.mSnapshot->stateFilePath().length())
     8970            RTFileDelete(mSnapshotData.mSnapshot->stateFilePath().c_str());
     8971
     8972        mSnapshotData.mSnapshot->uninit();
    89218973    }
    89228974
  • trunk/src/VBox/Main/MediumImpl.cpp

    r25888 r25903  
    118118    Utf8Str strLastAccessError;
    119119
    120     // pParent and llChildren are protected by VirtualBox::hardDiskTreeLockHandle()
     120    // pParent and llChildren are protected by VirtualBox::getMediaTreeLockHandle()
    121121    ComObjPtr<Medium> pParent;
    122122    MediaList llChildren;           // to add a child, just call push_back; to remove a child, call child->deparent() which does a lookup
     
    205205    HRESULT m_rc;
    206206
     207    // Whether the caller needs to call VirtualBox::saveSettings() after
     208    // the task function returns. Only used in synchronous (wait) mode;
     209    // otherwise the task will save the settings itself.
     210    bool *m_pfNeedsSaveSettings;
     211
    207212    Task(Medium *aThat,
    208213         Progress *aProgress,
     
    212217          m_pProgress(aProgress),
    213218          m_operation(aOperation),
    214           m_rc(S_OK)
    215     {}
     219          m_rc(S_OK),
     220          m_pfNeedsSaveSettings(NULL)
     221    { }
    216222
    217223    ~Task();
     
    258264
    259265    HRESULT startThread();
    260     HRESULT runNow();
     266    HRESULT runNow(bool *pfNeedsSaveSettings);
    261267
    262268    struct Data
     
    279285
    280286        /** Media to open, in {parent,child} order */
    281         std::auto_ptr <ImageChain> source;
     287        std::auto_ptr<ImageChain> source;
    282288        /** Media which are parent of target, in {parent,child} order */
    283         std::auto_ptr <ImageChain> parent;
     289        std::auto_ptr<ImageChain> parent;
    284290        /** The to-be parent medium object */
    285291        ComObjPtr<Medium> parentDisk;
     
    288294
    289295        /** Media to merge, in {parent,child} order */
    290         std::auto_ptr <MergeChain> chain;
     296        std::auto_ptr<MergeChain> chain;
    291297
    292298        /* Compact */
    293299
    294300        /** Media to open, in {parent,child} order */
    295         std::auto_ptr <ImageChain> images;
    296     }
    297     d;
     301        std::auto_ptr<ImageChain> images;
     302    } d;
    298303
    299304protected:
     
    354359 *       complete the progress object in this case.
    355360 */
    356 HRESULT Medium::Task::runNow()
    357 {
     361HRESULT Medium::Task::runNow(bool *pfNeedsSaveSettings)
     362{
     363    m_pfNeedsSaveSettings = pfNeedsSaveSettings;
     364
    358365    /* NIL_RTTHREAD indicates synchronous call. */
    359366    Medium::taskThread(NIL_RTTHREAD, this);
     
    880887 * @param aVirtualBox   VirtualBox object.
    881888 * @param aLocation     Storage unit location.
     889 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     890 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
    882891 */
    883892HRESULT Medium::init(VirtualBox *aVirtualBox,
    884893                     CBSTR aFormat,
    885                      CBSTR aLocation)
     894                     CBSTR aLocation,
     895                     bool *pfNeedsSaveSettings)
    886896{
    887897    AssertReturn(aVirtualBox != NULL, E_FAIL);
     
    917927        rc = setLocation(aLocation);
    918928        if (FAILED(rc)) return rc;
    919 
    920         /// @todo later we may want to use a pfnComposeLocation backend info
    921         /// callback to generate a well-formed location value (based on the hard
    922         /// disk properties we have) rather than allowing each caller to invent
    923         /// its own (pseudo-)location.
    924     }
    925 
    926     if (!(m->formatObj->capabilities() &
    927           (MediumFormatCapabilities_CreateFixed |
    928            MediumFormatCapabilities_CreateDynamic)))
     929    }
     930
     931    if (!(m->formatObj->capabilities() & (   MediumFormatCapabilities_CreateFixed
     932                                           | MediumFormatCapabilities_CreateDynamic))
     933       )
    929934    {
    930935        /* storage for hard disks of this format can neither be explicitly
     
    933938        m->state = MediumState_Created;
    934939        unconst(m->id).create();
    935         rc = m->pVirtualBox->registerHardDisk(this);
    936 
    937         /// @todo later we may want to use a pfnIsConfigSufficient backend info
    938         /// callback that would tell us when we have enough properties to work
    939         /// with the hard disk and this information could be used to actually
    940         /// move such hard disks from NotCreated to Created state. Instead of
    941         /// pfnIsConfigSufficient we can use MediumFormat property
    942         /// descriptions to see which properties are mandatory
     940
     941        AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     942        rc = m->pVirtualBox->registerHardDisk(this, pfNeedsSaveSettings);
    943943    }
    944944
     
    10781078    {
    10791079        // differencing image: add to parent
    1080         AutoWriteLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     1080        AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    10811081        m->pParent = aParent;
    10821082        aParent->m->llChildren.push_back(this);
     
    11601160     * get the actual state and the rest of the data, the user will have to call
    11611161     * COMGETTER(State). */
     1162
     1163    AutoWriteLock treeLock(aVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    11621164
    11631165    /* load all children */
     
    15411543
    15421544    /* we access mParent & children() */
    1543     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     1545    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    15441546
    15451547    /* cannot change the type of a differencing hard disk */
     
    15941596
    15951597    /* we access mParent */
    1596     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     1598    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    15971599
    15981600    m->pParent.queryInterfaceTo(aParent);
     
    16101612
    16111613    /* we access children */
    1612     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     1614    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    16131615
    16141616    SafeIfaceArray<IMedium> children(this->getChildren());
     
    16541656
    16551657        /* we access mParent */
    1656         AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     1658        AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    16571659
    16581660        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    20332035        return S_OK;
    20342036
    2035     /* unregisterWithVirtualBox() is assumed to always need a write mVirtualBox
    2036      * lock as it is intenede to modify its internal structires. Also, we want
    2037      * to unregister ourselves atomically after detecting that closure is
    2038      * possible to make sure that we don't do that after another thread has done
    2039      * VirtualBox::find*() but before it starts using us (provided that it holds
    2040      * a mVirtualBox lock of course). */
    2041 
    2042     AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     2037    // we're accessing parent/child and backrefs, so lock the tree first, then ourselves
     2038    AutoMultiWriteLock2 multilock(&m->pVirtualBox->getMediaTreeLockHandle(),
     2039                                  this->lockHandle()
     2040                                  COMMA_LOCKVAL_SRC_POS);
    20432041
    20442042    bool wasCreated = true;
     2043    bool fNeedsSaveSettings = false;
    20452044
    20462045    switch (m->state)
     
    20702069         * uninitialization (to keep the media registry consistent on
    20712070         * failure to do so) */
    2072         rc = unregisterWithVirtualBox();
     2071        rc = unregisterWithVirtualBox(&fNeedsSaveSettings);
    20732072        if (FAILED(rc)) return rc;
     2073    }
     2074
     2075    multilock.release();
     2076
     2077    if (fNeedsSaveSettings)
     2078    {
     2079        AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     2080        m->pVirtualBox->saveSettings();
    20742081    }
    20752082
     
    23892396
    23902397        /* we walk the source tree */
    2391         AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     2398        AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    23922399        for (Medium *hd = this;
    23932400             hd;
     
    24912498
    24922499        /* we walk the image tree */
    2493         AutoReadLock srcTreeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     2500        AutoReadLock srcTreeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    24942501        for (Medium *hd = this;
    24952502             hd;
     
    25562563    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    25572564
    2558     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     2565    /* canClose() needs the tree lock */
     2566    AutoMultiWriteLock2 multilock(&m->pVirtualBox->getMediaTreeLockHandle(),
     2567                                  this->lockHandle()
     2568                                  COMMA_LOCKVAL_SRC_POS);
    25592569
    25602570    LogFlowThisFunc(("ENTER for medium %s\n", m->strLocationFull.c_str()));
     
    25772587        progress.createObject();
    25782588        rc = progress->init(m->pVirtualBox,
    2579                             static_cast <IMedium *>(this),
     2589                            static_cast<IMedium*>(this),
    25802590                            BstrFmt(tr("Resetting differencing hard disk '%s'"), m->strLocationFull.raw()),
    25812591                            FALSE /* aCancelable */);
     
    25842594        /* setup task object and thread to carry out the operation
    25852595         * asynchronously */
    2586 
    25872596        std::auto_ptr<Task> task(new Task(this, progress, Task::Reset));
    25882597        AssertComRCThrowRC(task->m_autoCaller.rc());
     
    29322941
    29332942    /* we access children() */
    2934     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     2943    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    29352944
    29362945    updatePath(aOldPath, aNewPath);
     
    29662975
    29672976    /* we access mParent */
    2968     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     2977    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    29692978
    29702979    pBase = this;
     
    30053014
    30063015    /* we access children */
    3007     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     3016    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    30083017
    30093018    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    30523061
    30533062    /* we access mParent */
    3054     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     3063    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    30553064
    30563065    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    31813190
    31823191    /* we access mParent & children() */
    3183     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     3192    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    31843193
    31853194    AssertReturn(m->type == MediumType_Normal, E_FAIL);
     
    32983307 *       reading or writing.
    32993308 */
    3300 HRESULT Medium::discard(ComObjPtr<Progress> &aProgress, ULONG ulWeight, MergeChain *aChain)
     3309HRESULT Medium::discard(ComObjPtr<Progress> &aProgress,
     3310                        ULONG ulWeight,
     3311                        MergeChain *aChain,
     3312                        bool *pfNeedsSaveSettings)
    33013313{
    33023314    AssertReturn(!aProgress.isNull(), E_FAIL);
     
    33153327        if (aChain == NULL)
    33163328        {
    3317             AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3318 
    33193329            /* we access mParent & children() */
    3320             AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     3330            AutoMultiWriteLock2 mLock(&m->pVirtualBox->getMediaTreeLockHandle(), this->lockHandle() COMMA_LOCKVAL_SRC_POS);
    33213331
    33223332            Assert(getChildren().size() == 0);
     
    33403350            hdFrom = this;
    33413351
    3342             // deleteStorageAndWait calls unregisterWithVirtualBox which gets
    3343             // a write tree lock, so don't deadlock
    3344             treeLock.release();
    3345             alock.release();
    3346 
    3347             rc = deleteStorageAndWait(&aProgress);
     3352            rc = deleteStorageAndWait(&aProgress, pfNeedsSaveSettings);
    33483353        }
    33493354        else
     
    33513356            hdFrom = aChain->source();
    33523357
    3353             rc = hdFrom->mergeToAndWait(aChain, &aProgress);
     3358            rc = hdFrom->mergeToAndWait(aChain, &aProgress, pfNeedsSaveSettings);
    33543359        }
    33553360    }
     
    33863391
    33873392        /* we access mParent & children() */
    3388         AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     3393        AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    33893394
    33903395        Assert(getChildren().size() == 0);
     
    38523857
    38533858                    /* we set mParent & children() */
    3854                     AutoWriteLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     3859                    AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    38553860
    38563861                    Assert(m->pParent.isNull());
     
    38613866                {
    38623867                    /* we access mParent */
    3863                     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     3868                    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    38643869
    38653870                    /* check that parent UUIDs match. Note that there's no need
     
    40444049 * @param aWait         @c true if this method should block instead of creating
    40454050 *                      an asynchronous thread.
     4051 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     4052 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     4053 *                This only works in "wait" mode; otherwise saveSettings gets called automatically by the thread that was created,
     4054 *                and this parameter is ignored.
    40464055 *
    40474056 * @note Locks mVirtualBox and this object for writing. Locks getTreeLock() for
    40484057 *       writing.
    40494058 */
    4050 HRESULT Medium::deleteStorage(ComObjPtr <Progress> *aProgress, bool aWait)
     4059HRESULT Medium::deleteStorage(ComObjPtr<Progress> *aProgress,
     4060                              bool aWait,
     4061                              bool *pfNeedsSaveSettings)
    40514062{
    40524063    AssertReturn(aProgress != NULL || aWait == true, E_FAIL);
    40534064
    4054     /* unregisterWithVirtualBox() needs a write lock. We want to unregister
    4055      * ourselves atomically after detecting that deletion is possible to make
    4056      * sure that we don't do that after another thread has done
    4057      * VirtualBox::findHardDisk() but before it starts using us (provided that
    4058      * it holds a mVirtualBox lock too of course). */
    4059 
    4060     AutoMultiWriteLock2 alock(m->pVirtualBox->lockHandle(), this->lockHandle() COMMA_LOCKVAL_SRC_POS);
     4065    /* we're accessing the media tree, and canClose() needs the tree lock too */
     4066    AutoMultiWriteLock2 multilock(&m->pVirtualBox->getMediaTreeLockHandle(),
     4067                                  this->lockHandle()
     4068                                  COMMA_LOCKVAL_SRC_POS);
    40614069    LogFlowThisFunc(("aWait=%RTbool locationFull=%s\n", aWait, getLocationFull().c_str() ));
    40624070
     
    41114119    m->state = MediumState_Deleting;
    41124120
    4113     /* we need to leave this object's write lock now because of
    4114      * unregisterWithVirtualBox() that locks getTreeLock() for writing */
    4115     alock.leave();
    4116 
    41174121    /* try to remove from the list of known hard disks before performing actual
    41184122     * deletion (we favor the consistency of the media registry in the first
    41194123     * place which would have been broken if unregisterWithVirtualBox() failed
    41204124     * after we successfully deleted the storage) */
    4121 
    4122     rc = unregisterWithVirtualBox();
    4123 
    4124     alock.enter();
     4125    rc = unregisterWithVirtualBox(pfNeedsSaveSettings);
    41254126
    41264127    /* restore the state because we may fail below; we will set it later again*/
     
    41484149    }
    41494150
    4150     std::auto_ptr <Task> task(new Task(this, progress, Task::Delete));
     4151    std::auto_ptr<Task> task(new Task(this, progress, Task::Delete));
    41514152    AssertComRCReturnRC(task->m_autoCaller.rc());
    41524153
     
    41564157        m->state = MediumState_Deleting;
    41574158
    4158         rc = task->runNow();
     4159        rc = task->runNow(NULL /* pfNeedsSaveSettings*/ );        // there is no save settings to do in taskThreadDelete()
    41594160    }
    41604161    else
     
    42114212 * @param aWait         @c true if this method should block instead of creating
    42124213 *                      an asynchronous thread.
     4214 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     4215 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     4216 *                This only works in "wait" mode; otherwise saveSettings gets called automatically by the thread that was created,
     4217 *                and this parameter is ignored.
    42134218 *
    42144219 * @note Locks this object and @a aTarget for writing.
     
    42174222                                  MediumVariant_T aVariant,
    42184223                                  ComObjPtr<Progress> *aProgress,
    4219                                   bool aWait)
     4224                                  bool aWait,
     4225                                  bool *pfNeedsSaveSettings)
    42204226{
    42214227    AssertReturn(!aTarget.isNull(), E_FAIL);
     
    42334239
    42344240    /* Note: MediumState_LockedWrite is ok when taking an online snapshot */
    4235     AssertReturn(m->state == MediumState_LockedRead ||
    4236                   m->state == MediumState_LockedWrite, E_FAIL);
     4241    AssertReturn(    m->state == MediumState_LockedRead
     4242                  || m->state == MediumState_LockedWrite, E_FAIL);
    42374243
    42384244    if (aTarget->m->state != MediumState_NotCreated)
     
    42434249    /* check that the hard disk is not attached to any VM in the current state*/
    42444250    for (BackRefList::const_iterator it = m->backRefs.begin();
    4245          it != m->backRefs.end(); ++ it)
     4251         it != m->backRefs.end();
     4252         ++it)
    42464253    {
    42474254        if (it->fInCurState)
     
    42574264
    42584265            if (it->llSnapshotIds.size() == 0)
    4259             {
    42604266                return setError(VBOX_E_INVALID_OBJECT_STATE,
    42614267                                tr("Hard disk '%s' is attached to a virtual machine with UUID {%RTuuid}. No differencing hard disks based on it may be created until it is detached"),
    42624268                                m->strLocationFull.raw(), it->machineId.raw());
    4263             }
    42644269
    42654270            Assert(it->llSnapshotIds.size() == 1);
     
    42674272    }
    42684273
    4269     ComObjPtr <Progress> progress;
     4274    ComObjPtr<Progress> progress;
    42704275
    42714276    if (aProgress != NULL)
     
    42864291    }
    42874292
    4288     /* setup task object and thread to carry out the operation
     4293    /* set up task object and thread to carry out the operation
    42894294     * asynchronously */
    42904295
    4291     std::auto_ptr <Task> task(new Task(this, progress, Task::CreateDiff));
     4296    std::auto_ptr<Task> task(new Task(this, progress, Task::CreateDiff));
    42924297    AssertComRCReturnRC(task->m_autoCaller.rc());
    42934298
     
    43014306    if (aWait)
    43024307    {
    4303         /* go to Creating state before starting the task */
     4308        // go to Creating state before starting the task
    43044309        aTarget->m->state = MediumState_Creating;
    43054310
    4306         rc = task->runNow();
     4311        // release the locks because the task function will acquire other locks;
     4312        // this is safe because both this and the target are not protected by
     4313        // their states; we have asserted above that *this* is locked read or write!
     4314        alock.release();
     4315
     4316        rc = task->runNow(pfNeedsSaveSettings);
    43074317    }
    43084318    else
     
    43654375
    43664376    /* we walk the tree */
    4367     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     4377    AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    43684378
    43694379    HRESULT rc = S_OK;
     
    44954505 * @param aWait         @c true if this method should block instead of creating
    44964506 *                      an asynchronous thread.
     4507 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     4508 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     4509 *                This only works in "wait" mode; otherwise saveSettings gets called automatically by the thread that was created,
     4510 *                and this parameter is ignored.
    44974511 *
    44984512 * @note Locks the branch lock for writing. Locks the hard disks from the chain
     
    45014515HRESULT Medium::mergeTo(MergeChain *aChain,
    45024516                        ComObjPtr <Progress> *aProgress,
    4503                         bool aWait)
     4517                        bool aWait,
     4518                        bool *pfNeedsSaveSettings)
    45044519{
    45054520    AssertReturn(aChain != NULL, E_FAIL);
     
    45494564    if (aWait)
    45504565    {
    4551         rc = task->runNow();
     4566        rc = task->runNow(pfNeedsSaveSettings);
    45524567    }
    45534568    else
     
    46404655 * @note Also reused by Medium::Reset().
    46414656 *
    4642  * @note Locks getTreeLock() for reading.
     4657 * @note Caller must hold the media tree write lock!
    46434658 */
    46444659HRESULT Medium::canClose()
    46454660{
    4646     /* we access children */
    4647     AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     4661    Assert(m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    46484662
    46494663    if (getChildren().size() != 0)
     
    46564670
    46574671/**
     4672 * Calls either VirtualBox::unregisterImage or VirtualBox::unregisterHardDisk depending
     4673 * on the device type of this medium.
     4674 *
     4675 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     4676 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     4677 *
    46584678 * @note Called from within this object's AutoMayUninitSpan (or AutoCaller) and
    46594679 *       from under mVirtualBox write lock.
    46604680 *
    4661  * @note Locks getTreeLock() for writing.
    4662  */
    4663 HRESULT Medium::unregisterWithVirtualBox()
     4681 * @note Caller must have locked the media tree lock for writing!
     4682 */
     4683HRESULT Medium::unregisterWithVirtualBox(bool *pfNeedsSaveSettings)
    46644684{
    46654685    /* Note that we need to de-associate ourselves from the parent to let
     
    46674687
    46684688    /* we modify mParent and access children */
    4669     AutoWriteLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     4689    Assert(m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    46704690
    46714691    Medium *pParentBackup = m->pParent;
    4672 
    46734692    AssertReturn(getChildren().size() == 0, E_FAIL);
    4674 
    46754693    if (m->pParent)
    46764694        deparent();
     
    46804698    {
    46814699        case DeviceType_DVD:
    4682             rc = m->pVirtualBox->unregisterImage(this, DeviceType_DVD);
    4683             break;
     4700            rc = m->pVirtualBox->unregisterImage(this, DeviceType_DVD, pfNeedsSaveSettings);
     4701        break;
     4702
    46844703        case DeviceType_Floppy:
    4685             rc = m->pVirtualBox->unregisterImage(this, DeviceType_Floppy);
    4686             break;
     4704            rc = m->pVirtualBox->unregisterImage(this, DeviceType_Floppy, pfNeedsSaveSettings);
     4705        break;
     4706
    46874707        case DeviceType_HardDisk:
    4688             rc = m->pVirtualBox->unregisterHardDisk(this);
    4689             break;
     4708            rc = m->pVirtualBox->unregisterHardDisk(this, pfNeedsSaveSettings);
     4709        break;
     4710
    46904711        default:
    4691             break;
     4712        break;
    46924713    }
    46934714
     
    48674888/**
    48684889 * Implementation code called from Medium::taskThread for the "create base" task.
     4890 *
     4891 * This only gets started from Medium::CreateBaseStorage() and always runs
     4892 * asynchronously. As a result, we always save the VirtualBox.xml file when we're
     4893 * done here.
     4894 *
    48694895 * @param task
    48704896 * @param pvdOperationIfaces
     
    48774903    PVDINTERFACE vdOperationIfaces = (PVDINTERFACE)pvdOperationIfaces;
    48784904
    4879     /* The lock is also used as a signal from the task initiator (which
    4880     * releases it only after RTThreadCreate()) that we can start the job */
    4881     AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
    4882 
    48834905    /* these parameters we need after creation */
    48844906    uint64_t size = 0, logicalSize = 0;
    4885 
    4886     /* The object may request a specific UUID (through a special form of
    4887     * the setLocation() argument). Otherwise we have to generate it */
    4888     Guid id = m->id;
    4889     bool generateUuid = id.isEmpty();
    4890     if (generateUuid)
    4891     {
    4892         id.create();
    4893         /* VirtualBox::registerHardDisk() will need UUID */
    4894         unconst(m->id) = id;
    4895     }
     4907    bool fGenerateUuid = false;
    48964908
    48974909    try
    48984910    {
     4911        /* The lock is also used as a signal from the task initiator (which
     4912        * releases it only after RTThreadCreate()) that we can start the job */
     4913        AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
     4914
     4915        /* The object may request a specific UUID (through a special form of
     4916        * the setLocation() argument). Otherwise we have to generate it */
     4917        Guid id = m->id;
     4918        fGenerateUuid = id.isEmpty();
     4919        if (fGenerateUuid)
     4920        {
     4921            id.create();
     4922            /* VirtualBox::registerHardDisk() will need UUID */
     4923            unconst(m->id) = id;
     4924        }
     4925
    48994926        PVBOXHDD hdd;
    49004927        int vrc = VDCreate(m->vdDiskIfaces, &hdd);
     
    49484975    {
    49494976        /* register with mVirtualBox as the last step and move to
    4950         * Created state only on success (leaving an orphan file is
    4951         * better than breaking media registry consistency) */
    4952         rc = m->pVirtualBox->registerHardDisk(this);
    4953     }
    4954 
    4955     thisLock.maybeEnter();
     4977         * Created state only on success (leaving an orphan file is
     4978         * better than breaking media registry consistency) */
     4979        bool fNeedsSaveSettings = false;
     4980        AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     4981        rc = m->pVirtualBox->registerHardDisk(this, &fNeedsSaveSettings);
     4982        treeLock.release();
     4983
     4984        if (fNeedsSaveSettings)
     4985        {
     4986            AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     4987            m->pVirtualBox->saveSettings();
     4988        }
     4989    }
     4990
     4991    // reenter the lock before changing state
     4992    AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
    49564993
    49574994    if (SUCCEEDED(rc))
     
    49685005
    49695006        /* reset UUID to prevent it from being reused next time */
    4970         if (generateUuid)
     5007        if (fGenerateUuid)
    49715008            unconst(m->id).clear();
    49725009    }
     
    49775014/**
    49785015 * Implementation code called from Medium::taskThread for the "create diff" task.
     5016 *
     5017 * This task always gets started from Medium::createDiffStorage() and can run
     5018 * synchronously or asynchrously depending on the "wait" parameter passed to that
     5019 * function. If we run synchronously, the caller expects the bool *pfNeedsSaveSettings
     5020 * to be set before returning; otherwise (in asynchronous mode), we save the settings
     5021 * ourselves.
     5022 *
    49795023 * @param task
    49805024 * @param pvdOperationIfaces
     
    49875031    PVDINTERFACE vdOperationIfaces = (PVDINTERFACE)pvdOperationIfaces;
    49885032
     5033    bool fNeedsSaveSettings = false;
     5034
    49895035    ComObjPtr<Medium> &pTarget = task.d.target;
    49905036
    4991     /* Lock both in {parent,child} order. The lock is also used as a
    4992      * signal from the task initiator (which releases it only after
    4993      * RTThreadCreate()) that we can start the job*/
    4994     AutoMultiWriteLock2 thisLock(this, pTarget COMMA_LOCKVAL_SRC_POS);
    4995 
    49965037    uint64_t size = 0, logicalSize = 0;
    4997 
    4998     /* The object may request a specific UUID (through a special form of
    4999      * the setLocation() argument). Otherwise we have to generate it */
    5000     Guid targetId = pTarget->m->id;
    5001     bool generateUuid = targetId.isEmpty();
    5002     if (generateUuid)
    5003     {
    5004         targetId.create();
    5005         /* VirtualBox::registerHardDisk() will need UUID */
    5006         unconst(pTarget->m->id) = targetId;
    5007     }
     5038    bool fGenerateUuid = false;
    50085039
    50095040    try
    50105041    {
     5042        /* Lock both in {parent,child} order. The lock is also used as a
     5043        * signal from the task initiator (which releases it only after
     5044        * RTThreadCreate()) that we can start the job*/
     5045        AutoMultiWriteLock2 mediaLock(this, pTarget COMMA_LOCKVAL_SRC_POS);
     5046
     5047        /* The object may request a specific UUID (through a special form of
     5048        * the setLocation() argument). Otherwise we have to generate it */
     5049        Guid targetId = pTarget->m->id;
     5050        fGenerateUuid = targetId.isEmpty();
     5051        if (fGenerateUuid)
     5052        {
     5053            targetId.create();
     5054            /* VirtualBox::registerHardDisk() will need UUID */
     5055            unconst(pTarget->m->id) = targetId;
     5056        }
     5057
    50115058        PVBOXHDD hdd;
    50125059        int vrc = VDCreate(m->vdDiskIfaces, &hdd);
     
    50275074                || m->state == MediumState_LockedWrite);
    50285075
    5029         /* unlock before the potentially lengthy operation */
    5030         thisLock.leave();
     5076        /* the two media are now protected by their non-default states;
     5077           unlock the media before the potentially lengthy operation */
     5078        mediaLock.leave();
    50315079
    50325080        try
     
    50745122    if (SUCCEEDED(rc))
    50755123    {
    5076         /* we set mParent & children() (note that thatLock is released
    5077          * here), but lock VirtualBox first to follow the rule */
    5078         AutoWriteLock alock1(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
    5079         AutoWriteLock alock2(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     5124        AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    50805125
    50815126        Assert(pTarget->m->pParent.isNull());
     
    50955140         * Created state only on success (leaving an orphan file is
    50965141         * better than breaking media registry consistency) */
    5097         rc = m->pVirtualBox->registerHardDisk(pTarget);
     5142        rc = m->pVirtualBox->registerHardDisk(pTarget, &fNeedsSaveSettings);
    50985143
    50995144        if (FAILED(rc))
     
    51025147    }
    51035148
    5104     thisLock.maybeEnter();
     5149    AutoMultiWriteLock2 mediaLock(this, pTarget COMMA_LOCKVAL_SRC_POS);
    51055150
    51065151    if (SUCCEEDED(rc))
     
    51195164
    51205165        /* reset UUID to prevent it from being reused next time */
    5121         if (generateUuid)
     5166        if (fGenerateUuid)
    51225167            unconst(pTarget->m->id).clear();
    51235168    }
     
    51325177            AssertComRC(rc2);
    51335178        }
    5134     }
     5179
     5180        if (fNeedsSaveSettings)
     5181        {
     5182            mediaLock.leave();
     5183            AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     5184            m->pVirtualBox->saveSettings();
     5185        }
     5186    }
     5187    else
     5188        // synchronous mode: report save settings result to caller
     5189        if (task.m_pfNeedsSaveSettings)
     5190            *task.m_pfNeedsSaveSettings = fNeedsSaveSettings;
    51355191
    51365192    /* deregister the task registered in createDiffStorage() */
     
    51465202/**
    51475203 * Implementation code called from Medium::taskThread for the "merge" task.
     5204 *
     5205 * This task always gets started from Medium::mergeTo() and can run
     5206 * synchronously or asynchrously depending on the "wait" parameter passed to that
     5207 * function. If we run synchronously, the caller expects the bool *pfNeedsSaveSettings
     5208 * to be set before returning; otherwise (in asynchronous mode), we save the settings
     5209 * ourselves.
     5210 *
    51485211 * @param task
    51495212 * @param pvdOperationIfaces
     
    51825245
    51835246            for (MergeChain::const_iterator it = chain->begin();
    5184                     it != chain->end(); ++ it)
     5247                 it != chain->end();
     5248                 ++it)
    51855249            {
    51865250                /* complex sanity (sane complexity) */
     
    52015265                /* open the first image with VDOPEN_FLAGS_INFO because
    52025266                 * it's not necessarily the base one */
    5203                 vrc = VDOpen(hdd, (*it)->m->strFormat.c_str(),
    5204                                 (*it)->m->strLocationFull.c_str(),
    5205                                 it == chain->begin() ?
    5206                                    VD_OPEN_FLAGS_INFO : 0,
    5207                                 (*it)->m->vdDiskIfaces);
     5267                vrc = VDOpen(hdd,
     5268                             (*it)->m->strFormat.c_str(),
     5269                             (*it)->m->strLocationFull.c_str(),
     5270                             it == chain->begin() ? VD_OPEN_FLAGS_INFO : 0,
     5271                             (*it)->m->vdDiskIfaces);
    52085272                if (RT_FAILURE(vrc))
    52095273                    throw vrc;
     
    52385302                {
    52395303                    for (MediaList::const_iterator it = chain->children().begin();
    5240                             it != chain->children().end();
    5241                             ++it)
     5304                         it != chain->children().end();
     5305                         ++it)
    52425306                    {
    52435307                        /* VD_OPEN_FLAGS_INFO since UUID is wrong yet */
    5244                         vrc = VDOpen(hdd, (*it)->m->strFormat.c_str(),
    5245                                         (*it)->m->strLocationFull.c_str(),
    5246                                         VD_OPEN_FLAGS_INFO,
    5247                                         (*it)->m->vdDiskIfaces);
     5308                        vrc = VDOpen(hdd,
     5309                                     (*it)->m->strFormat.c_str(),
     5310                                     (*it)->m->strLocationFull.c_str(),
     5311                                     VD_OPEN_FLAGS_INFO,
     5312                                     (*it)->m->vdDiskIfaces);
    52485313                        if (RT_FAILURE(vrc))
    52495314                            throw vrc;
    52505315
    52515316                        vrc = VDSetParentUuid(hdd, 1,
    5252                                                 chain->target()->m->id);
     5317                                              chain->target()->m->id);
    52535318                        if (RT_FAILURE(vrc))
    52545319                            throw vrc;
     
    52775342    HRESULT rc2;
    52785343
    5279     bool saveSettingsFailed = false;
    5280 
    52815344    if (SUCCEEDED(rc))
    52825345    {
     
    52845347         * VDMerge; reparent the last one and uninitialize deleted */
    52855348
    5286         /* we set mParent & children() (note that thatLock is released
    5287          * here), but lock VirtualBox first to follow the rule */
    5288         AutoWriteLock alock1(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
    5289         AutoWriteLock alock2(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     5349        AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    52905350
    52915351        Medium *pSource = chain->source();
     
    52965356            /* first, unregister the target since it may become a base
    52975357             * hard disk which needs re-registration */
    5298             rc2 = pTarget->m->pVirtualBox->unregisterHardDisk(pTarget, false /* aSaveSettings */);
     5358            rc2 = m->pVirtualBox->unregisterHardDisk(pTarget, NULL /*&fNeedsSaveSettings*/);
    52995359            AssertComRC(rc2);
    53005360
     
    53105370
    53115371            /* then, register again */
    5312             rc2 = pTarget->m->pVirtualBox->registerHardDisk(pTarget, false /* aSaveSettings */);
     5372            rc2 = m->pVirtualBox->registerHardDisk(pTarget, NULL /*&fNeedsSaveSettings*/);
    53135373            AssertComRC(rc2);
    53145374        }
     
    53315391
    53325392                for (MediaList::const_iterator it = children.begin();
    5333                         it != children.end();
    5334                         ++it)
     5393                     it != children.end();
     5394                     ++it)
    53355395                {
    53365396                    AutoWriteLock childLock(*it COMMA_LOCKVAL_SRC_POS);
     
    53445404        }
    53455405
    5346         /* try to save the hard disk registry */
    5347         rc = m->pVirtualBox->saveSettings();
    5348 
    5349         if (SUCCEEDED(rc))
    5350         {
    5351             /* unregister and uninitialize all hard disks in the chain
    5352              * but the target */
    5353 
    5354             for (MergeChain::iterator it = chain->begin();
    5355                     it != chain->end();)
     5406        /* unregister and uninitialize all hard disks in the chain but the target */
     5407        for (MergeChain::iterator it = chain->begin();
     5408             it != chain->end();
     5409            )
     5410        {
     5411            if (*it == chain->target())
    53565412            {
    5357                 if (*it == chain->target())
    5358                 {
    5359                     ++ it;
    5360                     continue;
    5361                 }
    5362 
    5363                 rc2 = (*it)->m->pVirtualBox->
    5364                     unregisterHardDisk(*it, false /* aSaveSettings */);
    5365                 AssertComRC(rc2);
    5366 
    5367                 /* now, uninitialize the deleted hard disk (note that
    5368                  * due to the Deleting state, uninit() will not touch
    5369                  * the parent-child relationship so we need to
    5370                  * uninitialize each disk individually) */
    5371 
    5372                 /* note that the operation initiator hard disk (which is
    5373                  * normally also the source hard disk) is a special case
    5374                  * -- there is one more caller added by Task to it which
    5375                  * we must release. Also, if we are in sync mode, the
    5376                  * caller may still hold an AutoCaller instance for it
    5377                  * and therefore we cannot uninit() it (it's therefore
    5378                  * the caller's responsibility) */
    5379                 if (*it == this)
    5380                     task.m_autoCaller.release();
    5381 
    5382                 /* release the caller added by MergeChain before
    5383                  * uninit() */
    5384                 (*it)->releaseCaller();
    5385 
    5386                 if (fIsAsync || *it != this)
    5387                     (*it)->uninit();
    5388 
    5389                 /* delete (to prevent uninitialization in MergeChain
    5390                  * dtor) and advance to the next item */
    5391                 it = chain->erase(it);
     5413                ++it;
     5414                continue;
    53925415            }
    53935416
    5394             /* Note that states of all other hard disks (target, parent,
    5395              * children) will be restored by the MergeChain dtor */
    5396         }
    5397         else
    5398         {
    5399             /* too bad if we fail, but we'll need to rollback everything
    5400              * we did above to at least keep the HD tree in sync with
    5401              * the current registry on disk */
    5402 
    5403             saveSettingsFailed = true;
    5404 
    5405             /// @todo NEWMEDIA implement a proper undo
    5406 
    5407             AssertFailed();
    5408         }
    5409     }
     5417            rc2 = (*it)->m->pVirtualBox->unregisterHardDisk(*it, NULL /*pfNeedsSaveSettings*/);
     5418            AssertComRC(rc2);
     5419
     5420            /* now, uninitialize the deleted hard disk (note that
     5421             * due to the Deleting state, uninit() will not touch
     5422             * the parent-child relationship so we need to
     5423             * uninitialize each disk individually) */
     5424
     5425            /* note that the operation initiator hard disk (which is
     5426             * normally also the source hard disk) is a special case
     5427             * -- there is one more caller added by Task to it which
     5428             * we must release. Also, if we are in sync mode, the
     5429             * caller may still hold an AutoCaller instance for it
     5430             * and therefore we cannot uninit() it (it's therefore
     5431             * the caller's responsibility) */
     5432            if (*it == this)
     5433                task.m_autoCaller.release();
     5434
     5435            /* release the caller added by MergeChain before uninit() */
     5436            (*it)->releaseCaller();
     5437
     5438            if (fIsAsync || *it != this)
     5439                (*it)->uninit();
     5440
     5441            /* delete (to prevent uninitialization in MergeChain
     5442                * dtor) and advance to the next item */
     5443            it = chain->erase(it);
     5444        }
     5445    }
     5446
     5447    if (fIsAsync)
     5448    {
     5449        // in asynchronous mode, save settings now
     5450        AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     5451        m->pVirtualBox->saveSettings();
     5452    }
     5453    else
     5454        // synchronous mode: report save settings result to caller
     5455        if (task.m_pfNeedsSaveSettings)
     5456            *task.m_pfNeedsSaveSettings = true;
    54105457
    54115458    if (FAILED(rc))
     
    54245471        if (!fIsAsync)
    54255472            task.d.chain.release();
    5426 
    5427         NOREF(saveSettingsFailed);
    54285473    }
    54295474
     
    54335478/**
    54345479 * Implementation code called from Medium::taskThread for the "clone" task.
     5480 * This only gets started from Medium::CloneTo() and always runs asynchronously.
     5481 * As a result, we always save the VirtualBox.xml file when we're done here.
     5482 *
    54355483 * @param task
    54365484 * @param pvdOperationIfaces
     
    54465494    ComObjPtr<Medium> &pParent = task.d.parentDisk;
    54475495
    5448     /* Lock all in {parent,child} order. The lock is also used as a
    5449      * signal from the task initiator (which releases it only after
    5450      * RTThreadCreate()) that we can start the job. */
    5451     AutoMultiWriteLock3 thisLock(this, pTarget, pParent COMMA_LOCKVAL_SRC_POS);
    5452 
    5453     ImageChain *srcChain = task.d.source.get();
    5454     ImageChain *parentChain = task.d.parent.get();
     5496    bool fCreatingTarget;
    54555497
    54565498    uint64_t size = 0, logicalSize = 0;
    5457 
    5458     /* The object may request a specific UUID (through a special form of
    5459      * the setLocation() argument). Otherwise we have to generate it */
    5460     Guid targetId = pTarget->m->id;
    5461     bool generateUuid = targetId.isEmpty();
    5462     if (generateUuid)
    5463     {
    5464         targetId.create();
    5465         /* VirtualBox::registerHardDisk() will need UUID */
    5466         unconst(pTarget->m->id) = targetId;
    5467     }
     5499    bool fGenerateUuid = false;
    54685500
    54695501    try
    54705502    {
     5503        /* Lock all in {parent,child} order. The lock is also used as a
     5504         * signal from the task initiator (which releases it only after
     5505         * RTThreadCreate()) that we can start the job. */
     5506        AutoMultiWriteLock3 thisLock(this, pTarget, pParent COMMA_LOCKVAL_SRC_POS);
     5507
     5508        fCreatingTarget = pTarget->m->state == MediumState_Creating;
     5509
     5510        ImageChain *srcChain = task.d.source.get();
     5511        ImageChain *parentChain = task.d.parent.get();
     5512
     5513        /* The object may request a specific UUID (through a special form of
     5514         * the setLocation() argument). Otherwise we have to generate it */
     5515        Guid targetId = pTarget->m->id;
     5516        fGenerateUuid = targetId.isEmpty();
     5517        if (fGenerateUuid)
     5518        {
     5519            targetId.create();
     5520            /* VirtualBox::registerHardDisk() will need UUID */
     5521            unconst(pTarget->m->id) = targetId;
     5522        }
     5523
    54715524        PVBOXHDD hdd;
    54725525        int vrc = VDCreate(m->vdDiskIfaces, &hdd);
     
    55465599                             targetHdd,
    55475600                             targetFormat.c_str(),
    5548                              pTarget->m->state == MediumState_Creating ? targetLocation.raw() : (char *)NULL,
     5601                             (fCreatingTarget) ? targetLocation.raw() : (char *)NULL,
    55495602                             false,
    55505603                             0,
     
    55735626
    55745627    /* Only do the parent changes for newly created images. */
    5575     if (pTarget->m->state == MediumState_Creating)
    5576     {
    5577         if (SUCCEEDED(rc))
    5578         {
    5579             /* we set mParent & children() (note that thatLock is released
    5580                 * here), but lock VirtualBox first to follow the rule */
    5581             AutoWriteLock alock1(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
    5582             AutoWriteLock alock2(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    5583 
    5584             Assert(pTarget->m->pParent.isNull());
    5585 
    5586             if (pParent)
    5587             {
    5588                 /* associate the clone with the parent and deassociate
    5589                     * from VirtualBox */
    5590                 pTarget->m->pParent = pParent;
    5591                 pParent->m->llChildren.push_back(pTarget);
    5592 
    5593                 /* register with mVirtualBox as the last step and move to
    5594                     * Created state only on success (leaving an orphan file is
    5595                     * better than breaking media registry consistency) */
    5596                 rc = pParent->m->pVirtualBox->registerHardDisk(pTarget);
    5597 
    5598                 if (FAILED(rc))
    5599                     /* break parent association on failure to register */
    5600                     pTarget->deparent();     // removes target from parent
    5601             }
    5602             else
    5603             {
    5604                 /* just register  */
    5605                 rc = m->pVirtualBox->registerHardDisk(pTarget);
    5606             }
    5607         }
    5608     }
    5609 
    5610     thisLock.maybeEnter();
    5611 
    5612     if (pTarget->m->state == MediumState_Creating)
    5613     {
     5628    if (SUCCEEDED(rc) && fCreatingTarget)
     5629    {
     5630        /* we set mParent & children() */
     5631        AutoWriteLock alock2(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     5632
     5633        Assert(pTarget->m->pParent.isNull());
     5634
     5635        if (pParent)
     5636        {
     5637            /* associate the clone with the parent and deassociate
     5638             * from VirtualBox */
     5639            pTarget->m->pParent = pParent;
     5640            pParent->m->llChildren.push_back(pTarget);
     5641
     5642            /* register with mVirtualBox as the last step and move to
     5643             * Created state only on success (leaving an orphan file is
     5644             * better than breaking media registry consistency) */
     5645            rc = pParent->m->pVirtualBox->registerHardDisk(pTarget, NULL /* pfNeedsSaveSettings */);
     5646
     5647            if (FAILED(rc))
     5648                /* break parent association on failure to register */
     5649                pTarget->deparent();     // removes target from parent
     5650        }
     5651        else
     5652        {
     5653            /* just register  */
     5654            rc = m->pVirtualBox->registerHardDisk(pTarget, NULL /* pfNeedsSaveSettings */);
     5655        }
     5656    }
     5657
     5658    if (fCreatingTarget)
     5659    {
     5660        AutoWriteLock mLock(pTarget COMMA_LOCKVAL_SRC_POS);
     5661
    56145662        if (SUCCEEDED(rc))
    56155663        {
     
    56255673
    56265674            /* reset UUID to prevent it from being reused next time */
    5627             if (generateUuid)
     5675            if (fGenerateUuid)
    56285676                unconst(pTarget->m->id).clear();
    56295677        }
     5678    }
     5679
     5680    // now, at the end of this task (always asynchronous), save the settings
     5681    {
     5682        AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     5683        m->pVirtualBox->saveSettings();
    56305684    }
    56315685
     
    56435697/**
    56445698 * Implementation code called from Medium::taskThread for the "delete" task.
     5699 *
     5700 * This task always gets started from Medium::deleteStorage() and can run
     5701 * synchronously or asynchrously depending on the "wait" parameter passed to that
     5702 * function.
     5703 *
    56455704 * @return
    56465705 */
     
    56495708    HRESULT rc = S_OK;
    56505709
    5651     /* The lock is also used as a signal from the task initiator (which
    5652      * releases it only after RTThreadCreate()) that we can start the job */
    5653     AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
    5654 
    56555710    try
    56565711    {
     5712        /* The lock is also used as a signal from the task initiator (which
     5713         * releases it only after RTThreadCreate()) that we can start the job */
     5714        AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
     5715
    56575716        PVBOXHDD hdd;
    56585717        int vrc = VDCreate(m->vdDiskIfaces, &hdd);
     
    56645723        /* unlock before the potentially lengthy operation */
    56655724        Assert(m->state == MediumState_Deleting);
    5666         thisLock.leave();
     5725        thisLock.release();
    56675726
    56685727        try
     
    56885747    catch (HRESULT aRC) { rc = aRC; }
    56895748
    5690     thisLock.maybeEnter();
     5749    AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
    56915750
    56925751    /* go to the NotCreated state even on failure since the storage
    5693         * may have been already partially deleted and cannot be used any
    5694         * more. One will be able to manually re-open the storage if really
    5695         * needed to re-register it. */
     5752     * may have been already partially deleted and cannot be used any
     5753     * more. One will be able to manually re-open the storage if really
     5754     * needed to re-register it. */
    56965755    m->state = MediumState_NotCreated;
    56975756
     
    57045763/**
    57055764 * Implementation code called from Medium::taskThread for the "reset" task.
     5765 *
     5766 * This always gets started asynchronously from Medium::Reset().
     5767 *
    57065768 * @param task
    57075769 * @param pvdOperationIfaces
     
    57145776    PVDINTERFACE vdOperationIfaces = (PVDINTERFACE)pvdOperationIfaces;
    57155777
    5716     /* The lock is also used as a signal from the task initiator (which
    5717      * releases it only after RTThreadCreate()) that we can start the job */
    5718     AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
    5719 
    5720     /// @todo Below we use a pair of delete/create operations to reset
    5721     /// the diff contents but the most efficient way will of course be
    5722     /// to add a VDResetDiff() API call
    5723 
    57245778    uint64_t size = 0, logicalSize = 0;
    57255779
    57265780    try
    57275781    {
     5782        /* The lock is also used as a signal from the task initiator (which
     5783         * releases it only after RTThreadCreate()) that we can start the job */
     5784        AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
     5785
     5786        /// @todo Below we use a pair of delete/create operations to reset
     5787        /// the diff contents but the most efficient way will of course be
     5788        /// to add a VDResetDiff() API call
     5789
    57285790        PVBOXHDD hdd;
    57295791        int vrc = VDCreate(m->vdDiskIfaces, &hdd);
     
    57425804
    57435805        /* unlock before the potentially lengthy operation */
    5744         thisLock.leave();
     5806        thisLock.release();
    57455807
    57465808        try
    57475809        {
    57485810            /* first, delete the storage unit */
    5749             vrc = VDOpen(hdd, format.c_str(), location.c_str(),
    5750                             VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO,
    5751                             m->vdDiskIfaces);
     5811            vrc = VDOpen(hdd,
     5812                         format.c_str(),
     5813                         location.c_str(),
     5814                         VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO,
     5815                         m->vdDiskIfaces);
    57525816            if (RT_SUCCESS(vrc))
    57535817                vrc = VDClose(hdd, true /* fDelete */);
    57545818
    57555819            if (RT_FAILURE(vrc))
    5756             {
    57575820                throw setError(E_FAIL,
    5758                                 tr("Could not delete the hard disk storage unit '%s'%s"),
    5759                                 location.raw(), vdError(vrc).raw());
    5760             }
     5821                               tr("Could not delete the hard disk storage unit '%s'%s"),
     5822                               location.raw(), vdError(vrc).raw());
    57615823
    57625824            /* next, create it again */
    5763             vrc = VDOpen(hdd, parentFormat.c_str(), parentLocation.c_str(),
    5764                             VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO,
    5765                             m->vdDiskIfaces);
     5825            vrc = VDOpen(hdd,
     5826                         parentFormat.c_str(),
     5827                         parentLocation.c_str(),
     5828                         VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO,
     5829                         m->vdDiskIfaces);
    57665830            if (RT_FAILURE(vrc))
    5767             {
    57685831                throw setError(E_FAIL,
    57695832                                tr("Could not open the hard disk storage unit '%s'%s"),
    57705833                                parentLocation.raw(), vdError(vrc).raw());
    5771             }
    5772 
    5773             vrc = VDCreateDiff(hdd, format.c_str(), location.c_str(),
    5774                                 /// @todo use the same image variant as before
    5775                                 VD_IMAGE_FLAGS_NONE,
    5776                                 NULL, id.raw(),
    5777                                 parentId.raw(),
    5778                                 VD_OPEN_FLAGS_NORMAL,
    5779                                 m->vdDiskIfaces,
    5780                                 vdOperationIfaces);
     5834
     5835            vrc = VDCreateDiff(hdd,
     5836                               format.c_str(),
     5837                               location.c_str(),
     5838                               /// @todo use the same image variant as before
     5839                               VD_IMAGE_FLAGS_NONE,
     5840                               NULL,
     5841                               id.raw(),
     5842                               parentId.raw(),
     5843                               VD_OPEN_FLAGS_NORMAL,
     5844                               m->vdDiskIfaces,
     5845                               vdOperationIfaces);
    57815846            if (RT_FAILURE(vrc))
    5782             {
    57835847                throw setError(E_FAIL,
    57845848                                tr("Could not create the differencing hard disk storage unit '%s'%s"),
    57855849                                location.raw(), vdError(vrc).raw());
    5786             }
    57875850
    57885851            size = VDGetFileSize(hdd, 1);
     
    57955858    catch (HRESULT aRC) { rc = aRC; }
    57965859
    5797     thisLock.enter();
     5860    AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
    57985861
    57995862    m->size = size;
  • trunk/src/VBox/Main/SnapshotImpl.cpp

    r25860 r25903  
    12261226    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    12271227
    1228     /* saveSettings() needs mParent lock */
    1229     AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
     1228    // if this becomes true, we need to call VirtualBox::saveSettings() in the end
     1229    bool fNeedsSaveSettings = false;
     1230
     1231    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    12301232
    12311233    AssertReturn(    !Global::IsOnlineOrTransient(mData->mMachineState)
     
    12411243        /* save all current settings to ensure current changes are committed and
    12421244         * hard disks are fixed up */
     1245        alock.release();
     1246
     1247        AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
    12431248        HRESULT rc = saveSettings();
    12441249        if (FAILED(rc)) return rc;
     1250
     1251        alock.acquire();
    12451252    }
    12461253
     
    13051312                                 aConsoleProgress,
    13061313                                 1,            // operation weight; must be the same as in Console::TakeSnapshot()
    1307                                  !!fTakingSnapshotOnline);
     1314                                 !!fTakingSnapshotOnline,
     1315                                 &fNeedsSaveSettings);
    13081316        if (FAILED(rc))
    13091317            throw rc;
     
    13201328                                               1);        // weight
    13211329
    1322             /* Leave the lock before a lengthy operation (mMachineState is
    1323             * MachineState_Saving here) */
    1324             alock.leave();
     1330            /* Leave the lock before a lengthy operation (machine is protected
     1331             * by "Saving" machine state now) */
     1332            alock.release();
    13251333
    13261334            /* copy the state file */
     
    13301338                                   progressCallback,
    13311339                                   aConsoleProgress);
    1332             alock.enter();
     1340            alock.acquire();
    13331341
    13341342            if (RT_FAILURE(vrc))
    1335             {
    13361343                /** @todo r=bird: Delete stateTo when appropriate. */
    13371344                throw setError(E_FAIL,
     
    13401347                               stateTo.raw(),
    13411348                               vrc);
    1342             }
    13431349        }
    13441350    }
     
    13471353        LogThisFunc(("Caught %Rhrc [%s]\n", hrc, Global::stringifyMachineState(mData->mMachineState) ));
    13481354        if (    mSnapshotData.mLastState != mData->mMachineState
    1349             &&  (  mSnapshotData.mLastState == MachineState_Running
    1350                  ? mData->mMachineState == MachineState_LiveSnapshotting
    1351                  : mData->mMachineState == MachineState_Saving)
     1355             && (   mSnapshotData.mLastState == MachineState_Running
     1356                  ? mData->mMachineState == MachineState_LiveSnapshotting
     1357                  : mData->mMachineState == MachineState_Saving)
    13521358           )
    13531359            setMachineState(mSnapshotData.mLastState);
     
    13591365
    13601366        rc = hrc;
     1367
     1368        // @todo r=dj what with the implicit diff that we created above? this is never cleaned up
    13611369    }
    13621370
     
    13661374        *aStateFilePath = NULL;
    13671375
     1376    // @todo r=dj normally we would need to save the settings if fNeedsSaveSettings was set to true,
     1377    // but since we have no error handling that cleans up the diff image that might have gotten created,
     1378    // there's no point in saving the disk registry at this point either... this needs fixing.
     1379
    13681380    LogFlowThisFunc(("LEAVE - %Rhrc [%s]\n", rc, Global::stringifyMachineState(mData->mMachineState) ));
    13691381    return rc;
     
    13791391 * BeginTakingSnapshot() call, to clean up the server side.
    13801392 *
    1381  * @note Locks this object for writing.
     1393 * @note Locks VirtualBox and this object for writing.
    13821394 *
    13831395 * @param aSuccess Whether Console was successful with the client-side snapshot things.
     
    13911403    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
    13921404
    1393     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1405    AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
    13941406
    13951407    AssertReturn(   !aSuccess
    13961408                 || (    (    mData->mMachineState == MachineState_Saving
    1397                           || mData->mMachineState == MachineState_LiveSnapshotting)
    1398                      && mSnapshotData.mLastState != MachineState_Null
    1399                      && !mSnapshotData.mSnapshot.isNull()
     1409                           || mData->mMachineState == MachineState_LiveSnapshotting)
     1410                      && mSnapshotData.mLastState != MachineState_Null
     1411                      && !mSnapshotData.mSnapshot.isNull()
    14001412                    )
    14011413                 , E_FAIL);
     
    14071419     * all to avoid races.
    14081420     */
    1409     if (   mData->mMachineState != mSnapshotData.mLastState
    1410         && mSnapshotData.mLastState != MachineState_Running)
     1421    if (    mData->mMachineState != mSnapshotData.mLastState
     1422         && mSnapshotData.mLastState != MachineState_Running
     1423       )
    14111424        setMachineState(mSnapshotData.mLastState);
    1412 
    1413     return endTakingSnapshot(aSuccess);
    1414 }
    1415 
    1416 /**
    1417  * Internal helper method to finalize taking a snapshot. Gets called from
    1418  * SessionMachine::EndTakingSnapshot() to finalize the server-side
    1419  * parts of snapshotting.
    1420  *
    1421  * This also gets called from SessionMachine::uninit() if an untaken
    1422  * snapshot needs cleaning up.
    1423  *
    1424  * Expected to be called after completing *all* the tasks related to
    1425  * taking the snapshot, either successfully or unsuccessfilly.
    1426  *
    1427  * @param aSuccess  TRUE if the snapshot has been taken successfully.
    1428  *
    1429  * @note Locks this objects for writing.
    1430  */
    1431 HRESULT SessionMachine::endTakingSnapshot(BOOL aSuccess)
    1432 {
    1433     LogFlowThisFuncEnter();
    1434 
    1435     AutoCaller autoCaller(this);
    1436     AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
    1437 
    1438     AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
    1439             // saveSettings needs VirtualBox lock
    1440 
    1441     AssertReturn(!mSnapshotData.mSnapshot.isNull(), E_FAIL);
    1442 
    1443     MultiResult rc(S_OK);
    14441425
    14451426    ComObjPtr<Snapshot> pOldFirstSnap = mData->mFirstSnapshot;
     
    14471428
    14481429    bool fOnline = Global::IsOnline(mSnapshotData.mLastState);
     1430
     1431    HRESULT rc = S_OK;
    14491432
    14501433    if (aSuccess)
     
    14681451    {
    14691452        /* associate old hard disks with the snapshot and do locking/unlocking*/
    1470         fixupMedia(true /* aCommit */, fOnline);
     1453        commitMedia(fOnline);
    14711454
    14721455        /* inform callbacks */
     
    14781461        /* delete all differencing hard disks created (this will also attach
    14791462         * their parents back by rolling back mMediaData) */
    1480         fixupMedia(false /* aCommit */);
     1463        rollbackMedia();
    14811464
    14821465        mData->mFirstSnapshot = pOldFirstSnap;      // might have been changed above
     
    14941477    mSnapshotData.mSnapshot.setNull();
    14951478
    1496     LogFlowThisFuncLeave();
    14971479    return rc;
    14981480}
     
    16631645    }
    16641646
    1665     /* saveSettings() needs mParent lock */
    1666     AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
    1667 
    1668     /* @todo We don't need mParent lock so far so unlock() it. Better is to
    1669      * provide an AutoWriteLock argument that lets create a non-locking
    1670      * instance */
    1671     vboxLock.release();
    1672 
    16731647    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    16741648
     
    16821656
    16831657    bool stateRestored = false;
     1658    bool fNeedsSaveSettings = false;
    16841659
    16851660    try
     
    17241699                                     aTask.pProgress,
    17251700                                     1,
    1726                                      false /* aOnline */);
     1701                                     false /* aOnline */,
     1702                                     &fNeedsSaveSettings);
    17271703            if (FAILED(rc)) throw rc;
    17281704
     
    18091785
    18101786        int saveFlags = 0;
    1811 
    1812         /* @todo saveSettings() below needs a VirtualBox write lock and we need
    1813          * to leave this object's lock to do this to follow the {parent-child}
    1814          * locking rule. This is the last chance to do that while we are still
    1815          * in a protective state which allows us to temporarily leave the lock*/
    1816         alock.release();
    1817         vboxLock.acquire();
    1818         alock.acquire();
    18191787
    18201788        /* we have already discarded the current state, so set the execution
     
    18641832        }
    18651833
     1834        alock.leave();
     1835
     1836        AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
     1837        if (fNeedsSaveSettings)
     1838            // VirtualBox.xml needs saving too: must not hold machine lock at this point!
     1839            mParent->saveSettings();
     1840
     1841        alock.enter();
     1842
    18661843        // save all settings, reset the modified flag and commit;
    18671844        rc = saveSettings(SaveS_ResetCurStateModified | saveFlags);
     
    18771854            LogFlowThisFunc(("Deleting old current state in differencing image '%s'\n", pMedium->getName().raw()));
    18781855
    1879             HRESULT rc2 = pMedium->deleteStorageAndWait();
     1856            HRESULT rc2 = pMedium->deleteStorageAndWait(NULL /*aProgress*/, NULL /*pfNeedsSaveSettings*/ );
    18801857            // ignore errors here because we cannot roll back after saveSettings() above
    18811858            if (SUCCEEDED(rc2))
     
    21442121    MediumDiscardRecList toDiscard;
    21452122
    2146     bool settingsChanged = false;
     2123    bool fMachineSettingsChanged = false;       // Machine
     2124    bool fNeedsSaveSettings = false;            // VirtualBox.xml
    21472125
    21482126    try
     
    23062284        /// @todo NEWMEDIA maybe save everything in one operation in place of
    23072285        ///  saveSnapshotSettings() above
    2308         settingsChanged = true;
     2286        fMachineSettingsChanged = true;
    23092287
    23102288        /* third pass: */
     
    23232301            rc = it->hd->discard(aTask.pProgress,
    23242302                                 (ULONG)(it->hd->getSize() / _1M),          // weight
    2325                                  it->chain);
     2303                                 it->chain,
     2304                                 &fNeedsSaveSettings);
    23262305            if (FAILED(rc)) throw rc;
    23272306
     
    23762355        updateMachineStateOnClient();
    23772356
    2378         if (settingsChanged)
     2357        if (fMachineSettingsChanged || fNeedsSaveSettings)
    23792358        {
    23802359            // saveSettings needs VirtualBox write lock in addition to our own
    23812360            // (parent -> child locking order!)
    23822361            AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
    2383             alock.acquire();
    2384 
    2385             saveSettings(SaveS_InformCallbacksAnyway);
     2362
     2363            if (fMachineSettingsChanged)
     2364            {
     2365                alock.acquire();
     2366                saveSettings(SaveS_InformCallbacksAnyway);
     2367            }
     2368
     2369            if (fNeedsSaveSettings)
     2370                mParent->saveSettings();
    23862371        }
    23872372    }
  • trunk/src/VBox/Main/VirtualBoxImpl.cpp

    r25894 r25903  
    520520HRESULT VirtualBox::initMedia()
    521521{
     522    AutoWriteLock treeLock(getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     523
    522524    HRESULT rc = S_OK;
    523525    settings::MediaList::const_iterator it;
     
    536538        if (FAILED(rc)) return rc;
    537539
    538         rc = registerHardDisk(pHardDisk, false /* aSaveRegistry */);
     540        rc = registerHardDisk(pHardDisk, NULL /*pfNeedsSaveSettings*/ );
    539541        if (FAILED(rc)) return rc;
    540542    }
     
    551553        if (FAILED(rc)) return rc;
    552554
    553         rc = registerImage(pImage, DeviceType_DVD, false /* aSaveRegistry */);
     555        rc = registerImage(pImage, DeviceType_DVD, NULL /*pfNeedsSaveSettings*/ );
    554556        if (FAILED(rc)) return rc;
    555557    }
     
    566568        if (FAILED(rc)) return rc;
    567569
    568         rc = registerImage(pImage, DeviceType_Floppy, false /* aSaveRegistry */);
     570        rc = registerImage(pImage, DeviceType_Floppy, NULL /*pfNeedsSaveSettings*/ );
    569571        if (FAILED(rc)) return rc;
    570572    }
     
    13191321    HRESULT rc = E_FAIL;
    13201322
     1323    bool fNeedsSaveSettings = false;
     1324
    13211325    ComObjPtr<Medium> hardDisk;
    13221326    hardDisk.createObject();
    1323     rc = hardDisk->init(this, format.raw(), aLocation);
     1327    rc = hardDisk->init(this, format.raw(), aLocation, &fNeedsSaveSettings);
    13241328
    13251329    if (SUCCEEDED(rc))
    13261330        hardDisk.queryInterfaceTo(aHardDisk);
     1331
     1332    if (fNeedsSaveSettings)
     1333    {
     1334        AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS);
     1335        saveSettings();
     1336    }
    13271337
    13281338    return rc;
     
    13621372                        (accessMode == AccessMode_ReadWrite) ? Medium::OpenReadWrite : Medium::OpenReadOnly,
    13631373                        DeviceType_HardDisk,
    1364                         aSetImageId, imageId,
    1365                         aSetParentId, parentId);
     1374                        aSetImageId,
     1375                        imageId,
     1376                        aSetParentId,
     1377                        parentId);
    13661378
    13671379    if (SUCCEEDED(rc))
    13681380    {
    1369         rc = registerHardDisk (hardDisk);
     1381        bool fNeedsSaveSettings = false;
     1382        rc = registerHardDisk(hardDisk, &fNeedsSaveSettings);
    13701383
    13711384        /* Note that it's important to call uninit() on failure to register
     
    13771390        else
    13781391            hardDisk->uninit();
     1392
     1393        if (fNeedsSaveSettings)
     1394        {
     1395            AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS);
     1396            saveSettings();
     1397        }
    13791398    }
    13801399
     
    14401459    if (SUCCEEDED(rc))
    14411460    {
    1442         rc = registerImage(image, DeviceType_DVD);
     1461        bool fNeedsSaveSettings = false;
     1462        rc = registerImage(image, DeviceType_DVD, &fNeedsSaveSettings);
    14431463
    14441464        if (SUCCEEDED(rc))
    14451465            image.queryInterfaceTo(aDVDImage);
     1466
     1467        if (fNeedsSaveSettings)
     1468        {
     1469            AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS);
     1470            saveSettings();
     1471        }
    14461472    }
    14471473
     
    15071533    if (SUCCEEDED(rc))
    15081534    {
    1509         rc = registerImage(image, DeviceType_Floppy);
     1535        bool fNeedsSaveSettings = false;
     1536        rc = registerImage(image, DeviceType_Floppy, &fNeedsSaveSettings);
    15101537
    15111538        if (SUCCEEDED(rc))
    15121539            image.queryInterfaceTo(aFloppyImage);
     1540
     1541        if (fNeedsSaveSettings)
     1542        {
     1543            AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS);
     1544            saveSettings();
     1545        }
    15131546    }
    15141547
     
    27662799 * @return S_OK when found or E_INVALIDARG when not found.
    27672800 *
    2768  * @note Locks this object and hard disk objects for reading.
     2801 * @note Locks the media tree for reading.
    27692802 */
    27702803HRESULT VirtualBox::findHardDisk(const Guid *aId,
     
    28472880 * @return S_OK when found or E_INVALIDARG when not found.
    28482881 *
    2849  * @note Locks this object and image objects for reading.
     2882 * @note Locks the media tree for reading.
    28502883 */
    28512884HRESULT VirtualBox::findDVDImage(const Guid *aId,
     
    29252958 * @return S_OK when found or E_INVALIDARG when not found.
    29262959 *
    2927  * @note Locks this object and image objects for reading.
    2928  */
    2929 HRESULT VirtualBox::findFloppyImage(const Guid *aId, CBSTR aLocation,
     2960 * @note Locks the media tree for reading.
     2961 */
     2962HRESULT VirtualBox::findFloppyImage(const Guid *aId,
     2963                                    CBSTR aLocation,
    29302964                                    bool aSetError,
    29312965                                    ComObjPtr<Medium> *aImage /* = NULL */)
     
    31443178 * @param aConflict     Where to return parameters of the conflicting medium.
    31453179 *
    3146  * @note Locks this object and media objects for reading.
     3180 * @note Locks the media tree and media objects for reading.
    31473181 */
    31483182HRESULT VirtualBox::checkMediaForConflicts2(const Guid &aId,
     
    31543188    AssertReturn(!aId.isEmpty() && !aLocation.isEmpty(), E_FAIL);
    31553189
    3156     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     3190    AutoReadLock alock(getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    31573191
    31583192    HRESULT rc = S_OK;
     
    31763210    {
    31773211        ComObjPtr<Medium> image;
    3178         rc = findDVDImage (&aId, bstrLocation, false /* aSetError */, &image);
     3212        rc = findDVDImage(&aId, bstrLocation, false /* aSetError */, &image);
    31793213        if (SUCCEEDED(rc))
    31803214        {
     
    33943428 *
    33953429 * @param aHardDisk     Hard disk object to remember.
    3396  * @param aSaveRegistry Whether to save the registry after adding the new disk; this is @c false when this gets called during VirtualBox initialization.
    3397  *
    3398  * When @a aSaveRegistry is @c true, this operation may fail because of the
    3399  * failed #saveSettings() method it calls. In this case, the hard disk object
    3400  * will not be remembered. It is therefore the responsibility of the caller to
    3401  * call this method as the last step of some action that requires registration
    3402  * in order to make sure that only fully functional hard disk objects get
    3403  * registered.
    3404  *
    3405  * @note Locks this object for writing and @a aHardDisk for reading.
     3430 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     3431 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     3432 *
     3433 * @note Caller must hold the media tree lock for writing; in addition, this locks @a aHardDisk for reading
    34063434 */
    34073435HRESULT VirtualBox::registerHardDisk(Medium *aHardDisk,
    3408                                      bool aSaveRegistry /*= true*/)
     3436                                     bool *pfNeedsSaveSettings)
    34093437{
    34103438    AssertReturn(aHardDisk != NULL, E_INVALIDARG);
     
    34153443    AutoCaller hardDiskCaller(aHardDisk);
    34163444    AssertComRCReturn(hardDiskCaller.rc(), hardDiskCaller.rc());
     3445
     3446    // caller must hold the media tree write lock
     3447    Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    34173448
    34183449    Guid id;
     
    34273458
    34283459    HRESULT rc;
    3429     {
    3430         // lock the hard disk lists (list + map) while checking for conflicts
    3431         AutoWriteLock al(m->ollHardDisks.getLockHandle() COMMA_LOCKVAL_SRC_POS);
    3432 
    3433         Utf8Str strConflict;
    3434         rc = checkMediaForConflicts2(id,
    3435                                      strLocationFull,
    3436                                      strConflict);
    3437         if (FAILED(rc)) return rc;
    3438         if (strConflict.length())
    3439             return setError(E_INVALIDARG,
    3440                             tr("Cannot register the hard disk '%s' with UUID {%RTuuid} because a %s already exists in the media registry ('%s')"),
    3441                             strLocationFull.raw(),
    3442                             id.raw(),
    3443                             strConflict.raw(),
    3444                             m->strSettingsFilePath.raw());
    3445 
    3446         // store base (root) hard disks in the list
    3447         if (pParent.isNull())
    3448             m->ollHardDisks.getList().push_back(aHardDisk);
    3449                     // access the list directly because we already locked the list above
    3450 
    3451         // store all hard disks (even differencing images) in the map
    3452         m->mapHardDisks[id] = aHardDisk;
    3453     }
    3454 
    3455     if (aSaveRegistry)
    3456     {
    3457         rc = saveSettings();
    3458         if (FAILED(rc))
    3459             unregisterHardDisk(aHardDisk, false /* aSaveRegistry */);
    3460     }
     3460
     3461    Utf8Str strConflict;
     3462    rc = checkMediaForConflicts2(id,
     3463                                 strLocationFull,
     3464                                 strConflict);
     3465    if (FAILED(rc)) return rc;
     3466
     3467    if (strConflict.length())
     3468        return setError(E_INVALIDARG,
     3469                        tr("Cannot register the hard disk '%s' with UUID {%RTuuid} because a %s already exists in the media registry ('%s')"),
     3470                        strLocationFull.raw(),
     3471                        id.raw(),
     3472                        strConflict.raw(),
     3473                        m->strSettingsFilePath.raw());
     3474
     3475    // store base (root) hard disks in the list
     3476    if (pParent.isNull())
     3477        m->ollHardDisks.getList().push_back(aHardDisk);
     3478                // access the list directly because we already locked the list above
     3479
     3480    // store all hard disks (even differencing images) in the map
     3481    m->mapHardDisks[id] = aHardDisk;
     3482
     3483    if (pfNeedsSaveSettings)
     3484        *pfNeedsSaveSettings = true;
    34613485
    34623486    return rc;
     
    34673491 *
    34683492 * @param aHardDisk     Hard disk object to remove.
    3469  * @param aSaveRegistry @c true to save hard disk registry to disk (default).
    3470  *
    3471  * When @a aSaveRegistry is @c true, this operation may fail because of the
    3472  * failed #saveSettings() method it calls. In this case, the hard disk object
    3473  * will NOT be removed from the registry when this method returns. It is
    3474  * therefore the responsibility of the caller to call this method as the first
    3475  * step of some action that requires unregistration, before calling uninit() on
    3476  * @a aHardDisk.
    3477  *
    3478  * @note Locks this object for writing and @a aHardDisk for reading.
     3493 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     3494 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     3495 *
     3496 * @note Caller must hold the media tree lock for writing; in addition, this locks @a aHardDisk for reading
    34793497 */
    34803498HRESULT VirtualBox::unregisterHardDisk(Medium *aHardDisk,
    3481                                        bool aSaveRegistry /*= true*/)
     3499                                       bool *pfNeedsSaveSettings)
    34823500{
    34833501    AssertReturn(aHardDisk != NULL, E_INVALIDARG);
     
    34883506    AutoCaller hardDiskCaller (aHardDisk);
    34893507    AssertComRCReturn(hardDiskCaller.rc(), hardDiskCaller.rc());
     3508
     3509    // caller must hold the media tree write lock
     3510    Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    34903511
    34913512    Guid id;
     
    34973518    }
    34983519
    3499     {
    3500         // lock the hard disk lists (list + map)
    3501         AutoWriteLock al(m->ollHardDisks.getLockHandle() COMMA_LOCKVAL_SRC_POS);
    3502 
    3503         // remove base (root) hard disks from the list
    3504         if (pParent.isNull())
    3505             m->ollHardDisks.getList().remove(aHardDisk);
    3506                     // access the list directly because we already locked the list above
    3507 
    3508         // remove all hard disks (even differencing images) from map
    3509         size_t cnt = m->mapHardDisks.erase(id);
    3510         Assert(cnt == 1);
    3511         NOREF(cnt);
    3512     }
    3513 
    3514     HRESULT rc = S_OK;
    3515 
    3516     if (aSaveRegistry)
    3517     {
    3518         rc = saveSettings();
    3519         if (FAILED(rc))
    3520             registerHardDisk(aHardDisk, false /* aSaveRegistry */);
    3521     }
    3522 
    3523     return rc;
     3520    // remove base (root) hard disks from the list
     3521    if (pParent.isNull())
     3522        m->ollHardDisks.getList().remove(aHardDisk);
     3523                // access the list directly because caller must have locked the list
     3524
     3525    // remove all hard disks (even differencing images) from map
     3526    size_t cnt = m->mapHardDisks.erase(id);
     3527    Assert(cnt == 1);
     3528    NOREF(cnt);
     3529
     3530    if (pfNeedsSaveSettings)
     3531        *pfNeedsSaveSettings = true;
     3532
     3533    return S_OK;
    35243534}
    35253535
     
    35293539 * @param argImage      Image object to remember.
    35303540 * @param argType       Either DeviceType_DVD or DeviceType_Floppy.
    3531  * @param aSaveRegistry @c true to save the image registry to disk (default).
    3532  *
    3533  * When @a aSaveRegistry is @c true, this operation may fail because of the
    3534  * failed #saveSettings() method it calls. In this case, the image object
    3535  * will not be remembered. It is therefore the responsibility of the caller to
    3536  * call this method as the last step of some action that requires registration
    3537  * in order to make sure that only fully functional image objects get
    3538  * registered.
    3539  *
    3540  * @note Locks this object for writing and @a aImage for reading.
     3541 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     3542 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     3543 *
     3544 * @note Caller must hold the media tree lock for writing; in addition, this locks @a argImage for reading
    35413545 */
    35423546HRESULT VirtualBox::registerImage(Medium *argImage,
    35433547                                  DeviceType_T argType,
    3544                                   bool argSaveRegistry /*= true*/)
     3548                                  bool *pfNeedsSaveSettings)
    35453549{
    35463550    AssertReturn(argImage != NULL, E_INVALIDARG);
     
    35513555    AutoCaller imageCaller(argImage);
    35523556    AssertComRCReturn(imageCaller.rc(), imageCaller.rc());
     3557
     3558    // caller must hold the media tree write lock
     3559    Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    35533560
    35543561    Guid id;
     
    35663573
    35673574    HRESULT rc;
    3568     {
    3569         // lock the images lists (list + map) while checking for conflicts
    3570         AutoWriteLock al(oll.getLockHandle() COMMA_LOCKVAL_SRC_POS);
    3571 
    3572         Utf8Str strConflict;
    3573         rc = checkMediaForConflicts2(id,
    3574                                      strLocationFull,
    3575                                      strConflict);
    3576         if (FAILED(rc)) return rc;
    3577 
    3578         if (strConflict.length())
    3579             return setError(VBOX_E_INVALID_OBJECT_STATE,
    3580                             tr("Cannot register the image '%s' with UUID {%RTuuid} because a %s already exists in the media registry ('%s')"),
    3581                             strLocationFull.raw(),
    3582                             id.raw(),
    3583                             strConflict.raw(),
    3584                             m->strSettingsFilePath.raw());
    3585 
    3586         // add to the collection
    3587         oll.getList().push_back(argImage);
    3588                 // access the list directly because we already locked the list above
    3589     }
    3590 
    3591     if (argSaveRegistry)
    3592     {
    3593         rc = saveSettings();
    3594         if (FAILED(rc))
    3595             unregisterImage(argImage, argType, false /* aSaveRegistry */);
    3596     }
     3575    // lock the images lists (list + map) while checking for conflicts
     3576    AutoWriteLock al(oll.getLockHandle() COMMA_LOCKVAL_SRC_POS);
     3577
     3578    Utf8Str strConflict;
     3579    rc = checkMediaForConflicts2(id,
     3580                                    strLocationFull,
     3581                                    strConflict);
     3582    if (FAILED(rc)) return rc;
     3583
     3584    if (strConflict.length())
     3585        return setError(VBOX_E_INVALID_OBJECT_STATE,
     3586                        tr("Cannot register the image '%s' with UUID {%RTuuid} because a %s already exists in the media registry ('%s')"),
     3587                        strLocationFull.raw(),
     3588                        id.raw(),
     3589                        strConflict.raw(),
     3590                        m->strSettingsFilePath.raw());
     3591
     3592    // add to the collection
     3593    oll.getList().push_back(argImage);
     3594            // access the list directly because we already locked the list above
     3595
     3596    if (pfNeedsSaveSettings)
     3597        *pfNeedsSaveSettings = true;
    35973598
    35983599    return rc;
     
    36043605 * @param argImage        Image object to remove.
    36053606 * @param argType         Either DeviceType_DVD or DeviceType_Floppy.
    3606  * @param argSaveRegistry @c true to save hard disk registry to disk (default).
    3607  *
    3608  * When @a aSaveRegistry is @c true, this operation may fail because of the
    3609  * failed #saveSettings() method it calls. In this case, the image object
    3610  * will NOT be removed from the registry when this method returns. It is
    3611  * therefore the responsibility of the caller to call this method as the first
    3612  * step of some action that requires unregistration, before calling uninit() on
    3613  * @a aImage.
    3614  *
    3615  * @note Locks this object for writing and @a aImage for reading.
     3607 * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
     3608 *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
     3609 *
     3610 * @note Caller must hold the media tree lock for writing; in addition, this locks @a argImage for reading
    36163611 */
    36173612HRESULT VirtualBox::unregisterImage(Medium *argImage,
    36183613                                    DeviceType_T argType,
    3619                                     bool argSaveRegistry /*= true*/)
     3614                                    bool *pfNeedsSaveSettings)
    36203615{
    36213616    AssertReturn(argImage != NULL, E_INVALIDARG);
     
    36263621    AutoCaller imageCaller(argImage);
    36273622    AssertComRCReturn(imageCaller.rc(), imageCaller.rc());
     3623
     3624    // caller must hold the media tree write lock
     3625    Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread());
    36283626
    36293627    Guid id;
     
    36383636    ObjectsList<Medium> &oll = (argType == DeviceType_DVD) ? m->ollDVDImages : m->ollFloppyImages;
    36393637
    3640     oll.removeChild(argImage);
     3638    // access the list directly because the caller must have requested the lock
     3639    oll.getList().remove(argImage);
    36413640
    36423641    HRESULT rc = S_OK;
    36433642
    3644     if (argSaveRegistry)
    3645     {
    3646         rc = saveSettings();
    3647         if (FAILED(rc))
    3648             registerImage(argImage, argType, false /* aSaveRegistry */);
    3649     }
     3643    if (pfNeedsSaveSettings)
     3644        *pfNeedsSaveSettings = true;
    36503645
    36513646    return rc;
     
    37793774
    37803775/**
    3781  * Returns a lock handle used to protect changes to the hard disk hierarchy
    3782  * (e.g. serialize access to the Medium::mParent fields and methods
    3783  * adding/removing children). When using this lock, the following rules must
    3784  * be obeyed:
    3785  *
    3786  * 1. The write lock on this handle must be either held alone on the thread
    3787  *    or requested *after* the VirtualBox object lock. Mixing with other
    3788  *    locks is prohibited.
    3789  *
    3790  * 2. The read lock on this handle may be intermixed with any other lock
    3791  *    with the exception that it must be requested *after* the VirtualBox
    3792  *    object lock.
    3793  */
    3794 RWLockHandle& VirtualBox::hardDiskTreeLockHandle()
    3795 {
    3796     return m->ollHardDisks.getLockHandle();
     3776 * Returns the lock handle which protects the media trees (hard disks,
     3777 * DVDs, floppies). As opposed to version 3.1 and earlier, these lists
     3778 * are no longer protected by the VirtualBox lock, but by this more
     3779 * specialized lock. Mind the locking order: always request this lock
     3780 * after the VirtualBox object lock but before the locks of the media
     3781 * objects contained in these lists. See AutoLock.h.
     3782 */
     3783RWLockHandle& VirtualBox::getMediaTreeLockHandle()
     3784{
     3785    return m->lockMedia;
    37973786}
    37983787
  • trunk/src/VBox/Main/include/MachineImpl.h

    r25901 r25903  
    889889                                IProgress *aProgress,
    890890                                ULONG aWeight,
    891                                 bool aOnline);
    892     HRESULT deleteImplicitDiffs();
     891                                bool aOnline,
     892                                bool *pfNeedsSaveSettings);
     893    HRESULT deleteImplicitDiffs(bool *pfNeedsSaveSettings);
    893894
    894895    MediumAttachment* findAttachment(const MediaData::AttachmentList &ll,
     
    901902                                     Guid &id);
    902903
    903     void fixupMedia(bool aCommit, bool aOnline = false);
     904    void commitMedia(bool aOnline = false);
     905    void rollbackMedia();
    904906
    905907    bool isInOwnDir(Utf8Str *aSettingsDir = NULL);
     
    10881090
    10891091    HRESULT endSavingState(BOOL aSuccess);
    1090     HRESULT endTakingSnapshot(BOOL aSuccess);
    10911092
    10921093    typedef std::map<ComObjPtr<Machine>, MachineState_T> AffectedMachines;
  • trunk/src/VBox/Main/include/MediumImpl.h

    r25888 r25903  
    7878    HRESULT init(VirtualBox *aVirtualBox,
    7979                 CBSTR aFormat,
    80                  CBSTR aLocation);
     80                 CBSTR aLocation,
     81                 bool *pfNeedsSaveSettings);
    8182    HRESULT init(VirtualBox *aVirtualBox,
    8283                 CBSTR aLocation,
     
    193194     */
    194195    HRESULT deleteStorageNoWait(ComObjPtr<Progress> &aProgress)
    195     { return deleteStorage(&aProgress, false /* aWait */); }
     196    { return deleteStorage(&aProgress, false /* aWait */, NULL /* pfNeedsSaveSettings */); }
    196197
    197198    /**
     
    199200     * blocking the current thread.
    200201     */
    201     HRESULT deleteStorageAndWait(ComObjPtr<Progress> *aProgress = NULL)
    202     { return deleteStorage(aProgress, true /* aWait */); }
     202    HRESULT deleteStorageAndWait(ComObjPtr<Progress> *aProgress, bool *pfNeedsSaveSettings)
     203    { return deleteStorage(aProgress, true /* aWait */, pfNeedsSaveSettings); }
    203204
    204205    /**
     
    209210                                    MediumVariant_T aVariant,
    210211                                    ComObjPtr<Progress> &aProgress)
    211     { return createDiffStorage(aTarget, aVariant, &aProgress, false /* aWait */); }
     212    { return createDiffStorage(aTarget, aVariant, &aProgress, false /* aWait */, NULL /* pfNeedsSaveSettings*/ ); }
    212213
    213214    /**
     
    217218    HRESULT createDiffStorageAndWait(ComObjPtr<Medium> &aTarget,
    218219                                     MediumVariant_T aVariant,
    219                                      ComObjPtr<Progress> *aProgress = NULL)
    220     { return createDiffStorage(aTarget, aVariant, aProgress, true /* aWait */); }
     220                                     bool *pfNeedsSaveSettings)
     221    { return createDiffStorage(aTarget, aVariant, NULL /*aProgress*/, true /* aWait */, pfNeedsSaveSettings); }
    221222
    222223    HRESULT prepareMergeTo(Medium *aTarget, MergeChain * &aChain,
     
    229230    HRESULT mergeToNoWait(MergeChain *aChain,
    230231                          ComObjPtr<Progress> &aProgress)
    231     { return mergeTo(aChain, &aProgress, false /* aWait */); }
     232    { return mergeTo(aChain, &aProgress, false /* aWait */, NULL /*pfNeedsSaveSettings*/); }
    232233
    233234    /**
     
    236237     */
    237238    HRESULT mergeToAndWait(MergeChain *aChain,
    238                            ComObjPtr<Progress> *aProgress = NULL)
    239     { return mergeTo(aChain, aProgress, true /* aWait */); }
     239                           ComObjPtr<Progress> *aProgress,
     240                           bool *pfNeedsSaveSettings)
     241    { return mergeTo(aChain, aProgress, true /* aWait */, pfNeedsSaveSettings); }
    240242
    241243    void cancelMergeTo(MergeChain *aChain);
     
    244246
    245247    HRESULT prepareDiscard(MergeChain * &aChain);
    246     HRESULT discard(ComObjPtr<Progress> &aProgress, ULONG ulWeight, MergeChain *aChain);
     248    HRESULT discard(ComObjPtr<Progress> &aProgress, ULONG ulWeight, MergeChain *aChain, bool *pfNeedsSaveSettings);
    247249    void cancelDiscard(MergeChain *aChain);
    248250
     
    273275     * this object's AutoMayUninitSpan and from under mVirtualBox write lock.
    274276     */
    275     HRESULT unregisterWithVirtualBox();
     277    HRESULT unregisterWithVirtualBox(bool *pfNeedsSaveSettings);
    276278
    277279    HRESULT setStateError();
    278280
    279     HRESULT deleteStorage(ComObjPtr<Progress> *aProgress, bool aWait);
     281    HRESULT deleteStorage(ComObjPtr<Progress> *aProgress, bool aWait, bool *pfNeedsSaveSettings);
    280282
    281283    HRESULT createDiffStorage(ComObjPtr<Medium> &aTarget,
    282284                              MediumVariant_T aVariant,
    283285                              ComObjPtr<Progress> *aProgress,
    284                               bool aWait);
     286                              bool aWait,
     287                              bool *pfNeedsSaveSettings);
    285288
    286289    HRESULT mergeTo(MergeChain *aChain,
    287290                    ComObjPtr<Progress> *aProgress,
    288                     bool aWait);
     291                    bool aWait,
     292                    bool *pfNeedsSaveSettings);
    289293
    290294    HRESULT setLocation(const Utf8Str &aLocation, const Utf8Str &aFormat = Utf8Str());
  • trunk/src/VBox/Main/include/VirtualBoxImpl.h

    r25834 r25903  
    274274    void calculateRelativePath(const Utf8Str &strPath, Utf8Str &aResult);
    275275
    276     HRESULT registerHardDisk(Medium *aHardDisk, bool aSaveRegistry = true);
    277     HRESULT unregisterHardDisk(Medium *aHardDisk, bool aSaveRegistry = true);
    278 
    279     HRESULT registerImage(Medium *aImage, DeviceType_T argType, bool aSaveRegistry = true);
    280     HRESULT unregisterImage(Medium *aImage, DeviceType_T argType, bool aSaveRegistry = true);
     276    HRESULT registerHardDisk(Medium *aHardDisk, bool *pfNeedsSaveSettings);
     277    HRESULT unregisterHardDisk(Medium *aHardDisk, bool *pfNeedsSaveSettings);
     278
     279    HRESULT registerImage(Medium *aImage, DeviceType_T argType, bool *pfNeedsSaveSettings);
     280    HRESULT unregisterImage(Medium *aImage, DeviceType_T argType, bool *pfNeedsSaveSettings);
    281281
    282282    HRESULT saveSettings();
     
    289289    const Utf8Str& settingsFilePath();
    290290
    291     RWLockHandle& hardDiskTreeLockHandle();
     291    RWLockHandle& getMediaTreeLockHandle();
    292292
    293293    /* for VirtualBoxSupportErrorInfoImpl */
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