- 時間撮記:
- 2015-4-13 下午03:53:01 (10 年 以前)
- 檔案:
-
- 修改 1 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
r55185 r55214 164 164 mProgress(aProgress), 165 165 mServerProgress(aServerProgress), 166 mpUVM(NULL),167 166 mRC(E_FAIL), 168 167 mpSafeVMPtr(NULL) … … 175 174 { 176 175 mpSafeVMPtr = new Console::SafeVMPtr(aConsole); 177 if (mpSafeVMPtr->isOk()) 178 mpUVM = mpSafeVMPtr->rawUVM(); 179 else 176 if (!mpSafeVMPtr->isOk()) 180 177 mRC = mpSafeVMPtr->rc(); 181 178 } … … 205 202 Utf8Str mErrorMsg; 206 203 const ComPtr<IProgress> mServerProgress; 207 PUVM mpUVM;208 204 209 205 private: … … 212 208 }; 213 209 214 struct VMTakeSnapshotTask : public VMTask215 {216 VMTakeSnapshotTask(Console *aConsole,217 Progress *aProgress,218 IN_BSTR aName,219 IN_BSTR aDescription)220 : VMTask(aConsole, aProgress, NULL /* aServerProgress */,221 false /* aUsesVMPtr */),222 bstrName(aName),223 bstrDescription(aDescription),224 lastMachineState(MachineState_Null)225 {}226 227 Bstr bstrName,228 bstrDescription;229 Bstr bstrSavedStateFile; // received from BeginTakeSnapshot()230 MachineState_T lastMachineState;231 bool fTakingSnapshotOnline;232 ULONG ulMemSize;233 };234 210 235 211 struct VMPowerUpTask : public VMTask … … 264 240 true /* aUsesVMPtr */) 265 241 {} 266 };267 268 struct VMSaveTask : public VMTask269 {270 VMSaveTask(Console *aConsole,271 const ComPtr<IProgress> &aServerProgress,272 const Utf8Str &aSavedStateFile,273 MachineState_T aMachineStateBefore,274 Reason_T aReason)275 : VMTask(aConsole, NULL /* aProgress */, aServerProgress,276 true /* aUsesVMPtr */),277 mSavedStateFile(aSavedStateFile),278 mMachineStateBefore(aMachineStateBefore),279 mReason(aReason)280 {}281 282 Utf8Str mSavedStateFile;283 /* The local machine state we had before. Required if something fails */284 MachineState_T mMachineStateBefore;285 /* The reason for saving state */286 Reason_T mReason;287 242 }; 288 243 … … 597 552 meAttachmentType[slot] = NetworkAttachmentType_Null; 598 553 599 // VirtualBox 4.0: We no longer initialize the VMMDev instance here,600 // which starts the HGCM thread. Instead, this is now done in the601 // power-up thread when a VM is actually being powered up to avoid602 // having HGCM threads all over the place every time a session is603 // opened, even if that session will not run a VM.604 // unconst(m_pVMMDev) = new VMMDev(this);605 // AssertReturn(mVMMDev, E_FAIL);606 607 554 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER 608 555 unconst(mAudioVRDE) = new AudioVRDE(this); … … 2106 2053 HRESULT Console::powerUp(ComPtr<IProgress> &aProgress) 2107 2054 { 2108 ComObjPtr<IProgress> pProgress; 2109 i_powerUp(pProgress.asOutParam(), false /* aPaused */); 2110 pProgress.queryInterfaceTo(aProgress.asOutParam()); 2055 i_powerUp(aProgress.asOutParam(), false /* aPaused */); 2111 2056 return S_OK; 2112 2057 } … … 2114 2059 HRESULT Console::powerUpPaused(ComPtr<IProgress> &aProgress) 2115 2060 { 2116 ComObjPtr<IProgress> pProgress; 2117 i_powerUp(pProgress.asOutParam(), true /* aPaused */); 2118 pProgress.queryInterfaceTo(aProgress.asOutParam()); 2061 i_powerUp(aProgress.asOutParam(), true /* aPaused */); 2119 2062 return S_OK; 2120 2063 } … … 2133 2076 case MachineState_Stuck: 2134 2077 break; 2078 2079 /* Try cancel the save state. */ 2080 case MachineState_Saving: 2081 if (!mptrCancelableProgress.isNull()) 2082 { 2083 HRESULT hrc = mptrCancelableProgress->Cancel(); 2084 if (SUCCEEDED(hrc)) 2085 break; 2086 } 2087 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point during a save state")); 2135 2088 2136 2089 /* Try cancel the teleportation. */ … … 2145 2098 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point in a teleportation")); 2146 2099 2100 /* Try cancel the online snapshot. */ 2101 case MachineState_OnlineSnapshotting: 2102 if (!mptrCancelableProgress.isNull()) 2103 { 2104 HRESULT hrc = mptrCancelableProgress->Cancel(); 2105 if (SUCCEEDED(hrc)) 2106 break; 2107 } 2108 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point in an online snapshot")); 2109 2147 2110 /* Try cancel the live snapshot. */ 2148 2111 case MachineState_LiveSnapshotting: … … 2539 2502 LogFlowThisFuncEnter(); 2540 2503 2541 HRESULT rc = i_resume(Reason_Unspecified); 2504 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2505 2506 if (mMachineState != MachineState_Paused) 2507 return setError(VBOX_E_INVALID_VM_STATE, 2508 tr("Cannot resume the machine as it is not paused (machine state: %s)"), 2509 Global::stringifyMachineState(mMachineState)); 2510 2511 HRESULT rc = i_resume(Reason_Unspecified, alock); 2542 2512 2543 2513 LogFlowThisFunc(("rc=%Rhrc\n", rc)); … … 2720 2690 LogFlowThisFunc(("rc=%Rhrc\n", rc)); 2721 2691 LogFlowThisFuncLeave(); 2722 return rc;2723 }2724 2725 HRESULT Console::saveState(ComPtr<IProgress> &aProgress)2726 {2727 LogFlowThisFuncEnter();2728 ComObjPtr<IProgress> pProgress;2729 2730 HRESULT rc = i_saveState(Reason_Unspecified, pProgress.asOutParam());2731 pProgress.queryInterfaceTo(aProgress.asOutParam());2732 2733 LogFlowThisFunc(("rc=%Rhrc\n", rc));2734 LogFlowThisFuncLeave();2735 return rc;2736 }2737 2738 HRESULT Console::adoptSavedState(const com::Utf8Str &aSavedStateFile)2739 {2740 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);2741 2742 if ( mMachineState != MachineState_PoweredOff2743 && mMachineState != MachineState_Teleported2744 && mMachineState != MachineState_Aborted2745 )2746 return setError(VBOX_E_INVALID_VM_STATE,2747 tr("Cannot adopt the saved machine state as the machine is not in Powered Off, Teleported or Aborted state (machine state: %s)"),2748 Global::stringifyMachineState(mMachineState));2749 2750 return mControl->AdoptSavedState(Bstr(aSavedStateFile.c_str()).raw());2751 }2752 2753 HRESULT Console::discardSavedState(BOOL aFRemoveFile)2754 {2755 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);2756 2757 if (mMachineState != MachineState_Saved)2758 return setError(VBOX_E_INVALID_VM_STATE,2759 tr("Cannot delete the machine state as the machine is not in the saved state (machine state: %s)"),2760 Global::stringifyMachineState(mMachineState));2761 2762 HRESULT rc = mControl->SetRemoveSavedStateFile(aFRemoveFile);2763 if (FAILED(rc)) return rc;2764 2765 /*2766 * Saved -> PoweredOff transition will be detected in the SessionMachine2767 * and properly handled.2768 */2769 rc = i_setMachineState(MachineState_PoweredOff);2770 2771 2692 return rc; 2772 2693 } … … 3155 3076 3156 3077 return rc; 3157 }3158 3159 HRESULT Console::takeSnapshot(const com::Utf8Str &aName,3160 const com::Utf8Str &aDescription,3161 ComPtr<IProgress> &aProgress)3162 {3163 LogFlowThisFuncEnter();3164 3165 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);3166 LogFlowThisFunc(("aName='%s' mMachineState=%d\n", aName.c_str(), mMachineState));3167 3168 if (Global::IsTransient(mMachineState))3169 return setError(VBOX_E_INVALID_VM_STATE,3170 tr("Cannot take a snapshot of the machine while it is changing the state (machine state: %s)"),3171 Global::stringifyMachineState(mMachineState));3172 3173 HRESULT rc = S_OK;3174 3175 /* prepare the progress object:3176 a) count the no. of hard disk attachments to get a matching no. of progress sub-operations */3177 ULONG cOperations = 2; // always at least setting up + finishing up3178 ULONG ulTotalOperationsWeight = 2; // one each for setting up + finishing up3179 SafeIfaceArray<IMediumAttachment> aMediumAttachments;3180 rc = mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aMediumAttachments));3181 if (FAILED(rc))3182 return setError(rc, tr("Cannot get medium attachments of the machine"));3183 3184 ULONG ulMemSize;3185 rc = mMachine->COMGETTER(MemorySize)(&ulMemSize);3186 if (FAILED(rc))3187 return rc;3188 3189 for (size_t i = 0;3190 i < aMediumAttachments.size();3191 ++i)3192 {3193 DeviceType_T type;3194 rc = aMediumAttachments[i]->COMGETTER(Type)(&type);3195 if (FAILED(rc))3196 return rc;3197 3198 if (type == DeviceType_HardDisk)3199 {3200 ++cOperations;3201 3202 // assume that creating a diff image takes as long as saving a 1MB state3203 // (note, the same value must be used in SessionMachine::BeginTakingSnapshot() on the server!)3204 ulTotalOperationsWeight += 1;3205 }3206 }3207 3208 // b) one extra sub-operations for online snapshots OR offline snapshots that have a saved state (needs to be copied)3209 bool const fTakingSnapshotOnline = Global::IsOnline(mMachineState);3210 3211 LogFlowFunc(("fTakingSnapshotOnline = %d, mMachineState = %d\n", fTakingSnapshotOnline, mMachineState));3212 3213 if (fTakingSnapshotOnline)3214 {3215 ++cOperations;3216 ulTotalOperationsWeight += ulMemSize;3217 }3218 3219 // finally, create the progress object3220 ComObjPtr<Progress> pProgress;3221 pProgress.createObject();3222 rc = pProgress->init(static_cast<IConsole *>(this),3223 Bstr(tr("Taking a snapshot of the virtual machine")).raw(),3224 (mMachineState >= MachineState_FirstOnline)3225 && (mMachineState <= MachineState_LastOnline) /* aCancelable */,3226 cOperations,3227 ulTotalOperationsWeight,3228 Bstr(tr("Setting up snapshot operation")).raw(), // first sub-op description3229 1); // ulFirstOperationWeight3230 3231 if (FAILED(rc))3232 return rc;3233 3234 VMTakeSnapshotTask *pTask;3235 if (!(pTask = new VMTakeSnapshotTask(this, pProgress, Bstr(aName).raw(), Bstr(aDescription).raw())))3236 return E_OUTOFMEMORY;3237 3238 Assert(pTask->mProgress);3239 3240 try3241 {3242 mptrCancelableProgress = pProgress;3243 3244 /*3245 * If we fail here it means a PowerDown() call happened on another3246 * thread while we were doing Pause() (which releases the Console lock).3247 * We assign PowerDown() a higher precedence than TakeSnapshot(),3248 * therefore just return the error to the caller.3249 */3250 rc = pTask->rc();3251 if (FAILED(rc)) throw rc;3252 3253 pTask->ulMemSize = ulMemSize;3254 3255 /* memorize the current machine state */3256 pTask->lastMachineState = mMachineState;3257 pTask->fTakingSnapshotOnline = fTakingSnapshotOnline;3258 3259 int vrc = RTThreadCreate(NULL,3260 Console::i_fntTakeSnapshotWorker,3261 (void *)pTask,3262 0,3263 RTTHREADTYPE_MAIN_WORKER,3264 0,3265 "TakeSnap");3266 if (FAILED(vrc))3267 throw setError(E_FAIL,3268 tr("Could not create VMTakeSnap thread (%Rrc)"),3269 vrc);3270 3271 pTask->mProgress.queryInterfaceTo(aProgress.asOutParam());3272 }3273 catch (HRESULT erc)3274 {3275 delete pTask;3276 rc = erc;3277 mptrCancelableProgress.setNull();3278 }3279 3280 LogFlowThisFunc(("rc=%Rhrc\n", rc));3281 LogFlowThisFuncLeave();3282 return rc;3283 }3284 3285 HRESULT Console::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress)3286 {3287 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);3288 3289 if (Global::IsTransient(mMachineState))3290 return setError(VBOX_E_INVALID_VM_STATE,3291 tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),3292 Global::stringifyMachineState(mMachineState));3293 ComObjPtr<IProgress> iProgress;3294 MachineState_T machineState = MachineState_Null;3295 HRESULT rc = mControl->DeleteSnapshot((IConsole *)this, Bstr(aId.toString()).raw(), Bstr(aId.toString()).raw(),3296 FALSE /* fDeleteAllChildren */, &machineState, iProgress.asOutParam());3297 if (FAILED(rc)) return rc;3298 iProgress.queryInterfaceTo(aProgress.asOutParam());3299 3300 i_setMachineStateLocally(machineState);3301 return S_OK;3302 }3303 3304 HRESULT Console::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress)3305 3306 {3307 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);3308 3309 if (Global::IsTransient(mMachineState))3310 return setError(VBOX_E_INVALID_VM_STATE,3311 tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),3312 Global::stringifyMachineState(mMachineState));3313 3314 ComObjPtr<IProgress> iProgress;3315 MachineState_T machineState = MachineState_Null;3316 HRESULT rc = mControl->DeleteSnapshot((IConsole *)this, Bstr(aId.toString()).raw(), Bstr(aId.toString()).raw(),3317 TRUE /* fDeleteAllChildren */, &machineState, iProgress.asOutParam());3318 if (FAILED(rc)) return rc;3319 iProgress.queryInterfaceTo(aProgress.asOutParam());3320 3321 i_setMachineStateLocally(machineState);3322 return S_OK;3323 }3324 3325 HRESULT Console::deleteSnapshotRange(const com::Guid &aStartId, const com::Guid &aEndId, ComPtr<IProgress> &aProgress)3326 {3327 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);3328 3329 if (Global::IsTransient(mMachineState))3330 return setError(VBOX_E_INVALID_VM_STATE,3331 tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),3332 Global::stringifyMachineState(mMachineState));3333 3334 ComObjPtr<IProgress> iProgress;3335 MachineState_T machineState = MachineState_Null;3336 HRESULT rc = mControl->DeleteSnapshot((IConsole *)this, Bstr(aStartId.toString()).raw(), Bstr(aEndId.toString()).raw(),3337 FALSE /* fDeleteAllChildren */, &machineState, iProgress.asOutParam());3338 if (FAILED(rc)) return rc;3339 iProgress.queryInterfaceTo(aProgress.asOutParam());3340 3341 i_setMachineStateLocally(machineState);3342 return S_OK;3343 }3344 3345 HRESULT Console::restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot, ComPtr<IProgress> &aProgress)3346 {3347 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);3348 3349 if (Global::IsOnlineOrTransient(mMachineState))3350 return setError(VBOX_E_INVALID_VM_STATE,3351 tr("Cannot delete the current state of the running machine (machine state: %s)"),3352 Global::stringifyMachineState(mMachineState));3353 3354 ISnapshot* iSnapshot = aSnapshot;3355 ComObjPtr<IProgress> iProgress;3356 MachineState_T machineState = MachineState_Null;3357 HRESULT rc = mControl->RestoreSnapshot((IConsole*)this, iSnapshot, &machineState, iProgress.asOutParam());3358 if (FAILED(rc)) return rc;3359 iProgress.queryInterfaceTo(aProgress.asOutParam());3360 3361 i_setMachineStateLocally(machineState);3362 return S_OK;3363 3078 } 3364 3079 … … 3645 3360 getStaticComponentName(), 3646 3361 Utf8StrFmt("Invalid state '%s' for changing medium", 3647 VMR3GetStateName(enmVMState)),3362 VMR3GetStateName(enmVMState)), 3648 3363 false /*aWarning*/, 3649 3364 true /*aLogIt*/); … … 6219 5934 6220 5935 /* We will need to release the lock before doing the actual merge */ 6221 Auto ReadLock alock(this COMMA_LOCKVAL_SRC_POS);5936 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 6222 5937 6223 5938 /* paranoia - we don't want merges to happen while teleporting etc. */ … … 6295 6010 AssertComRCReturnRC(rc); 6296 6011 6012 Assert(mMachineState == MachineState_DeletingSnapshotOnline); 6013 6014 /* Pause the VM, as it might have pending IO on this drive */ 6015 bool fResume = false; 6016 rc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), &alock, &fResume); 6017 if (FAILED(rc)) 6018 return rc; 6019 6297 6020 alock.release(); 6298 6299 /* Pause the VM, as it might have pending IO on this drive */6300 VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM());6301 if (mMachineState == MachineState_DeletingSnapshotOnline)6302 {6303 LogFlowFunc(("Suspending the VM...\n"));6304 /* disable the callback to prevent Console-level state change */6305 mVMStateChangeCallbackDisabled = true;6306 int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG);6307 mVMStateChangeCallbackDisabled = false;6308 AssertRCReturn(vrc2, E_FAIL);6309 }6310 6311 6021 vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, 6312 6022 (PFNRT)i_reconfigureMediumAttachment, 13, … … 6316 6026 /* error handling is after resuming the VM */ 6317 6027 6318 if (mMachineState == MachineState_DeletingSnapshotOnline) 6319 { 6320 LogFlowFunc(("Resuming the VM...\n")); 6321 /* disable the callback to prevent Console-level state change */ 6322 mVMStateChangeCallbackDisabled = true; 6323 int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG); 6324 mVMStateChangeCallbackDisabled = false; 6325 if (RT_FAILURE(vrc2)) 6326 { 6327 /* too bad, we failed. try to sync the console state with the VMM state */ 6328 AssertLogRelRC(vrc2); 6329 i_vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this); 6330 } 6331 } 6028 if (fResume) 6029 i_resumeAfterConfigChange(ptrVM.rawUVM()); 6332 6030 6333 6031 if (RT_FAILURE(vrc)) … … 6356 6054 return setError(E_FAIL, tr("Failed to perform an online medium merge (%Rrc)"), vrc); 6357 6055 6056 alock.acquire(); 6358 6057 /* Pause the VM, as it might have pending IO on this drive */ 6359 enmVMState = VMR3GetStateU(ptrVM.rawUVM()); 6360 if (mMachineState == MachineState_DeletingSnapshotOnline) 6361 { 6362 LogFlowFunc(("Suspending the VM...\n")); 6363 /* disable the callback to prevent Console-level state change */ 6364 mVMStateChangeCallbackDisabled = true; 6365 int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG); 6366 mVMStateChangeCallbackDisabled = false; 6367 AssertRCReturn(vrc2, E_FAIL); 6368 } 6058 rc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), &alock, &fResume); 6059 if (FAILED(rc)) 6060 return rc; 6061 alock.release(); 6369 6062 6370 6063 /* Update medium chain and state now, so that the VM can continue. */ … … 6378 6071 /* error handling is after resuming the VM */ 6379 6072 6380 if (mMachineState == MachineState_DeletingSnapshotOnline) 6381 { 6382 LogFlowFunc(("Resuming the VM...\n")); 6383 /* disable the callback to prevent Console-level state change */ 6384 mVMStateChangeCallbackDisabled = true; 6385 int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG); 6386 mVMStateChangeCallbackDisabled = false; 6387 AssertRC(vrc2); 6388 if (RT_FAILURE(vrc2)) 6389 { 6390 /* too bad, we failed. try to sync the console state with the VMM state */ 6391 i_vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this); 6392 } 6393 } 6073 if (fResume) 6074 i_resumeAfterConfigChange(ptrVM.rawUVM()); 6394 6075 6395 6076 if (RT_FAILURE(vrc)) … … 6397 6078 if (FAILED(rc)) 6398 6079 return rc; 6080 6081 return rc; 6082 } 6083 6084 HRESULT Console::i_reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments) 6085 { 6086 HRESULT rc = S_OK; 6087 6088 AutoCaller autoCaller(this); 6089 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 6090 6091 /* get the VM handle. */ 6092 SafeVMPtr ptrVM(this); 6093 if (!ptrVM.isOk()) 6094 return ptrVM.rc(); 6095 6096 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 6097 6098 for (size_t i = 0; i < aAttachments.size(); ++i) 6099 { 6100 ComPtr<IStorageController> pStorageController; 6101 Bstr controllerName; 6102 ULONG lInstance; 6103 StorageControllerType_T enmController; 6104 StorageBus_T enmBus; 6105 BOOL fUseHostIOCache; 6106 6107 /* 6108 * We could pass the objects, but then EMT would have to do lots of 6109 * IPC (to VBoxSVC) which takes a significant amount of time. 6110 * Better query needed values here and pass them. 6111 */ 6112 rc = aAttachments[i]->COMGETTER(Controller)(controllerName.asOutParam()); 6113 if (FAILED(rc)) 6114 throw rc; 6115 6116 rc = mMachine->GetStorageControllerByName(controllerName.raw(), 6117 pStorageController.asOutParam()); 6118 if (FAILED(rc)) 6119 throw rc; 6120 6121 rc = pStorageController->COMGETTER(ControllerType)(&enmController); 6122 if (FAILED(rc)) 6123 throw rc; 6124 rc = pStorageController->COMGETTER(Instance)(&lInstance); 6125 if (FAILED(rc)) 6126 throw rc; 6127 rc = pStorageController->COMGETTER(Bus)(&enmBus); 6128 if (FAILED(rc)) 6129 throw rc; 6130 rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache); 6131 if (FAILED(rc)) 6132 throw rc; 6133 6134 const char *pcszDevice = i_convertControllerTypeToDev(enmController); 6135 6136 BOOL fBuiltinIOCache; 6137 rc = mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); 6138 if (FAILED(rc)) 6139 throw rc; 6140 6141 alock.release(); 6142 6143 int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, 6144 (PFNRT)i_reconfigureMediumAttachment, 13, 6145 this, ptrVM.rawUVM(), pcszDevice, lInstance, enmBus, fUseHostIOCache, 6146 fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */, 6147 0 /* uMergeTarget */, aAttachments[i], mMachineState, &rc); 6148 if (RT_FAILURE(vrc)) 6149 throw setError(E_FAIL, tr("%Rrc"), vrc); 6150 if (FAILED(rc)) 6151 throw rc; 6152 6153 alock.acquire(); 6154 } 6399 6155 6400 6156 return rc; … … 6450 6206 case MachineState_Paused: 6451 6207 case MachineState_TeleportingPausedVM: 6452 case MachineState_ Saving:6208 case MachineState_OnlineSnapshotting: 6453 6209 6454 6210 /* Remove any keys which are supposed to be removed on a suspend. */ … … 6502 6258 * a specific reason. 6503 6259 */ 6504 HRESULT Console::i_resume(Reason_T aReason )6260 HRESULT Console::i_resume(Reason_T aReason, AutoWriteLock &alock) 6505 6261 { 6506 6262 LogFlowThisFuncEnter(); … … 6508 6264 AutoCaller autoCaller(this); 6509 6265 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 6510 6511 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);6512 6513 if (mMachineState != MachineState_Paused)6514 return setError(VBOX_E_INVALID_VM_STATE,6515 tr("Cannot resume the machine as it is not paused (machine state: %s)"),6516 Global::stringifyMachineState(mMachineState));6517 6266 6518 6267 /* get the VM handle. */ … … 6544 6293 if (aReason == Reason_HostResume) 6545 6294 enmReason = VMRESUMEREASON_HOST_RESUME; 6295 else if (aReason == Reason_Snapshot) 6296 enmReason = VMRESUMEREASON_STATE_SAVED; 6297 6298 // for snapshots: no state change callback, VBoxSVC does everything 6299 if (aReason == Reason_Snapshot) 6300 mVMStateChangeCallbackDisabled = true; 6546 6301 vrc = VMR3Resume(ptrVM.rawUVM(), enmReason); 6302 if (aReason == Reason_Snapshot) 6303 mVMStateChangeCallbackDisabled = false; 6547 6304 } 6548 6305 … … 6558 6315 6559 6316 /** 6560 * Worker for Console::SaveState and internal entry point for saving state of 6561 * a VM for a specific reason. 6562 */ 6563 HRESULT Console::i_saveState(Reason_T aReason, IProgress **aProgress) 6317 * Internal entry point for saving state of a VM for a specific reason. This 6318 * method is completely synchronous. 6319 * 6320 * The machine state is already set appropriately. It is only changed when 6321 * saving state actually paused the VM (happens with live snapshots and 6322 * teleportation), and in this case reflects the now paused variant. 6323 * 6324 * @note Locks this object for writing. 6325 */ 6326 HRESULT Console::i_saveState(Reason_T aReason, const ComPtr<IProgress> &aProgress, const Utf8Str &aStateFilePath, bool aPauseVM, bool &aLeftPaused) 6564 6327 { 6565 6328 LogFlowThisFuncEnter(); 6566 6567 CheckComArgOutPointerValid(aProgress); 6329 aLeftPaused = false; 6330 6331 AssertReturn(!aProgress.isNull(), E_INVALIDARG); 6332 AssertReturn(!aStateFilePath.isEmpty(), E_INVALIDARG); 6568 6333 6569 6334 AutoCaller autoCaller(this); … … 6573 6338 6574 6339 LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); 6575 if ( mMachineState != MachineState_Running 6576 && mMachineState != MachineState_Paused) 6340 if ( mMachineState != MachineState_Saving 6341 && mMachineState != MachineState_LiveSnapshotting 6342 && mMachineState != MachineState_OnlineSnapshotting 6343 && mMachineState != MachineState_Teleporting 6344 && mMachineState != MachineState_TeleportingPausedVM) 6577 6345 { 6578 6346 return setError(VBOX_E_INVALID_VM_STATE, … … 6580 6348 Global::stringifyMachineState(mMachineState)); 6581 6349 } 6350 bool fContinueAfterwards = mMachineState != MachineState_Saving; 6582 6351 6583 6352 Bstr strDisableSaveState; … … 6590 6359 LogRel(("Saving state of VM, reason \"%s\"\n", Global::stringifyReason(aReason))); 6591 6360 6592 /* memorize the current machine state */ 6593 MachineState_T lastMachineState = mMachineState; 6594 6595 if (mMachineState == MachineState_Running) 6596 { 6597 /* get the VM handle. */ 6598 SafeVMPtr ptrVM(this); 6599 if (!ptrVM.isOk()) 6600 return ptrVM.rc(); 6601 6361 /* ensure the directory for the saved state file exists */ 6362 { 6363 Utf8Str dir = aStateFilePath; 6364 dir.stripFilename(); 6365 if (!RTDirExists(dir.c_str())) 6366 { 6367 int vrc = RTDirCreateFullPath(dir.c_str(), 0700); 6368 if (RT_FAILURE(vrc)) 6369 return setError(VBOX_E_FILE_ERROR, 6370 tr("Could not create a directory '%s' to save the state to (%Rrc)"), 6371 dir.c_str(), vrc); 6372 } 6373 } 6374 6375 /* Get the VM handle early, we need it in several places. */ 6376 SafeVMPtr ptrVM(this); 6377 if (!ptrVM.isOk()) 6378 return ptrVM.rc(); 6379 6380 bool fPaused = false; 6381 if (aPauseVM) 6382 { 6602 6383 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */ 6603 6384 alock.release(); … … 6610 6391 alock.acquire(); 6611 6392 6612 HRESULT hrc = S_OK;6613 6393 if (RT_FAILURE(vrc)) 6614 hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc); 6615 if (FAILED(hrc)) 6616 return hrc; 6617 } 6618 6619 HRESULT rc = S_OK; 6620 bool fBeganSavingState = false; 6621 bool fTaskCreationFailed = false; 6622 6623 do 6624 { 6625 ComPtr<IProgress> pProgress; 6626 Bstr stateFilePath; 6627 6394 return setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc); 6395 fPaused = true; 6396 } 6397 6398 LogFlowFunc(("Saving the state to '%s'...\n", aStateFilePath.c_str())); 6399 6400 mptrCancelableProgress = aProgress; 6401 alock.release(); 6402 int vrc = VMR3Save(ptrVM.rawUVM(), 6403 aStateFilePath.c_str(), 6404 fContinueAfterwards, 6405 Console::i_stateProgressCallback, 6406 static_cast<IProgress *>(aProgress), 6407 &aLeftPaused); 6408 alock.acquire(); 6409 mptrCancelableProgress.setNull(); 6410 if (RT_FAILURE(vrc)) 6411 { 6412 if (fPaused) 6413 { 6414 alock.release(); 6415 VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED); 6416 alock.acquire(); 6417 } 6418 return setError(E_FAIL, tr("Failed to save the machine state to '%s' (%Rrc)"), 6419 aStateFilePath.c_str(), vrc); 6420 } 6421 Assert(fContinueAfterwards || !aLeftPaused); 6422 6423 if (!fContinueAfterwards) 6424 { 6628 6425 /* 6629 * request a saved state file path from the server6630 * ( this will set the machine state to Saving on the server to block6631 * others from accessing this machine)6426 * The machine has been successfully saved, so power it down 6427 * (vmstateChangeCallback() will set state to Saved on success). 6428 * Note: we release the VM caller, otherwise it will deadlock. 6632 6429 */ 6633 rc = mControl->BeginSavingState(pProgress.asOutParam(), 6634 stateFilePath.asOutParam()); 6635 if (FAILED(rc)) 6636 break; 6637 6638 fBeganSavingState = true; 6639 6640 /* sync the state with the server */ 6641 i_setMachineStateLocally(MachineState_Saving); 6642 6643 /* ensure the directory for the saved state file exists */ 6644 { 6645 Utf8Str dir = stateFilePath; 6646 dir.stripFilename(); 6647 if (!RTDirExists(dir.c_str())) 6648 { 6649 int vrc = RTDirCreateFullPath(dir.c_str(), 0700); 6650 if (RT_FAILURE(vrc)) 6651 { 6652 rc = setError(VBOX_E_FILE_ERROR, 6653 tr("Could not create a directory '%s' to save the state to (%Rrc)"), 6654 dir.c_str(), vrc); 6655 break; 6656 } 6657 } 6658 } 6659 6660 /* Create a task object early to ensure mpUVM protection is successful. */ 6661 std::auto_ptr<VMSaveTask> task(new VMSaveTask(this, pProgress, 6662 stateFilePath, 6663 lastMachineState, 6664 aReason)); 6665 rc = task->rc(); 6666 /* 6667 * If we fail here it means a PowerDown() call happened on another 6668 * thread while we were doing Pause() (which releases the Console lock). 6669 * We assign PowerDown() a higher precedence than SaveState(), 6670 * therefore just return the error to the caller. 6671 */ 6672 if (FAILED(rc)) 6673 { 6674 fTaskCreationFailed = true; 6675 break; 6676 } 6677 6678 /* create a thread to wait until the VM state is saved */ 6679 int vrc = RTThreadCreate(NULL, Console::i_saveStateThread, (void *)task.get(), 6680 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave"); 6681 if (RT_FAILURE(vrc)) 6682 { 6683 rc = setError(E_FAIL, "Could not create VMSave thread (%Rrc)", vrc); 6684 break; 6685 } 6686 6687 /* task is now owned by saveStateThread(), so release it */ 6688 task.release(); 6689 6690 /* return the progress to the caller */ 6691 pProgress.queryInterfaceTo(aProgress); 6692 } while (0); 6693 6694 if (FAILED(rc) && !fTaskCreationFailed) 6695 { 6696 /* preserve existing error info */ 6697 ErrorInfoKeeper eik; 6698 6699 if (fBeganSavingState) 6700 { 6701 /* 6702 * cancel the requested save state procedure. 6703 * This will reset the machine state to the state it had right 6704 * before calling mControl->BeginSavingState(). 6705 */ 6706 mControl->EndSavingState(eik.getResultCode(), eik.getText().raw()); 6707 } 6708 6709 if (lastMachineState == MachineState_Running) 6710 { 6711 /* restore the paused state if appropriate */ 6712 i_setMachineStateLocally(MachineState_Paused); 6713 /* restore the running state if appropriate */ 6714 SafeVMPtr ptrVM(this); 6715 if (ptrVM.isOk()) 6716 { 6717 alock.release(); 6718 VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED); 6719 alock.acquire(); 6720 } 6721 } 6722 else 6723 i_setMachineStateLocally(lastMachineState); 6724 } 6725 6726 LogFlowThisFunc(("rc=%Rhrc\n", rc)); 6727 LogFlowThisFuncLeave(); 6728 return rc; 6430 ptrVM.release(); 6431 alock.release(); 6432 autoCaller.release(); 6433 HRESULT rc = i_powerDown(); 6434 AssertComRC(rc); 6435 autoCaller.add(); 6436 alock.acquire(); 6437 } 6438 else 6439 { 6440 if (fPaused) 6441 aLeftPaused = true; 6442 } 6443 6444 LogFlowFuncLeave(); 6445 return S_OK; 6446 } 6447 6448 /** 6449 * Internal entry point for cancelling a VM save state. 6450 * 6451 * @note Locks this object for writing. 6452 */ 6453 HRESULT Console::i_cancelSaveState() 6454 { 6455 LogFlowThisFuncEnter(); 6456 6457 AutoCaller autoCaller(this); 6458 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 6459 6460 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 6461 6462 /* Get the VM handle. */ 6463 SafeVMPtr ptrVM(this); 6464 if (!ptrVM.isOk()) 6465 return ptrVM.rc(); 6466 6467 SSMR3Cancel(ptrVM.rawUVM()); 6468 6469 LogFlowFuncLeave(); 6470 return S_OK; 6729 6471 } 6730 6472 … … 6745 6487 6746 6488 AssertReturn( mMachineState == MachineState_Saving 6489 || mMachineState == MachineState_OnlineSnapshotting 6747 6490 || mMachineState == MachineState_LiveSnapshotting 6748 || mMachineState == MachineState_RestoringSnapshot6749 || mMachineState == MachineState_DeletingSnapshot6750 6491 || mMachineState == MachineState_DeletingSnapshotOnline 6751 6492 || mMachineState == MachineState_DeletingSnapshotPaused 6493 || aMachineState == MachineState_Saving 6494 || aMachineState == MachineState_OnlineSnapshotting 6495 || aMachineState == MachineState_LiveSnapshotting 6496 || aMachineState == MachineState_DeletingSnapshotOnline 6497 || aMachineState == MachineState_DeletingSnapshotPaused 6752 6498 , E_FAIL); 6753 6499 6754 6500 return i_setMachineStateLocally(aMachineState); 6501 } 6502 6503 /** 6504 * Gets called by Session::COMGETTER(NominalState)() 6505 * (IInternalSessionControl::getNominalState()). 6506 * 6507 * @note Locks this object for reading. 6508 */ 6509 HRESULT Console::i_getNominalState(MachineState_T &aNominalState) 6510 { 6511 LogFlowThisFuncEnter(); 6512 6513 AutoCaller autoCaller(this); 6514 AssertComRCReturnRC(autoCaller.rc()); 6515 6516 /* Get the VM handle. */ 6517 SafeVMPtr ptrVM(this); 6518 if (!ptrVM.isOk()) 6519 return ptrVM.rc(); 6520 6521 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 6522 6523 MachineState_T enmMachineState = MachineState_Null; 6524 VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM()); 6525 switch (enmVMState) 6526 { 6527 case VMSTATE_CREATING: 6528 case VMSTATE_CREATED: 6529 case VMSTATE_POWERING_ON: 6530 enmMachineState = MachineState_Starting; 6531 break; 6532 case VMSTATE_LOADING: 6533 enmMachineState = MachineState_Restoring; 6534 break; 6535 case VMSTATE_RESUMING: 6536 case VMSTATE_SUSPENDING: 6537 case VMSTATE_SUSPENDING_LS: 6538 case VMSTATE_SUSPENDING_EXT_LS: 6539 case VMSTATE_SUSPENDED: 6540 case VMSTATE_SUSPENDED_LS: 6541 case VMSTATE_SUSPENDED_EXT_LS: 6542 enmMachineState = MachineState_Paused; 6543 break; 6544 case VMSTATE_RUNNING: 6545 case VMSTATE_RUNNING_LS: 6546 case VMSTATE_RUNNING_FT: 6547 case VMSTATE_RESETTING: 6548 case VMSTATE_RESETTING_LS: 6549 case VMSTATE_DEBUGGING: 6550 case VMSTATE_DEBUGGING_LS: 6551 enmMachineState = MachineState_Running; 6552 break; 6553 case VMSTATE_SAVING: 6554 enmMachineState = MachineState_Saving; 6555 break; 6556 case VMSTATE_POWERING_OFF: 6557 case VMSTATE_POWERING_OFF_LS: 6558 case VMSTATE_DESTROYING: 6559 enmMachineState = MachineState_Stopping; 6560 break; 6561 case VMSTATE_OFF: 6562 case VMSTATE_OFF_LS: 6563 case VMSTATE_FATAL_ERROR: 6564 case VMSTATE_FATAL_ERROR_LS: 6565 case VMSTATE_LOAD_FAILURE: 6566 case VMSTATE_TERMINATED: 6567 enmMachineState = MachineState_PoweredOff; 6568 break; 6569 case VMSTATE_GURU_MEDITATION: 6570 case VMSTATE_GURU_MEDITATION_LS: 6571 enmMachineState = MachineState_Stuck; 6572 break; 6573 default: 6574 AssertMsgFailed(("%s\n", VMR3GetStateName(enmVMState))); 6575 enmMachineState = MachineState_PoweredOff; 6576 } 6577 aNominalState = enmMachineState; 6578 6579 LogFlowFuncLeave(); 6580 return S_OK; 6755 6581 } 6756 6582 … … 7160 6986 try 7161 6987 { 7162 7163 6988 if (Global::IsOnlineOrTransient(mMachineState)) 7164 6989 throw setError(VBOX_E_INVALID_VM_STATE, … … 7273 7098 } 7274 7099 7275 /* Setup task object and thread to carry out the operat on7276 * Asycnhronously */7100 /* Setup task object and thread to carry out the operation 7101 * asynchronously */ 7277 7102 std::auto_ptr<VMPowerUpTask> task(new VMPowerUpTask(this, pPowerupProgress)); 7278 7103 ComAssertComRCRetRC(task->rc()); … … 7892 7717 */ 7893 7718 HRESULT Console::i_setMachineState(MachineState_T aMachineState, 7894 bool aUpdateServer /* = true */)7719 bool aUpdateServer /* = true */) 7895 7720 { 7896 7721 AutoCaller autoCaller(this); … … 7905 7730 LogThisFunc(("machineState=%s -> %s aUpdateServer=%RTbool\n", 7906 7731 Global::stringifyMachineState(mMachineState), Global::stringifyMachineState(aMachineState), aUpdateServer)); 7732 LogRel(("Console: machine state changed to %s\n", Global::stringifyMachineState(aMachineState))); 7907 7733 mMachineState = aMachineState; 7908 7734 … … 8515 8341 8516 8342 case MachineState_LiveSnapshotting: 8517 that->i_setMachineState(MachineState_ Saving);8343 that->i_setMachineState(MachineState_OnlineSnapshotting); 8518 8344 break; 8519 8345 … … 8524 8350 case MachineState_TeleportingIn: 8525 8351 case MachineState_FaultTolerantSyncing: 8352 case MachineState_OnlineSnapshotting: 8526 8353 /* The worker thread handles the transition. */ 8527 8354 break; 8528 8355 8529 default:8530 AssertMsgFailed(("%s\n", Global::stringifyMachineState(that->mMachineState)));8531 8356 case MachineState_Running: 8532 8357 that->i_setMachineState(MachineState_Paused); … … 8536 8361 /* Nothing to do. */ 8537 8362 break; 8363 8364 default: 8365 AssertMsgFailed(("%s\n", Global::stringifyMachineState(that->mMachineState))); 8538 8366 } 8539 8367 break; … … 8553 8381 8554 8382 case MachineState_LiveSnapshotting: 8555 that->i_setMachineState(MachineState_ Saving);8383 that->i_setMachineState(MachineState_OnlineSnapshotting); 8556 8384 break; 8557 8385 … … 9613 9441 // Create the VMM device object, which starts the HGCM thread; do this only 9614 9442 // once for the console, for the pathological case that the same console 9615 // object is used to power up a VM twice. VirtualBox 4.0: we now do that 9616 // here instead of the Console constructor (see Console::init()) 9443 // object is used to power up a VM twice. 9617 9444 if (!pConsole->m_pVMMDev) 9618 9445 { … … 10102 9929 10103 9930 /** 10104 * Progress cancelation callback employed by Console::fntTakeSnapshotWorker.10105 */10106 static void takesnapshotProgressCancelCallback(void *pvUser)10107 {10108 PUVM pUVM = (PUVM)pvUser;10109 SSMR3Cancel(pUVM);10110 }10111 10112 /**10113 * Worker thread created by Console::TakeSnapshot.10114 * @param Thread The current thread (ignored).10115 * @param pvUser The task.10116 * @return VINF_SUCCESS (ignored).10117 */10118 /*static*/10119 DECLCALLBACK(int) Console::i_fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)10120 {10121 VMTakeSnapshotTask *pTask = (VMTakeSnapshotTask*)pvUser;10122 10123 // taking a snapshot consists of the following:10124 10125 // 1) creating a diff image for each virtual hard disk, into which write operations go after10126 // the snapshot has been created (done in VBoxSVC, in SessionMachine::BeginTakingSnapshot)10127 // 2) creating a Snapshot object with the state of the machine (hardware + storage,10128 // done in VBoxSVC, also in SessionMachine::BeginTakingSnapshot)10129 // 3) saving the state of the virtual machine (here, in the VM process, if the machine is online)10130 10131 Console *that = pTask->mConsole;10132 bool fBeganTakingSnapshot = false;10133 bool fSuspenededBySave = false;10134 10135 AutoCaller autoCaller(that);10136 if (FAILED(autoCaller.rc()))10137 {10138 that->mptrCancelableProgress.setNull();10139 return autoCaller.rc();10140 }10141 10142 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);10143 10144 HRESULT rc = S_OK;10145 10146 try10147 {10148 /* STEP 1 + 2:10149 * request creating the diff images on the server and create the snapshot object10150 * (this will set the machine state to Saving on the server to block10151 * others from accessing this machine)10152 */10153 rc = that->mControl->BeginTakingSnapshot(that,10154 pTask->bstrName.raw(),10155 pTask->bstrDescription.raw(),10156 pTask->mProgress,10157 pTask->fTakingSnapshotOnline,10158 pTask->bstrSavedStateFile.asOutParam());10159 if (FAILED(rc))10160 throw rc;10161 10162 fBeganTakingSnapshot = true;10163 10164 /* Check sanity: for offline snapshots there must not be a saved state10165 * file name. All other combinations are valid (even though online10166 * snapshots without saved state file seems inconsistent - there are10167 * some exotic use cases, which need to be explicitly enabled, see the10168 * code of SessionMachine::BeginTakingSnapshot. */10169 if ( !pTask->fTakingSnapshotOnline10170 && !pTask->bstrSavedStateFile.isEmpty())10171 throw i_setErrorStatic(E_FAIL, "Invalid state of saved state file");10172 10173 /* sync the state with the server */10174 if (pTask->lastMachineState == MachineState_Running)10175 that->i_setMachineStateLocally(MachineState_LiveSnapshotting);10176 else10177 that->i_setMachineStateLocally(MachineState_Saving);10178 10179 // STEP 3: save the VM state (if online)10180 if (pTask->fTakingSnapshotOnline)10181 {10182 int vrc;10183 SafeVMPtr ptrVM(that);10184 if (!ptrVM.isOk())10185 throw ptrVM.rc();10186 10187 pTask->mProgress->SetNextOperation(Bstr(tr("Saving the machine state")).raw(),10188 pTask->ulMemSize); // operation weight, same as computed10189 // when setting up progress object10190 if (!pTask->bstrSavedStateFile.isEmpty())10191 {10192 Utf8Str strSavedStateFile(pTask->bstrSavedStateFile);10193 10194 pTask->mProgress->i_setCancelCallback(takesnapshotProgressCancelCallback, ptrVM.rawUVM());10195 10196 alock.release();10197 LogFlowFunc(("VMR3Save...\n"));10198 vrc = VMR3Save(ptrVM.rawUVM(),10199 strSavedStateFile.c_str(),10200 true /*fContinueAfterwards*/,10201 Console::i_stateProgressCallback,10202 static_cast<IProgress *>(pTask->mProgress),10203 &fSuspenededBySave);10204 alock.acquire();10205 if (RT_FAILURE(vrc))10206 throw i_setErrorStatic(E_FAIL,10207 tr("Failed to save the machine state to '%s' (%Rrc)"),10208 strSavedStateFile.c_str(), vrc);10209 10210 pTask->mProgress->i_setCancelCallback(NULL, NULL);10211 }10212 else10213 LogRel(("Console: skipped saving state as part of online snapshot\n"));10214 10215 if (!pTask->mProgress->i_notifyPointOfNoReturn())10216 throw i_setErrorStatic(E_FAIL, tr("Canceled"));10217 that->mptrCancelableProgress.setNull();10218 10219 // STEP 4: reattach hard disks10220 LogFlowFunc(("Reattaching new differencing hard disks...\n"));10221 10222 pTask->mProgress->SetNextOperation(Bstr(tr("Reconfiguring medium attachments")).raw(),10223 1); // operation weight, same as computed when setting up progress object10224 10225 com::SafeIfaceArray<IMediumAttachment> atts;10226 rc = that->mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(atts));10227 if (FAILED(rc))10228 throw rc;10229 10230 for (size_t i = 0;10231 i < atts.size();10232 ++i)10233 {10234 ComPtr<IStorageController> pStorageController;10235 Bstr controllerName;10236 ULONG lInstance;10237 StorageControllerType_T enmController;10238 StorageBus_T enmBus;10239 BOOL fUseHostIOCache;10240 10241 /*10242 * We can't pass a storage controller object directly10243 * (g++ complains about not being able to pass non POD types through '...')10244 * so we have to query needed values here and pass them.10245 */10246 rc = atts[i]->COMGETTER(Controller)(controllerName.asOutParam());10247 if (FAILED(rc))10248 throw rc;10249 10250 rc = that->mMachine->GetStorageControllerByName(controllerName.raw(),10251 pStorageController.asOutParam());10252 if (FAILED(rc))10253 throw rc;10254 10255 rc = pStorageController->COMGETTER(ControllerType)(&enmController);10256 if (FAILED(rc))10257 throw rc;10258 rc = pStorageController->COMGETTER(Instance)(&lInstance);10259 if (FAILED(rc))10260 throw rc;10261 rc = pStorageController->COMGETTER(Bus)(&enmBus);10262 if (FAILED(rc))10263 throw rc;10264 rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);10265 if (FAILED(rc))10266 throw rc;10267 10268 const char *pcszDevice = Console::i_convertControllerTypeToDev(enmController);10269 10270 BOOL fBuiltinIOCache;10271 rc = that->mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);10272 if (FAILED(rc))10273 throw rc;10274 10275 alock.release();10276 vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,10277 (PFNRT)i_reconfigureMediumAttachment, 13,10278 that, ptrVM.rawUVM(), pcszDevice, lInstance, enmBus, fUseHostIOCache,10279 fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */,10280 0 /* uMergeTarget */, atts[i], that->mMachineState, &rc);10281 alock.acquire();10282 if (RT_FAILURE(vrc))10283 throw i_setErrorStatic(E_FAIL, Console::tr("%Rrc"), vrc);10284 if (FAILED(rc))10285 throw rc;10286 }10287 }10288 10289 /*10290 * finalize the requested snapshot object.10291 * This will reset the machine state to the state it had right10292 * before calling mControl->BeginTakingSnapshot().10293 */10294 rc = that->mControl->EndTakingSnapshot(TRUE /*aSuccess*/);10295 // do not throw rc here because we can't call EndTakingSnapshot() twice10296 LogFlowFunc(("EndTakingSnapshot -> %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(that->mMachineState)));10297 }10298 catch (HRESULT rcThrown)10299 {10300 /* preserve existing error info */10301 ErrorInfoKeeper eik;10302 10303 if (fBeganTakingSnapshot)10304 that->mControl->EndTakingSnapshot(FALSE /*aSuccess*/);10305 10306 rc = rcThrown;10307 LogFunc(("Caught %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(that->mMachineState)));10308 }10309 Assert(alock.isWriteLockOnCurrentThread());10310 10311 if (FAILED(rc)) /* Must come before calling setMachineState. */10312 pTask->mProgress->i_notifyComplete(rc);10313 10314 /*10315 * Fix up the machine state.10316 *10317 * For live snapshots we do all the work, for the two other variations we10318 * just update the local copy.10319 */10320 MachineState_T enmMachineState;10321 that->mMachine->COMGETTER(State)(&enmMachineState);10322 if ( that->mMachineState == MachineState_LiveSnapshotting10323 || that->mMachineState == MachineState_Saving)10324 {10325 10326 if (!pTask->fTakingSnapshotOnline)10327 that->i_setMachineStateLocally(pTask->lastMachineState);10328 else if (SUCCEEDED(rc))10329 {10330 Assert( pTask->lastMachineState == MachineState_Running10331 || pTask->lastMachineState == MachineState_Paused);10332 Assert(that->mMachineState == MachineState_Saving);10333 if (pTask->lastMachineState == MachineState_Running)10334 {10335 LogFlowFunc(("VMR3Resume...\n"));10336 SafeVMPtr ptrVM(that);10337 alock.release();10338 int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED);10339 alock.acquire();10340 if (RT_FAILURE(vrc))10341 {10342 rc = i_setErrorStatic(VBOX_E_VM_ERROR, tr("Could not resume the machine execution (%Rrc)"), vrc);10343 pTask->mProgress->i_notifyComplete(rc);10344 if (that->mMachineState == MachineState_Saving)10345 that->i_setMachineStateLocally(MachineState_Paused);10346 }10347 }10348 else10349 that->i_setMachineStateLocally(MachineState_Paused);10350 }10351 else10352 {10353 /** @todo this could probably be made more generic and reused elsewhere. */10354 /* paranoid cleanup on for a failed online snapshot. */10355 VMSTATE enmVMState = VMR3GetStateU(that->mpUVM);10356 switch (enmVMState)10357 {10358 case VMSTATE_RUNNING:10359 case VMSTATE_RUNNING_LS:10360 case VMSTATE_DEBUGGING:10361 case VMSTATE_DEBUGGING_LS:10362 case VMSTATE_POWERING_OFF:10363 case VMSTATE_POWERING_OFF_LS:10364 case VMSTATE_RESETTING:10365 case VMSTATE_RESETTING_LS:10366 Assert(!fSuspenededBySave);10367 that->i_setMachineState(MachineState_Running);10368 break;10369 10370 case VMSTATE_GURU_MEDITATION:10371 case VMSTATE_GURU_MEDITATION_LS:10372 that->i_setMachineState(MachineState_Stuck);10373 break;10374 10375 case VMSTATE_FATAL_ERROR:10376 case VMSTATE_FATAL_ERROR_LS:10377 if (pTask->lastMachineState == MachineState_Paused)10378 that->i_setMachineStateLocally(pTask->lastMachineState);10379 else10380 that->i_setMachineState(MachineState_Paused);10381 break;10382 10383 default:10384 AssertMsgFailed(("%s\n", VMR3GetStateName(enmVMState)));10385 case VMSTATE_SUSPENDED:10386 case VMSTATE_SUSPENDED_LS:10387 case VMSTATE_SUSPENDING:10388 case VMSTATE_SUSPENDING_LS:10389 case VMSTATE_SUSPENDING_EXT_LS:10390 if (fSuspenededBySave)10391 {10392 Assert(pTask->lastMachineState == MachineState_Running);10393 LogFlowFunc(("VMR3Resume (on failure)...\n"));10394 SafeVMPtr ptrVM(that);10395 alock.release();10396 int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED); AssertLogRelRC(vrc);10397 alock.acquire();10398 if (RT_FAILURE(vrc))10399 that->i_setMachineState(MachineState_Paused);10400 }10401 else if (pTask->lastMachineState == MachineState_Paused)10402 that->i_setMachineStateLocally(pTask->lastMachineState);10403 else10404 that->i_setMachineState(MachineState_Paused);10405 break;10406 }10407 10408 }10409 }10410 /*else: somebody else has change the state... Leave it. */10411 10412 /* check the remote state to see that we got it right. */10413 that->mMachine->COMGETTER(State)(&enmMachineState);10414 AssertLogRelMsg(that->mMachineState == enmMachineState,10415 ("mMachineState=%s enmMachineState=%s\n", Global::stringifyMachineState(that->mMachineState),10416 Global::stringifyMachineState(enmMachineState) ));10417 10418 10419 if (SUCCEEDED(rc)) /* The failure cases are handled above. */10420 pTask->mProgress->i_notifyComplete(rc);10421 10422 delete pTask;10423 10424 LogFlowFuncLeave();10425 return VINF_SUCCESS;10426 }10427 10428 /**10429 * Thread for executing the saved state operation.10430 *10431 * @param Thread The thread handle.10432 * @param pvUser Pointer to a VMSaveTask structure.10433 * @return VINF_SUCCESS (ignored).10434 *10435 * @note Locks the Console object for writing.10436 */10437 /*static*/10438 DECLCALLBACK(int) Console::i_saveStateThread(RTTHREAD Thread, void *pvUser)10439 {10440 LogFlowFuncEnter();10441 10442 std::auto_ptr<VMSaveTask> task(static_cast<VMSaveTask*>(pvUser));10443 AssertReturn(task.get(), VERR_INVALID_PARAMETER);10444 10445 Assert(task->mSavedStateFile.length());10446 Assert(task->mProgress.isNull());10447 Assert(!task->mServerProgress.isNull());10448 10449 const ComObjPtr<Console> &that = task->mConsole;10450 Utf8Str errMsg;10451 HRESULT rc = S_OK;10452 10453 LogFlowFunc(("Saving the state to '%s'...\n", task->mSavedStateFile.c_str()));10454 10455 bool fSuspenededBySave;10456 int vrc = VMR3Save(task->mpUVM,10457 task->mSavedStateFile.c_str(),10458 false, /*fContinueAfterwards*/10459 Console::i_stateProgressCallback,10460 static_cast<IProgress *>(task->mServerProgress),10461 &fSuspenededBySave);10462 if (RT_FAILURE(vrc))10463 {10464 errMsg = Utf8StrFmt(Console::tr("Failed to save the machine state to '%s' (%Rrc)"),10465 task->mSavedStateFile.c_str(), vrc);10466 rc = E_FAIL;10467 }10468 Assert(!fSuspenededBySave);10469 10470 /* lock the console once we're going to access it */10471 AutoWriteLock thatLock(that COMMA_LOCKVAL_SRC_POS);10472 10473 /* synchronize the state with the server */10474 if (SUCCEEDED(rc))10475 {10476 /*10477 * The machine has been successfully saved, so power it down10478 * (vmstateChangeCallback() will set state to Saved on success).10479 * Note: we release the task's VM caller, otherwise it will10480 * deadlock.10481 */10482 task->releaseVMCaller();10483 thatLock.release();10484 rc = that->i_powerDown();10485 thatLock.acquire();10486 }10487 10488 /*10489 * If we failed, reset the local machine state.10490 */10491 if (FAILED(rc))10492 that->i_setMachineStateLocally(task->mMachineStateBefore);10493 10494 /*10495 * Finalize the requested save state procedure. In case of failure it will10496 * reset the machine state to the state it had right before calling10497 * mControl->BeginSavingState(). This must be the last thing because it10498 * will set the progress to completed, and that means that the frontend10499 * can immediately uninit the associated console object.10500 */10501 that->mControl->EndSavingState(rc, Bstr(errMsg).raw());10502 10503 LogFlowFuncLeave();10504 return VINF_SUCCESS;10505 }10506 10507 /**10508 9931 * Thread for powering down the Console. 10509 9932 * … … 10560 9983 /* 10561 9984 * For now, just call SaveState. We should probably try notify the GUI so 10562 * it can pop up a progress object and stuff. 9985 * it can pop up a progress object and stuff. The progress object created 9986 * by the call isn't returned to anyone and thus gets updated without 9987 * anyone noticing it. 10563 9988 */ 10564 HRESULT hrc = pConsole->SaveState(NULL); 9989 ComPtr<IProgress> pProgress; 9990 HRESULT hrc = pConsole->mMachine->SaveState(pProgress.asOutParam()); 10565 9991 return SUCCEEDED(hrc) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc); 10566 9992 }
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器