Changeset 25903 in vbox
- Timestamp:
- Jan 18, 2010 6:15:43 PM (15 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ConsoleImpl.cpp
r25902 r25903 1752 1752 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1753 1753 1754 AutoWriteLock alock(this );1754 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1755 1755 1756 1756 if ( mMachineState != MachineState_Running … … 1905 1905 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1906 1906 1907 AutoWriteLock alock(this );1907 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1908 1908 1909 1909 if ( mMachineState != MachineState_Running -
trunk/src/VBox/Main/MachineImpl.cpp
r25901 r25903 1129 1129 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1130 1130 1131 AutoReadLock alock(this );1131 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1132 1132 1133 1133 *enabled = mHWData->mCPUHotPlugEnabled; … … 1143 1143 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1144 1144 1145 AutoWriteLock alock(this );1145 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1146 1146 1147 1147 rc = checkStateDependency(MutableStateDep); … … 2426 2426 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2427 2427 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); 2433 2434 2434 2435 HRESULT rc = checkStateDependency(MutableStateDep); … … 2505 2506 break; 2506 2507 2507 case DeviceType_DVD: 2508 case DeviceType_DVD: // @todo r=dj eliminate this, replace with findDVDImage 2508 2509 if (!uuid.isEmpty()) 2509 2510 { … … 2538 2539 break; 2539 2540 2540 case DeviceType_Floppy: 2541 case DeviceType_Floppy: // @todo r=dj eliminate this, replace with findFloppyImage 2541 2542 if (!uuid.isEmpty()) 2542 2543 { … … 2582 2583 AutoWriteLock mediumLock(medium COMMA_LOCKVAL_SRC_POS); 2583 2584 2584 if ( (pAttachTemp = findAttachment(mMediaData->mAttachments, medium))2585 && !medium.isNull())2586 {2585 if ( (pAttachTemp = findAttachment(mMediaData->mAttachments, medium)) 2586 && !medium.isNull() 2587 ) 2587 2588 return setError(VBOX_E_OBJECT_IN_USE, 2588 2589 tr("Medium '%s' is already attached to this virtual machine"), 2589 2590 medium->getLocationFull().raw()); 2590 }2591 2591 2592 2592 bool indirect = false; … … 2774 2774 medium->preferredDiffFormat().raw(), 2775 2775 BstrFmt("%ls"RTPATH_SLASH_STR, 2776 mUserData->mSnapshotFolderFull.raw()).raw()); 2776 mUserData->mSnapshotFolderFull.raw()).raw(), 2777 &fNeedsSaveSettings); 2777 2778 if (FAILED(rc)) return rc; 2778 2779 … … 2789 2790 alock.leave(); 2790 2791 2791 rc = medium->createDiffStorageAndWait(diff, MediumVariant_Standard );2792 rc = medium->createDiffStorageAndWait(diff, MediumVariant_Standard, &fNeedsSaveSettings); 2792 2793 2793 2794 alock.enter(); … … 2826 2827 mMediaData->mAttachments.push_back(attachment); 2827 2828 2829 if (fNeedsSaveSettings) 2830 { 2831 mediumLock.release(); 2832 alock.release(); 2833 2834 AutoWriteLock(mParent COMMA_LOCKVAL_SRC_POS); 2835 mParent->saveSettings(); 2836 } 2837 2828 2838 return rc; 2829 2839 } … … 2839 2849 AutoCaller autoCaller(this); 2840 2850 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2851 2852 bool fNeedsSaveSettings = false; 2841 2853 2842 2854 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 2881 2893 alock.leave(); 2882 2894 2883 rc = oldmedium->deleteStorageAndWait( );2895 rc = oldmedium->deleteStorageAndWait(NULL /*aProgress*/, &fNeedsSaveSettings); 2884 2896 2885 2897 alock.enter(); … … 2900 2912 if (mediumType != DeviceType_HardDisk && !oldmedium.isNull()) 2901 2913 oldmedium->detachFrom(mData->mUuid); 2914 2915 if (fNeedsSaveSettings) 2916 { 2917 alock.release(); 2918 AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS); 2919 saveSettings(); 2920 } 2902 2921 2903 2922 return S_OK; … … 4360 4379 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 4361 4380 4362 AutoWriteLock alock(this );4381 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 4363 4382 4364 4383 if (!mHWData->mCPUHotPlugEnabled) … … 4394 4413 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 4395 4414 4396 AutoWriteLock alock(this );4415 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 4397 4416 4398 4417 if (!mHWData->mCPUHotPlugEnabled) … … 4437 4456 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 4438 4457 4439 AutoReadLock alock(this );4458 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 4440 4459 4441 4460 /* If hotplug is enabled the CPU is always enabled. */ … … 6966 6985 * - SaveS_InformCallbacksAnyway: Callbacks will be informed even if 6967 6986 * #isReallyModified() returns false. This is necessary for cases when we 6968 * change machine data di ectly, not through the backup()/commit() mechanism.6987 * change machine data directly, not through the backup()/commit() mechanism. 6969 6988 * 6970 6989 * @note Must be called from under mParent write lock (sometimes needed by … … 7520 7539 * attached). 7521 7540 * @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. 7522 7543 * 7523 7544 * @note The progress object is not marked as completed, neither on success nor … … 7529 7550 IProgress *aProgress, 7530 7551 ULONG aWeight, 7531 bool aOnline) 7552 bool aOnline, 7553 bool *pfNeedsSaveSettings) 7532 7554 { 7533 7555 AssertReturn(!aFolder.isEmpty(), E_FAIL); … … 7625 7647 medium->preferredDiffFormat().raw(), 7626 7648 BstrFmt("%ls"RTPATH_SLASH_STR, 7627 mUserData->mSnapshotFolderFull.raw()).raw()); 7649 mUserData->mSnapshotFolderFull.raw()).raw(), 7650 pfNeedsSaveSettings); 7628 7651 if (FAILED(rc)) throw rc; 7629 7652 … … 7633 7656 rc = medium->createDiffStorageAndWait(diff, 7634 7657 MediumVariant_Standard, 7635 NULL);7658 pfNeedsSaveSettings); 7636 7659 7637 7660 /** @todo r=bird: How is the locking and diff image cleaned up if we fail before … … 7693 7716 MultiResultRef mrc (rc); 7694 7717 7695 mrc = deleteImplicitDiffs( );7718 mrc = deleteImplicitDiffs(pfNeedsSaveSettings); 7696 7719 } 7697 7720 … … 7706 7729 * called from #fixupMedia() when the changes are rolled back. 7707 7730 * 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 * 7708 7734 * @note Locks this object for writing. 7709 7735 */ 7710 HRESULT Machine::deleteImplicitDiffs( )7736 HRESULT Machine::deleteImplicitDiffs(bool *pfNeedsSaveSettings) 7711 7737 { 7712 7738 AutoCaller autoCaller(this); … … 7783 7809 ComObjPtr<Medium> hd = (*it)->getMedium(); 7784 7810 7785 rc = hd->deleteStorageAndWait( );7811 rc = hd->deleteStorageAndWait(NULL /*aProgress*/, pfNeedsSaveSettings); 7786 7812 #if 1 /* HACK ALERT: Just make it kind of work */ /** @todo Fix this hack properly. The LockWrite / UnlockWrite / LockRead changes aren't undone! */ 7787 7813 if (rc == VBOX_E_INVALID_OBJECT_STATE) … … 7789 7815 LogFlowFunc(("Applying unlock hack on '%s'! FIXME!\n", (*it)->getLogName())); 7790 7816 hd->UnlockWrite(NULL); 7791 rc = hd->deleteStorageAndWait( );7817 rc = hd->deleteStorageAndWait(NULL /*aProgress*/, pfNeedsSaveSettings); 7792 7818 } 7793 7819 #endif … … 7890 7916 7891 7917 /** 7892 * Perform deferred hard disk detachments on success and deletion of implicitly 7893 * created diffs on failure. 7918 * Perform deferred hard disk detachments. 7894 7919 * 7895 7920 * Does nothing if the hard disk attachment data (mMediaData) is not changed (not 7896 7921 * backed up). 7897 7922 * 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 * 7907 7927 * @param aOnline Whether the VM was online prior to this operation. 7908 7928 * 7909 7929 * @note Locks this object for writing! 7910 7930 */ 7911 void Machine:: fixupMedia(bool aCommit,bool aOnline /*= false*/)7931 void Machine::commitMedia(bool aOnline /*= false*/) 7912 7932 { 7913 7933 AutoCaller autoCaller(this); … … 7916 7936 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 7917 7937 7918 LogFlowThisFunc(("Entering, a Commit=%d, aOnline=%d\n", aCommit, aOnline));7938 LogFlowThisFunc(("Entering, aOnline=%d\n", aOnline)); 7919 7939 7920 7940 HRESULT rc = S_OK; … … 7924 7944 return; 7925 7945 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 */ 8080 void 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 { 7939 8104 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 MediumAttachment7947 * based commit logic. */7948 if (fImplicit)7949 {7950 /* convert implicit attachment to normal */7951 pAttach->setImplicit(false);7952 7953 if ( aOnline7954 && pMedium7955 && pAttach->getType() == DeviceType_HardDisk7956 )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 the7966 * 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 that7977 * vector (write lock => read lock) but this would take7978 * some effort. So lets just ignore the error code in7979 * 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 7988 8105 if (pMedium) 7989 8106 { 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 the8009 * 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 detached8018 * 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 */8024 8107 rc = pMedium->detachFrom(mData->mUuid); 8025 8108 AssertComRC(rc); 8026 8027 if ( aOnline8028 && 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 }8036 8109 } 8037 8110 } 8038 8111 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) 8058 8120 { 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); 8065 8123 } 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*/); 8088 8132 8089 8133 return; … … 8307 8351 8308 8352 if (mMediaData.isBackedUp()) 8309 fixupMedia(false /* aCommit */);8353 rollbackMedia(); 8310 8354 8311 8355 /* check for changes in child objects */ … … 8402 8446 8403 8447 if (mMediaData.isBackedUp()) 8404 fixupMedia(true /* aCommit */);8448 commitMedia(); 8405 8449 8406 8450 mBIOSSettings->commit(); … … 8913 8957 { 8914 8958 LogWarningThisFunc(("canceling failed save state request!\n")); 8915 endSavingState 8959 endSavingState(FALSE /* aSuccess */); 8916 8960 } 8917 8961 else if (!mSnapshotData.mSnapshot.isNull()) 8918 8962 { 8919 8963 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(); 8921 8973 } 8922 8974 -
trunk/src/VBox/Main/MediumImpl.cpp
r25888 r25903 118 118 Utf8Str strLastAccessError; 119 119 120 // pParent and llChildren are protected by VirtualBox:: hardDiskTreeLockHandle()120 // pParent and llChildren are protected by VirtualBox::getMediaTreeLockHandle() 121 121 ComObjPtr<Medium> pParent; 122 122 MediaList llChildren; // to add a child, just call push_back; to remove a child, call child->deparent() which does a lookup … … 205 205 HRESULT m_rc; 206 206 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 207 212 Task(Medium *aThat, 208 213 Progress *aProgress, … … 212 217 m_pProgress(aProgress), 213 218 m_operation(aOperation), 214 m_rc(S_OK) 215 {} 219 m_rc(S_OK), 220 m_pfNeedsSaveSettings(NULL) 221 { } 216 222 217 223 ~Task(); … … 258 264 259 265 HRESULT startThread(); 260 HRESULT runNow( );266 HRESULT runNow(bool *pfNeedsSaveSettings); 261 267 262 268 struct Data … … 279 285 280 286 /** Media to open, in {parent,child} order */ 281 std::auto_ptr 287 std::auto_ptr<ImageChain> source; 282 288 /** Media which are parent of target, in {parent,child} order */ 283 std::auto_ptr 289 std::auto_ptr<ImageChain> parent; 284 290 /** The to-be parent medium object */ 285 291 ComObjPtr<Medium> parentDisk; … … 288 294 289 295 /** Media to merge, in {parent,child} order */ 290 std::auto_ptr 296 std::auto_ptr<MergeChain> chain; 291 297 292 298 /* Compact */ 293 299 294 300 /** Media to open, in {parent,child} order */ 295 std::auto_ptr <ImageChain> images; 296 } 297 d; 301 std::auto_ptr<ImageChain> images; 302 } d; 298 303 299 304 protected: … … 354 359 * complete the progress object in this case. 355 360 */ 356 HRESULT Medium::Task::runNow() 357 { 361 HRESULT Medium::Task::runNow(bool *pfNeedsSaveSettings) 362 { 363 m_pfNeedsSaveSettings = pfNeedsSaveSettings; 364 358 365 /* NIL_RTTHREAD indicates synchronous call. */ 359 366 Medium::taskThread(NIL_RTTHREAD, this); … … 880 887 * @param aVirtualBox VirtualBox object. 881 888 * @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. 882 891 */ 883 892 HRESULT Medium::init(VirtualBox *aVirtualBox, 884 893 CBSTR aFormat, 885 CBSTR aLocation) 894 CBSTR aLocation, 895 bool *pfNeedsSaveSettings) 886 896 { 887 897 AssertReturn(aVirtualBox != NULL, E_FAIL); … … 917 927 rc = setLocation(aLocation); 918 928 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 ) 929 934 { 930 935 /* storage for hard disks of this format can neither be explicitly … … 933 938 m->state = MediumState_Created; 934 939 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); 943 943 } 944 944 … … 1078 1078 { 1079 1079 // 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); 1081 1081 m->pParent = aParent; 1082 1082 aParent->m->llChildren.push_back(this); … … 1160 1160 * get the actual state and the rest of the data, the user will have to call 1161 1161 * COMGETTER(State). */ 1162 1163 AutoWriteLock treeLock(aVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 1162 1164 1163 1165 /* load all children */ … … 1541 1543 1542 1544 /* we access mParent & children() */ 1543 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);1545 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 1544 1546 1545 1547 /* cannot change the type of a differencing hard disk */ … … 1594 1596 1595 1597 /* we access mParent */ 1596 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);1598 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 1597 1599 1598 1600 m->pParent.queryInterfaceTo(aParent); … … 1610 1612 1611 1613 /* we access children */ 1612 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);1614 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 1613 1615 1614 1616 SafeIfaceArray<IMedium> children(this->getChildren()); … … 1654 1656 1655 1657 /* we access mParent */ 1656 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);1658 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 1657 1659 1658 1660 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); … … 2033 2035 return S_OK; 2034 2036 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); 2043 2041 2044 2042 bool wasCreated = true; 2043 bool fNeedsSaveSettings = false; 2045 2044 2046 2045 switch (m->state) … … 2070 2069 * uninitialization (to keep the media registry consistent on 2071 2070 * failure to do so) */ 2072 rc = unregisterWithVirtualBox( );2071 rc = unregisterWithVirtualBox(&fNeedsSaveSettings); 2073 2072 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(); 2074 2081 } 2075 2082 … … 2389 2396 2390 2397 /* 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); 2392 2399 for (Medium *hd = this; 2393 2400 hd; … … 2491 2498 2492 2499 /* 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); 2494 2501 for (Medium *hd = this; 2495 2502 hd; … … 2556 2563 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2557 2564 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); 2559 2569 2560 2570 LogFlowThisFunc(("ENTER for medium %s\n", m->strLocationFull.c_str())); … … 2577 2587 progress.createObject(); 2578 2588 rc = progress->init(m->pVirtualBox, 2579 static_cast <IMedium*>(this),2589 static_cast<IMedium*>(this), 2580 2590 BstrFmt(tr("Resetting differencing hard disk '%s'"), m->strLocationFull.raw()), 2581 2591 FALSE /* aCancelable */); … … 2584 2594 /* setup task object and thread to carry out the operation 2585 2595 * asynchronously */ 2586 2587 2596 std::auto_ptr<Task> task(new Task(this, progress, Task::Reset)); 2588 2597 AssertComRCThrowRC(task->m_autoCaller.rc()); … … 2932 2941 2933 2942 /* we access children() */ 2934 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);2943 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 2935 2944 2936 2945 updatePath(aOldPath, aNewPath); … … 2966 2975 2967 2976 /* we access mParent */ 2968 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);2977 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 2969 2978 2970 2979 pBase = this; … … 3005 3014 3006 3015 /* we access children */ 3007 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);3016 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 3008 3017 3009 3018 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); … … 3052 3061 3053 3062 /* we access mParent */ 3054 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);3063 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 3055 3064 3056 3065 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); … … 3181 3190 3182 3191 /* we access mParent & children() */ 3183 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);3192 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 3184 3193 3185 3194 AssertReturn(m->type == MediumType_Normal, E_FAIL); … … 3298 3307 * reading or writing. 3299 3308 */ 3300 HRESULT Medium::discard(ComObjPtr<Progress> &aProgress, ULONG ulWeight, MergeChain *aChain) 3309 HRESULT Medium::discard(ComObjPtr<Progress> &aProgress, 3310 ULONG ulWeight, 3311 MergeChain *aChain, 3312 bool *pfNeedsSaveSettings) 3301 3313 { 3302 3314 AssertReturn(!aProgress.isNull(), E_FAIL); … … 3315 3327 if (aChain == NULL) 3316 3328 { 3317 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);3318 3319 3329 /* we access mParent & children() */ 3320 Auto ReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);3330 AutoMultiWriteLock2 mLock(&m->pVirtualBox->getMediaTreeLockHandle(), this->lockHandle() COMMA_LOCKVAL_SRC_POS); 3321 3331 3322 3332 Assert(getChildren().size() == 0); … … 3340 3350 hdFrom = this; 3341 3351 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); 3348 3353 } 3349 3354 else … … 3351 3356 hdFrom = aChain->source(); 3352 3357 3353 rc = hdFrom->mergeToAndWait(aChain, &aProgress );3358 rc = hdFrom->mergeToAndWait(aChain, &aProgress, pfNeedsSaveSettings); 3354 3359 } 3355 3360 } … … 3386 3391 3387 3392 /* we access mParent & children() */ 3388 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);3393 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 3389 3394 3390 3395 Assert(getChildren().size() == 0); … … 3852 3857 3853 3858 /* we set mParent & children() */ 3854 AutoWriteLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);3859 AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 3855 3860 3856 3861 Assert(m->pParent.isNull()); … … 3861 3866 { 3862 3867 /* we access mParent */ 3863 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);3868 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 3864 3869 3865 3870 /* check that parent UUIDs match. Note that there's no need … … 4044 4049 * @param aWait @c true if this method should block instead of creating 4045 4050 * 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. 4046 4055 * 4047 4056 * @note Locks mVirtualBox and this object for writing. Locks getTreeLock() for 4048 4057 * writing. 4049 4058 */ 4050 HRESULT Medium::deleteStorage(ComObjPtr <Progress> *aProgress, bool aWait) 4059 HRESULT Medium::deleteStorage(ComObjPtr<Progress> *aProgress, 4060 bool aWait, 4061 bool *pfNeedsSaveSettings) 4051 4062 { 4052 4063 AssertReturn(aProgress != NULL || aWait == true, E_FAIL); 4053 4064 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); 4061 4069 LogFlowThisFunc(("aWait=%RTbool locationFull=%s\n", aWait, getLocationFull().c_str() )); 4062 4070 … … 4111 4119 m->state = MediumState_Deleting; 4112 4120 4113 /* we need to leave this object's write lock now because of4114 * unregisterWithVirtualBox() that locks getTreeLock() for writing */4115 alock.leave();4116 4117 4121 /* try to remove from the list of known hard disks before performing actual 4118 4122 * deletion (we favor the consistency of the media registry in the first 4119 4123 * place which would have been broken if unregisterWithVirtualBox() failed 4120 4124 * after we successfully deleted the storage) */ 4121 4122 rc = unregisterWithVirtualBox(); 4123 4124 alock.enter(); 4125 rc = unregisterWithVirtualBox(pfNeedsSaveSettings); 4125 4126 4126 4127 /* restore the state because we may fail below; we will set it later again*/ … … 4148 4149 } 4149 4150 4150 std::auto_ptr 4151 std::auto_ptr<Task> task(new Task(this, progress, Task::Delete)); 4151 4152 AssertComRCReturnRC(task->m_autoCaller.rc()); 4152 4153 … … 4156 4157 m->state = MediumState_Deleting; 4157 4158 4158 rc = task->runNow( );4159 rc = task->runNow(NULL /* pfNeedsSaveSettings*/ ); // there is no save settings to do in taskThreadDelete() 4159 4160 } 4160 4161 else … … 4211 4212 * @param aWait @c true if this method should block instead of creating 4212 4213 * 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. 4213 4218 * 4214 4219 * @note Locks this object and @a aTarget for writing. … … 4217 4222 MediumVariant_T aVariant, 4218 4223 ComObjPtr<Progress> *aProgress, 4219 bool aWait) 4224 bool aWait, 4225 bool *pfNeedsSaveSettings) 4220 4226 { 4221 4227 AssertReturn(!aTarget.isNull(), E_FAIL); … … 4233 4239 4234 4240 /* 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); 4237 4243 4238 4244 if (aTarget->m->state != MediumState_NotCreated) … … 4243 4249 /* check that the hard disk is not attached to any VM in the current state*/ 4244 4250 for (BackRefList::const_iterator it = m->backRefs.begin(); 4245 it != m->backRefs.end(); ++ it) 4251 it != m->backRefs.end(); 4252 ++it) 4246 4253 { 4247 4254 if (it->fInCurState) … … 4257 4264 4258 4265 if (it->llSnapshotIds.size() == 0) 4259 {4260 4266 return setError(VBOX_E_INVALID_OBJECT_STATE, 4261 4267 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"), 4262 4268 m->strLocationFull.raw(), it->machineId.raw()); 4263 }4264 4269 4265 4270 Assert(it->llSnapshotIds.size() == 1); … … 4267 4272 } 4268 4273 4269 ComObjPtr 4274 ComObjPtr<Progress> progress; 4270 4275 4271 4276 if (aProgress != NULL) … … 4286 4291 } 4287 4292 4288 /* set up task object and thread to carry out the operation4293 /* set up task object and thread to carry out the operation 4289 4294 * asynchronously */ 4290 4295 4291 std::auto_ptr 4296 std::auto_ptr<Task> task(new Task(this, progress, Task::CreateDiff)); 4292 4297 AssertComRCReturnRC(task->m_autoCaller.rc()); 4293 4298 … … 4301 4306 if (aWait) 4302 4307 { 4303 / * go to Creating state before starting the task */4308 // go to Creating state before starting the task 4304 4309 aTarget->m->state = MediumState_Creating; 4305 4310 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); 4307 4317 } 4308 4318 else … … 4365 4375 4366 4376 /* we walk the tree */ 4367 AutoReadLock treeLock(m->pVirtualBox-> hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);4377 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 4368 4378 4369 4379 HRESULT rc = S_OK; … … 4495 4505 * @param aWait @c true if this method should block instead of creating 4496 4506 * 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. 4497 4511 * 4498 4512 * @note Locks the branch lock for writing. Locks the hard disks from the chain … … 4501 4515 HRESULT Medium::mergeTo(MergeChain *aChain, 4502 4516 ComObjPtr <Progress> *aProgress, 4503 bool aWait) 4517 bool aWait, 4518 bool *pfNeedsSaveSettings) 4504 4519 { 4505 4520 AssertReturn(aChain != NULL, E_FAIL); … … 4549 4564 if (aWait) 4550 4565 { 4551 rc = task->runNow( );4566 rc = task->runNow(pfNeedsSaveSettings); 4552 4567 } 4553 4568 else … … 4640 4655 * @note Also reused by Medium::Reset(). 4641 4656 * 4642 * @note Locks getTreeLock() for reading.4657 * @note Caller must hold the media tree write lock! 4643 4658 */ 4644 4659 HRESULT Medium::canClose() 4645 4660 { 4646 /* we access children */ 4647 AutoReadLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 4661 Assert(m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread()); 4648 4662 4649 4663 if (getChildren().size() != 0) … … 4656 4670 4657 4671 /** 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 * 4658 4678 * @note Called from within this object's AutoMayUninitSpan (or AutoCaller) and 4659 4679 * from under mVirtualBox write lock. 4660 4680 * 4661 * @note Locks getTreeLock() for writing.4662 */ 4663 HRESULT Medium::unregisterWithVirtualBox( )4681 * @note Caller must have locked the media tree lock for writing! 4682 */ 4683 HRESULT Medium::unregisterWithVirtualBox(bool *pfNeedsSaveSettings) 4664 4684 { 4665 4685 /* Note that we need to de-associate ourselves from the parent to let … … 4667 4687 4668 4688 /* we modify mParent and access children */ 4669 A utoWriteLock treeLock(m->pVirtualBox->hardDiskTreeLockHandle() COMMA_LOCKVAL_SRC_POS);4689 Assert(m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread()); 4670 4690 4671 4691 Medium *pParentBackup = m->pParent; 4672 4673 4692 AssertReturn(getChildren().size() == 0, E_FAIL); 4674 4675 4693 if (m->pParent) 4676 4694 deparent(); … … 4680 4698 { 4681 4699 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 4684 4703 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 4687 4707 case DeviceType_HardDisk: 4688 rc = m->pVirtualBox->unregisterHardDisk(this); 4689 break; 4708 rc = m->pVirtualBox->unregisterHardDisk(this, pfNeedsSaveSettings); 4709 break; 4710 4690 4711 default: 4691 4712 break; 4692 4713 } 4693 4714 … … 4867 4888 /** 4868 4889 * 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 * 4869 4895 * @param task 4870 4896 * @param pvdOperationIfaces … … 4877 4903 PVDINTERFACE vdOperationIfaces = (PVDINTERFACE)pvdOperationIfaces; 4878 4904 4879 /* The lock is also used as a signal from the task initiator (which4880 * releases it only after RTThreadCreate()) that we can start the job */4881 AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);4882 4883 4905 /* these parameters we need after creation */ 4884 4906 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; 4896 4908 4897 4909 try 4898 4910 { 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 4899 4926 PVBOXHDD hdd; 4900 4927 int vrc = VDCreate(m->vdDiskIfaces, &hdd); … … 4948 4975 { 4949 4976 /* 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); 4956 4993 4957 4994 if (SUCCEEDED(rc)) … … 4968 5005 4969 5006 /* reset UUID to prevent it from being reused next time */ 4970 if ( generateUuid)5007 if (fGenerateUuid) 4971 5008 unconst(m->id).clear(); 4972 5009 } … … 4977 5014 /** 4978 5015 * 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 * 4979 5023 * @param task 4980 5024 * @param pvdOperationIfaces … … 4987 5031 PVDINTERFACE vdOperationIfaces = (PVDINTERFACE)pvdOperationIfaces; 4988 5032 5033 bool fNeedsSaveSettings = false; 5034 4989 5035 ComObjPtr<Medium> &pTarget = task.d.target; 4990 5036 4991 /* Lock both in {parent,child} order. The lock is also used as a4992 * signal from the task initiator (which releases it only after4993 * RTThreadCreate()) that we can start the job*/4994 AutoMultiWriteLock2 thisLock(this, pTarget COMMA_LOCKVAL_SRC_POS);4995 4996 5037 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; 5008 5039 5009 5040 try 5010 5041 { 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 5011 5058 PVBOXHDD hdd; 5012 5059 int vrc = VDCreate(m->vdDiskIfaces, &hdd); … … 5027 5074 || m->state == MediumState_LockedWrite); 5028 5075 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(); 5031 5079 5032 5080 try … … 5074 5122 if (SUCCEEDED(rc)) 5075 5123 { 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); 5080 5125 5081 5126 Assert(pTarget->m->pParent.isNull()); … … 5095 5140 * Created state only on success (leaving an orphan file is 5096 5141 * better than breaking media registry consistency) */ 5097 rc = m->pVirtualBox->registerHardDisk(pTarget );5142 rc = m->pVirtualBox->registerHardDisk(pTarget, &fNeedsSaveSettings); 5098 5143 5099 5144 if (FAILED(rc)) … … 5102 5147 } 5103 5148 5104 thisLock.maybeEnter();5149 AutoMultiWriteLock2 mediaLock(this, pTarget COMMA_LOCKVAL_SRC_POS); 5105 5150 5106 5151 if (SUCCEEDED(rc)) … … 5119 5164 5120 5165 /* reset UUID to prevent it from being reused next time */ 5121 if ( generateUuid)5166 if (fGenerateUuid) 5122 5167 unconst(pTarget->m->id).clear(); 5123 5168 } … … 5132 5177 AssertComRC(rc2); 5133 5178 } 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; 5135 5191 5136 5192 /* deregister the task registered in createDiffStorage() */ … … 5146 5202 /** 5147 5203 * 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 * 5148 5211 * @param task 5149 5212 * @param pvdOperationIfaces … … 5182 5245 5183 5246 for (MergeChain::const_iterator it = chain->begin(); 5184 it != chain->end(); ++ it) 5247 it != chain->end(); 5248 ++it) 5185 5249 { 5186 5250 /* complex sanity (sane complexity) */ … … 5201 5265 /* open the first image with VDOPEN_FLAGS_INFO because 5202 5266 * 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 5207 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); 5208 5272 if (RT_FAILURE(vrc)) 5209 5273 throw vrc; … … 5238 5302 { 5239 5303 for (MediaList::const_iterator it = chain->children().begin(); 5240 5241 5304 it != chain->children().end(); 5305 ++it) 5242 5306 { 5243 5307 /* 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); 5248 5313 if (RT_FAILURE(vrc)) 5249 5314 throw vrc; 5250 5315 5251 5316 vrc = VDSetParentUuid(hdd, 1, 5252 5317 chain->target()->m->id); 5253 5318 if (RT_FAILURE(vrc)) 5254 5319 throw vrc; … … 5277 5342 HRESULT rc2; 5278 5343 5279 bool saveSettingsFailed = false;5280 5281 5344 if (SUCCEEDED(rc)) 5282 5345 { … … 5284 5347 * VDMerge; reparent the last one and uninitialize deleted */ 5285 5348 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); 5290 5350 5291 5351 Medium *pSource = chain->source(); … … 5296 5356 /* first, unregister the target since it may become a base 5297 5357 * hard disk which needs re-registration */ 5298 rc2 = pTarget->m->pVirtualBox->unregisterHardDisk(pTarget, false /* aSaveSettings*/);5358 rc2 = m->pVirtualBox->unregisterHardDisk(pTarget, NULL /*&fNeedsSaveSettings*/); 5299 5359 AssertComRC(rc2); 5300 5360 … … 5310 5370 5311 5371 /* then, register again */ 5312 rc2 = pTarget->m->pVirtualBox->registerHardDisk(pTarget, false /* aSaveSettings*/);5372 rc2 = m->pVirtualBox->registerHardDisk(pTarget, NULL /*&fNeedsSaveSettings*/); 5313 5373 AssertComRC(rc2); 5314 5374 } … … 5331 5391 5332 5392 for (MediaList::const_iterator it = children.begin(); 5333 5334 5393 it != children.end(); 5394 ++it) 5335 5395 { 5336 5396 AutoWriteLock childLock(*it COMMA_LOCKVAL_SRC_POS); … … 5344 5404 } 5345 5405 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()) 5356 5412 { 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; 5392 5415 } 5393 5416 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; 5410 5457 5411 5458 if (FAILED(rc)) … … 5424 5471 if (!fIsAsync) 5425 5472 task.d.chain.release(); 5426 5427 NOREF(saveSettingsFailed);5428 5473 } 5429 5474 … … 5433 5478 /** 5434 5479 * 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 * 5435 5483 * @param task 5436 5484 * @param pvdOperationIfaces … … 5446 5494 ComObjPtr<Medium> &pParent = task.d.parentDisk; 5447 5495 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; 5455 5497 5456 5498 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; 5468 5500 5469 5501 try 5470 5502 { 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 5471 5524 PVBOXHDD hdd; 5472 5525 int vrc = VDCreate(m->vdDiskIfaces, &hdd); … … 5546 5599 targetHdd, 5547 5600 targetFormat.c_str(), 5548 pTarget->m->state == MediumState_Creating? targetLocation.raw() : (char *)NULL,5601 (fCreatingTarget) ? targetLocation.raw() : (char *)NULL, 5549 5602 false, 5550 5603 0, … … 5573 5626 5574 5627 /* 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 5614 5662 if (SUCCEEDED(rc)) 5615 5663 { … … 5625 5673 5626 5674 /* reset UUID to prevent it from being reused next time */ 5627 if ( generateUuid)5675 if (fGenerateUuid) 5628 5676 unconst(pTarget->m->id).clear(); 5629 5677 } 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(); 5630 5684 } 5631 5685 … … 5643 5697 /** 5644 5698 * 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 * 5645 5704 * @return 5646 5705 */ … … 5649 5708 HRESULT rc = S_OK; 5650 5709 5651 /* The lock is also used as a signal from the task initiator (which5652 * releases it only after RTThreadCreate()) that we can start the job */5653 AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);5654 5655 5710 try 5656 5711 { 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 5657 5716 PVBOXHDD hdd; 5658 5717 int vrc = VDCreate(m->vdDiskIfaces, &hdd); … … 5664 5723 /* unlock before the potentially lengthy operation */ 5665 5724 Assert(m->state == MediumState_Deleting); 5666 thisLock. leave();5725 thisLock.release(); 5667 5726 5668 5727 try … … 5688 5747 catch (HRESULT aRC) { rc = aRC; } 5689 5748 5690 thisLock.maybeEnter();5749 AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS); 5691 5750 5692 5751 /* go to the NotCreated state even on failure since the storage 5693 5694 5695 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. */ 5696 5755 m->state = MediumState_NotCreated; 5697 5756 … … 5704 5763 /** 5705 5764 * Implementation code called from Medium::taskThread for the "reset" task. 5765 * 5766 * This always gets started asynchronously from Medium::Reset(). 5767 * 5706 5768 * @param task 5707 5769 * @param pvdOperationIfaces … … 5714 5776 PVDINTERFACE vdOperationIfaces = (PVDINTERFACE)pvdOperationIfaces; 5715 5777 5716 /* The lock is also used as a signal from the task initiator (which5717 * 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 reset5721 /// the diff contents but the most efficient way will of course be5722 /// to add a VDResetDiff() API call5723 5724 5778 uint64_t size = 0, logicalSize = 0; 5725 5779 5726 5780 try 5727 5781 { 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 5728 5790 PVBOXHDD hdd; 5729 5791 int vrc = VDCreate(m->vdDiskIfaces, &hdd); … … 5742 5804 5743 5805 /* unlock before the potentially lengthy operation */ 5744 thisLock. leave();5806 thisLock.release(); 5745 5807 5746 5808 try 5747 5809 { 5748 5810 /* 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); 5752 5816 if (RT_SUCCESS(vrc)) 5753 5817 vrc = VDClose(hdd, true /* fDelete */); 5754 5818 5755 5819 if (RT_FAILURE(vrc)) 5756 {5757 5820 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()); 5761 5823 5762 5824 /* 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); 5766 5830 if (RT_FAILURE(vrc)) 5767 {5768 5831 throw setError(E_FAIL, 5769 5832 tr("Could not open the hard disk storage unit '%s'%s"), 5770 5833 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); 5781 5846 if (RT_FAILURE(vrc)) 5782 {5783 5847 throw setError(E_FAIL, 5784 5848 tr("Could not create the differencing hard disk storage unit '%s'%s"), 5785 5849 location.raw(), vdError(vrc).raw()); 5786 }5787 5850 5788 5851 size = VDGetFileSize(hdd, 1); … … 5795 5858 catch (HRESULT aRC) { rc = aRC; } 5796 5859 5797 thisLock.enter();5860 AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS); 5798 5861 5799 5862 m->size = size; -
trunk/src/VBox/Main/SnapshotImpl.cpp
r25860 r25903 1226 1226 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 1227 1227 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); 1230 1232 1231 1233 AssertReturn( !Global::IsOnlineOrTransient(mData->mMachineState) … … 1241 1243 /* save all current settings to ensure current changes are committed and 1242 1244 * hard disks are fixed up */ 1245 alock.release(); 1246 1247 AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS); 1243 1248 HRESULT rc = saveSettings(); 1244 1249 if (FAILED(rc)) return rc; 1250 1251 alock.acquire(); 1245 1252 } 1246 1253 … … 1305 1312 aConsoleProgress, 1306 1313 1, // operation weight; must be the same as in Console::TakeSnapshot() 1307 !!fTakingSnapshotOnline); 1314 !!fTakingSnapshotOnline, 1315 &fNeedsSaveSettings); 1308 1316 if (FAILED(rc)) 1309 1317 throw rc; … … 1320 1328 1); // weight 1321 1329 1322 /* Leave the lock before a lengthy operation (m MachineState is1323 * 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(); 1325 1333 1326 1334 /* copy the state file */ … … 1330 1338 progressCallback, 1331 1339 aConsoleProgress); 1332 alock. enter();1340 alock.acquire(); 1333 1341 1334 1342 if (RT_FAILURE(vrc)) 1335 {1336 1343 /** @todo r=bird: Delete stateTo when appropriate. */ 1337 1344 throw setError(E_FAIL, … … 1340 1347 stateTo.raw(), 1341 1348 vrc); 1342 }1343 1349 } 1344 1350 } … … 1347 1353 LogThisFunc(("Caught %Rhrc [%s]\n", hrc, Global::stringifyMachineState(mData->mMachineState) )); 1348 1354 if ( mSnapshotData.mLastState != mData->mMachineState 1349 && (mSnapshotData.mLastState == MachineState_Running1350 ? mData->mMachineState == MachineState_LiveSnapshotting1351 : mData->mMachineState == MachineState_Saving)1355 && ( mSnapshotData.mLastState == MachineState_Running 1356 ? mData->mMachineState == MachineState_LiveSnapshotting 1357 : mData->mMachineState == MachineState_Saving) 1352 1358 ) 1353 1359 setMachineState(mSnapshotData.mLastState); … … 1359 1365 1360 1366 rc = hrc; 1367 1368 // @todo r=dj what with the implicit diff that we created above? this is never cleaned up 1361 1369 } 1362 1370 … … 1366 1374 *aStateFilePath = NULL; 1367 1375 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 1368 1380 LogFlowThisFunc(("LEAVE - %Rhrc [%s]\n", rc, Global::stringifyMachineState(mData->mMachineState) )); 1369 1381 return rc; … … 1379 1391 * BeginTakingSnapshot() call, to clean up the server side. 1380 1392 * 1381 * @note Locks this object for writing.1393 * @note Locks VirtualBox and this object for writing. 1382 1394 * 1383 1395 * @param aSuccess Whether Console was successful with the client-side snapshot things. … … 1391 1403 AssertComRCReturn (autoCaller.rc(), autoCaller.rc()); 1392 1404 1393 Auto WriteLock alock(this COMMA_LOCKVAL_SRC_POS);1405 AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS); 1394 1406 1395 1407 AssertReturn( !aSuccess 1396 1408 || ( ( mData->mMachineState == MachineState_Saving 1397 ||mData->mMachineState == MachineState_LiveSnapshotting)1398 &&mSnapshotData.mLastState != MachineState_Null1399 &&!mSnapshotData.mSnapshot.isNull()1409 || mData->mMachineState == MachineState_LiveSnapshotting) 1410 && mSnapshotData.mLastState != MachineState_Null 1411 && !mSnapshotData.mSnapshot.isNull() 1400 1412 ) 1401 1413 , E_FAIL); … … 1407 1419 * all to avoid races. 1408 1420 */ 1409 if ( mData->mMachineState != mSnapshotData.mLastState 1410 && mSnapshotData.mLastState != MachineState_Running) 1421 if ( mData->mMachineState != mSnapshotData.mLastState 1422 && mSnapshotData.mLastState != MachineState_Running 1423 ) 1411 1424 setMachineState(mSnapshotData.mLastState); 1412 1413 return endTakingSnapshot(aSuccess);1414 }1415 1416 /**1417 * Internal helper method to finalize taking a snapshot. Gets called from1418 * SessionMachine::EndTakingSnapshot() to finalize the server-side1419 * parts of snapshotting.1420 *1421 * This also gets called from SessionMachine::uninit() if an untaken1422 * snapshot needs cleaning up.1423 *1424 * Expected to be called after completing *all* the tasks related to1425 * 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 lock1440 1441 AssertReturn(!mSnapshotData.mSnapshot.isNull(), E_FAIL);1442 1443 MultiResult rc(S_OK);1444 1425 1445 1426 ComObjPtr<Snapshot> pOldFirstSnap = mData->mFirstSnapshot; … … 1447 1428 1448 1429 bool fOnline = Global::IsOnline(mSnapshotData.mLastState); 1430 1431 HRESULT rc = S_OK; 1449 1432 1450 1433 if (aSuccess) … … 1468 1451 { 1469 1452 /* associate old hard disks with the snapshot and do locking/unlocking*/ 1470 fixupMedia(true /* aCommit */,fOnline);1453 commitMedia(fOnline); 1471 1454 1472 1455 /* inform callbacks */ … … 1478 1461 /* delete all differencing hard disks created (this will also attach 1479 1462 * their parents back by rolling back mMediaData) */ 1480 fixupMedia(false /* aCommit */);1463 rollbackMedia(); 1481 1464 1482 1465 mData->mFirstSnapshot = pOldFirstSnap; // might have been changed above … … 1494 1477 mSnapshotData.mSnapshot.setNull(); 1495 1478 1496 LogFlowThisFuncLeave();1497 1479 return rc; 1498 1480 } … … 1663 1645 } 1664 1646 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 to1669 * provide an AutoWriteLock argument that lets create a non-locking1670 * instance */1671 vboxLock.release();1672 1673 1647 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1674 1648 … … 1682 1656 1683 1657 bool stateRestored = false; 1658 bool fNeedsSaveSettings = false; 1684 1659 1685 1660 try … … 1724 1699 aTask.pProgress, 1725 1700 1, 1726 false /* aOnline */); 1701 false /* aOnline */, 1702 &fNeedsSaveSettings); 1727 1703 if (FAILED(rc)) throw rc; 1728 1704 … … 1809 1785 1810 1786 int saveFlags = 0; 1811 1812 /* @todo saveSettings() below needs a VirtualBox write lock and we need1813 * 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 still1815 * in a protective state which allows us to temporarily leave the lock*/1816 alock.release();1817 vboxLock.acquire();1818 alock.acquire();1819 1787 1820 1788 /* we have already discarded the current state, so set the execution … … 1864 1832 } 1865 1833 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 1866 1843 // save all settings, reset the modified flag and commit; 1867 1844 rc = saveSettings(SaveS_ResetCurStateModified | saveFlags); … … 1877 1854 LogFlowThisFunc(("Deleting old current state in differencing image '%s'\n", pMedium->getName().raw())); 1878 1855 1879 HRESULT rc2 = pMedium->deleteStorageAndWait( );1856 HRESULT rc2 = pMedium->deleteStorageAndWait(NULL /*aProgress*/, NULL /*pfNeedsSaveSettings*/ ); 1880 1857 // ignore errors here because we cannot roll back after saveSettings() above 1881 1858 if (SUCCEEDED(rc2)) … … 2144 2121 MediumDiscardRecList toDiscard; 2145 2122 2146 bool settingsChanged = false; 2123 bool fMachineSettingsChanged = false; // Machine 2124 bool fNeedsSaveSettings = false; // VirtualBox.xml 2147 2125 2148 2126 try … … 2306 2284 /// @todo NEWMEDIA maybe save everything in one operation in place of 2307 2285 /// saveSnapshotSettings() above 2308 settingsChanged = true;2286 fMachineSettingsChanged = true; 2309 2287 2310 2288 /* third pass: */ … … 2323 2301 rc = it->hd->discard(aTask.pProgress, 2324 2302 (ULONG)(it->hd->getSize() / _1M), // weight 2325 it->chain); 2303 it->chain, 2304 &fNeedsSaveSettings); 2326 2305 if (FAILED(rc)) throw rc; 2327 2306 … … 2376 2355 updateMachineStateOnClient(); 2377 2356 2378 if ( settingsChanged)2357 if (fMachineSettingsChanged || fNeedsSaveSettings) 2379 2358 { 2380 2359 // saveSettings needs VirtualBox write lock in addition to our own 2381 2360 // (parent -> child locking order!) 2382 2361 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(); 2386 2371 } 2387 2372 } -
trunk/src/VBox/Main/VirtualBoxImpl.cpp
r25894 r25903 520 520 HRESULT VirtualBox::initMedia() 521 521 { 522 AutoWriteLock treeLock(getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 523 522 524 HRESULT rc = S_OK; 523 525 settings::MediaList::const_iterator it; … … 536 538 if (FAILED(rc)) return rc; 537 539 538 rc = registerHardDisk(pHardDisk, false /* aSaveRegistry */);540 rc = registerHardDisk(pHardDisk, NULL /*pfNeedsSaveSettings*/ ); 539 541 if (FAILED(rc)) return rc; 540 542 } … … 551 553 if (FAILED(rc)) return rc; 552 554 553 rc = registerImage(pImage, DeviceType_DVD, false /* aSaveRegistry */);555 rc = registerImage(pImage, DeviceType_DVD, NULL /*pfNeedsSaveSettings*/ ); 554 556 if (FAILED(rc)) return rc; 555 557 } … … 566 568 if (FAILED(rc)) return rc; 567 569 568 rc = registerImage(pImage, DeviceType_Floppy, false /* aSaveRegistry */);570 rc = registerImage(pImage, DeviceType_Floppy, NULL /*pfNeedsSaveSettings*/ ); 569 571 if (FAILED(rc)) return rc; 570 572 } … … 1319 1321 HRESULT rc = E_FAIL; 1320 1322 1323 bool fNeedsSaveSettings = false; 1324 1321 1325 ComObjPtr<Medium> hardDisk; 1322 1326 hardDisk.createObject(); 1323 rc = hardDisk->init(this, format.raw(), aLocation );1327 rc = hardDisk->init(this, format.raw(), aLocation, &fNeedsSaveSettings); 1324 1328 1325 1329 if (SUCCEEDED(rc)) 1326 1330 hardDisk.queryInterfaceTo(aHardDisk); 1331 1332 if (fNeedsSaveSettings) 1333 { 1334 AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS); 1335 saveSettings(); 1336 } 1327 1337 1328 1338 return rc; … … 1362 1372 (accessMode == AccessMode_ReadWrite) ? Medium::OpenReadWrite : Medium::OpenReadOnly, 1363 1373 DeviceType_HardDisk, 1364 aSetImageId, imageId, 1365 aSetParentId, parentId); 1374 aSetImageId, 1375 imageId, 1376 aSetParentId, 1377 parentId); 1366 1378 1367 1379 if (SUCCEEDED(rc)) 1368 1380 { 1369 rc = registerHardDisk (hardDisk); 1381 bool fNeedsSaveSettings = false; 1382 rc = registerHardDisk(hardDisk, &fNeedsSaveSettings); 1370 1383 1371 1384 /* Note that it's important to call uninit() on failure to register … … 1377 1390 else 1378 1391 hardDisk->uninit(); 1392 1393 if (fNeedsSaveSettings) 1394 { 1395 AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS); 1396 saveSettings(); 1397 } 1379 1398 } 1380 1399 … … 1440 1459 if (SUCCEEDED(rc)) 1441 1460 { 1442 rc = registerImage(image, DeviceType_DVD); 1461 bool fNeedsSaveSettings = false; 1462 rc = registerImage(image, DeviceType_DVD, &fNeedsSaveSettings); 1443 1463 1444 1464 if (SUCCEEDED(rc)) 1445 1465 image.queryInterfaceTo(aDVDImage); 1466 1467 if (fNeedsSaveSettings) 1468 { 1469 AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS); 1470 saveSettings(); 1471 } 1446 1472 } 1447 1473 … … 1507 1533 if (SUCCEEDED(rc)) 1508 1534 { 1509 rc = registerImage(image, DeviceType_Floppy); 1535 bool fNeedsSaveSettings = false; 1536 rc = registerImage(image, DeviceType_Floppy, &fNeedsSaveSettings); 1510 1537 1511 1538 if (SUCCEEDED(rc)) 1512 1539 image.queryInterfaceTo(aFloppyImage); 1540 1541 if (fNeedsSaveSettings) 1542 { 1543 AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS); 1544 saveSettings(); 1545 } 1513 1546 } 1514 1547 … … 2766 2799 * @return S_OK when found or E_INVALIDARG when not found. 2767 2800 * 2768 * @note Locks th is object and hard disk objectsfor reading.2801 * @note Locks the media tree for reading. 2769 2802 */ 2770 2803 HRESULT VirtualBox::findHardDisk(const Guid *aId, … … 2847 2880 * @return S_OK when found or E_INVALIDARG when not found. 2848 2881 * 2849 * @note Locks th is object and image objectsfor reading.2882 * @note Locks the media tree for reading. 2850 2883 */ 2851 2884 HRESULT VirtualBox::findDVDImage(const Guid *aId, … … 2925 2958 * @return S_OK when found or E_INVALIDARG when not found. 2926 2959 * 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 */ 2962 HRESULT VirtualBox::findFloppyImage(const Guid *aId, 2963 CBSTR aLocation, 2930 2964 bool aSetError, 2931 2965 ComObjPtr<Medium> *aImage /* = NULL */) … … 3144 3178 * @param aConflict Where to return parameters of the conflicting medium. 3145 3179 * 3146 * @note Locks th is objectand media objects for reading.3180 * @note Locks the media tree and media objects for reading. 3147 3181 */ 3148 3182 HRESULT VirtualBox::checkMediaForConflicts2(const Guid &aId, … … 3154 3188 AssertReturn(!aId.isEmpty() && !aLocation.isEmpty(), E_FAIL); 3155 3189 3156 AutoReadLock alock( thisCOMMA_LOCKVAL_SRC_POS);3190 AutoReadLock alock(getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 3157 3191 3158 3192 HRESULT rc = S_OK; … … 3176 3210 { 3177 3211 ComObjPtr<Medium> image; 3178 rc = findDVDImage 3212 rc = findDVDImage(&aId, bstrLocation, false /* aSetError */, &image); 3179 3213 if (SUCCEEDED(rc)) 3180 3214 { … … 3394 3428 * 3395 3429 * @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 3406 3434 */ 3407 3435 HRESULT VirtualBox::registerHardDisk(Medium *aHardDisk, 3408 bool aSaveRegistry /*= true*/)3436 bool *pfNeedsSaveSettings) 3409 3437 { 3410 3438 AssertReturn(aHardDisk != NULL, E_INVALIDARG); … … 3415 3443 AutoCaller hardDiskCaller(aHardDisk); 3416 3444 AssertComRCReturn(hardDiskCaller.rc(), hardDiskCaller.rc()); 3445 3446 // caller must hold the media tree write lock 3447 Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread()); 3417 3448 3418 3449 Guid id; … … 3427 3458 3428 3459 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; 3461 3485 3462 3486 return rc; … … 3467 3491 * 3468 3492 * @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 3479 3497 */ 3480 3498 HRESULT VirtualBox::unregisterHardDisk(Medium *aHardDisk, 3481 bool aSaveRegistry /*= true*/)3499 bool *pfNeedsSaveSettings) 3482 3500 { 3483 3501 AssertReturn(aHardDisk != NULL, E_INVALIDARG); … … 3488 3506 AutoCaller hardDiskCaller (aHardDisk); 3489 3507 AssertComRCReturn(hardDiskCaller.rc(), hardDiskCaller.rc()); 3508 3509 // caller must hold the media tree write lock 3510 Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread()); 3490 3511 3491 3512 Guid id; … … 3497 3518 } 3498 3519 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; 3524 3534 } 3525 3535 … … 3529 3539 * @param argImage Image object to remember. 3530 3540 * @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 3541 3545 */ 3542 3546 HRESULT VirtualBox::registerImage(Medium *argImage, 3543 3547 DeviceType_T argType, 3544 bool argSaveRegistry /*= true*/)3548 bool *pfNeedsSaveSettings) 3545 3549 { 3546 3550 AssertReturn(argImage != NULL, E_INVALIDARG); … … 3551 3555 AutoCaller imageCaller(argImage); 3552 3556 AssertComRCReturn(imageCaller.rc(), imageCaller.rc()); 3557 3558 // caller must hold the media tree write lock 3559 Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread()); 3553 3560 3554 3561 Guid id; … … 3566 3573 3567 3574 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; 3597 3598 3598 3599 return rc; … … 3604 3605 * @param argImage Image object to remove. 3605 3606 * @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 3616 3611 */ 3617 3612 HRESULT VirtualBox::unregisterImage(Medium *argImage, 3618 3613 DeviceType_T argType, 3619 bool argSaveRegistry /*= true*/)3614 bool *pfNeedsSaveSettings) 3620 3615 { 3621 3616 AssertReturn(argImage != NULL, E_INVALIDARG); … … 3626 3621 AutoCaller imageCaller(argImage); 3627 3622 AssertComRCReturn(imageCaller.rc(), imageCaller.rc()); 3623 3624 // caller must hold the media tree write lock 3625 Assert(getMediaTreeLockHandle().isWriteLockOnCurrentThread()); 3628 3626 3629 3627 Guid id; … … 3638 3636 ObjectsList<Medium> &oll = (argType == DeviceType_DVD) ? m->ollDVDImages : m->ollFloppyImages; 3639 3637 3640 oll.removeChild(argImage); 3638 // access the list directly because the caller must have requested the lock 3639 oll.getList().remove(argImage); 3641 3640 3642 3641 HRESULT rc = S_OK; 3643 3642 3644 if (argSaveRegistry) 3645 { 3646 rc = saveSettings(); 3647 if (FAILED(rc)) 3648 registerImage(argImage, argType, false /* aSaveRegistry */); 3649 } 3643 if (pfNeedsSaveSettings) 3644 *pfNeedsSaveSettings = true; 3650 3645 3651 3646 return rc; … … 3779 3774 3780 3775 /** 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 */ 3783 RWLockHandle& VirtualBox::getMediaTreeLockHandle() 3784 { 3785 return m->lockMedia; 3797 3786 } 3798 3787 -
trunk/src/VBox/Main/include/MachineImpl.h
r25901 r25903 889 889 IProgress *aProgress, 890 890 ULONG aWeight, 891 bool aOnline); 892 HRESULT deleteImplicitDiffs(); 891 bool aOnline, 892 bool *pfNeedsSaveSettings); 893 HRESULT deleteImplicitDiffs(bool *pfNeedsSaveSettings); 893 894 894 895 MediumAttachment* findAttachment(const MediaData::AttachmentList &ll, … … 901 902 Guid &id); 902 903 903 void fixupMedia(bool aCommit, bool aOnline = false); 904 void commitMedia(bool aOnline = false); 905 void rollbackMedia(); 904 906 905 907 bool isInOwnDir(Utf8Str *aSettingsDir = NULL); … … 1088 1090 1089 1091 HRESULT endSavingState(BOOL aSuccess); 1090 HRESULT endTakingSnapshot(BOOL aSuccess);1091 1092 1092 1093 typedef std::map<ComObjPtr<Machine>, MachineState_T> AffectedMachines; -
trunk/src/VBox/Main/include/MediumImpl.h
r25888 r25903 78 78 HRESULT init(VirtualBox *aVirtualBox, 79 79 CBSTR aFormat, 80 CBSTR aLocation); 80 CBSTR aLocation, 81 bool *pfNeedsSaveSettings); 81 82 HRESULT init(VirtualBox *aVirtualBox, 82 83 CBSTR aLocation, … … 193 194 */ 194 195 HRESULT deleteStorageNoWait(ComObjPtr<Progress> &aProgress) 195 { return deleteStorage(&aProgress, false /* aWait */ ); }196 { return deleteStorage(&aProgress, false /* aWait */, NULL /* pfNeedsSaveSettings */); } 196 197 197 198 /** … … 199 200 * blocking the current thread. 200 201 */ 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); } 203 204 204 205 /** … … 209 210 MediumVariant_T aVariant, 210 211 ComObjPtr<Progress> &aProgress) 211 { return createDiffStorage(aTarget, aVariant, &aProgress, false /* aWait */ ); }212 { return createDiffStorage(aTarget, aVariant, &aProgress, false /* aWait */, NULL /* pfNeedsSaveSettings*/ ); } 212 213 213 214 /** … … 217 218 HRESULT createDiffStorageAndWait(ComObjPtr<Medium> &aTarget, 218 219 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); } 221 222 222 223 HRESULT prepareMergeTo(Medium *aTarget, MergeChain * &aChain, … … 229 230 HRESULT mergeToNoWait(MergeChain *aChain, 230 231 ComObjPtr<Progress> &aProgress) 231 { return mergeTo(aChain, &aProgress, false /* aWait */ ); }232 { return mergeTo(aChain, &aProgress, false /* aWait */, NULL /*pfNeedsSaveSettings*/); } 232 233 233 234 /** … … 236 237 */ 237 238 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); } 240 242 241 243 void cancelMergeTo(MergeChain *aChain); … … 244 246 245 247 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); 247 249 void cancelDiscard(MergeChain *aChain); 248 250 … … 273 275 * this object's AutoMayUninitSpan and from under mVirtualBox write lock. 274 276 */ 275 HRESULT unregisterWithVirtualBox( );277 HRESULT unregisterWithVirtualBox(bool *pfNeedsSaveSettings); 276 278 277 279 HRESULT setStateError(); 278 280 279 HRESULT deleteStorage(ComObjPtr<Progress> *aProgress, bool aWait );281 HRESULT deleteStorage(ComObjPtr<Progress> *aProgress, bool aWait, bool *pfNeedsSaveSettings); 280 282 281 283 HRESULT createDiffStorage(ComObjPtr<Medium> &aTarget, 282 284 MediumVariant_T aVariant, 283 285 ComObjPtr<Progress> *aProgress, 284 bool aWait); 286 bool aWait, 287 bool *pfNeedsSaveSettings); 285 288 286 289 HRESULT mergeTo(MergeChain *aChain, 287 290 ComObjPtr<Progress> *aProgress, 288 bool aWait); 291 bool aWait, 292 bool *pfNeedsSaveSettings); 289 293 290 294 HRESULT setLocation(const Utf8Str &aLocation, const Utf8Str &aFormat = Utf8Str()); -
trunk/src/VBox/Main/include/VirtualBoxImpl.h
r25834 r25903 274 274 void calculateRelativePath(const Utf8Str &strPath, Utf8Str &aResult); 275 275 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); 281 281 282 282 HRESULT saveSettings(); … … 289 289 const Utf8Str& settingsFilePath(); 290 290 291 RWLockHandle& hardDiskTreeLockHandle();291 RWLockHandle& getMediaTreeLockHandle(); 292 292 293 293 /* for VirtualBoxSupportErrorInfoImpl */
Note:
See TracChangeset
for help on using the changeset viewer.