summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-client/ConsoleImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-client/ConsoleImpl.cpp')
-rw-r--r--src/VBox/Main/src-client/ConsoleImpl.cpp708
1 files changed, 261 insertions, 447 deletions
diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp
index 78d97f7eb..d0c74c245 100644
--- a/src/VBox/Main/src-client/ConsoleImpl.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2005-2013 Oracle Corporation
+ * Copyright (C) 2005-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -489,7 +489,7 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc
// Event source may be needed by other children
unconst(mEventSource).createObject();
- rc = mEventSource->init(static_cast<IConsole*>(this));
+ rc = mEventSource->init();
AssertComRCReturnRC(rc);
mcAudioRefs = 0;
@@ -2394,7 +2394,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PUVM pUVM)
*/
PVMREQ pReq;
vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::unplugCpu, 3,
+ (PFNRT)unplugCpu, 3,
this, pUVM, (VMCPUID)aCpu);
if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
{
@@ -2500,7 +2500,7 @@ HRESULT Console::doCPUAdd(ULONG aCpu, PUVM pUVM)
*/
PVMREQ pReq;
int vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::plugCpu, 3,
+ (PFNRT)plugCpu, 3,
this, pUVM, aCpu);
/* release the lock before a VMR3* call (EMT will call us back)! */
@@ -3505,6 +3505,83 @@ HRESULT Console::convertBusPortDeviceToLun(StorageBus_T enmBus, LONG port, LONG
// private methods
/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Suspend the VM before we do any medium or network attachment change.
+ *
+ * @param pUVM Safe VM handle.
+ * @param pAlock The automatic lock instance. This is for when we have
+ * to leave it in order to avoid deadlocks.
+ * @param pfSuspend where to store the information if we need to resume
+ * afterwards.
+ */
+HRESULT Console::suspendBeforeConfigChange(PUVM pUVM, AutoWriteLock *pAlock, bool *pfResume)
+{
+ *pfResume = false;
+ VMSTATE enmVMState = VMR3GetStateU(pUVM);
+ switch (enmVMState)
+ {
+ case VMSTATE_RESETTING:
+ case VMSTATE_RUNNING:
+ {
+ LogFlowFunc(("Suspending the VM...\n"));
+ /* disable the callback to prevent Console-level state change */
+ mVMStateChangeCallbackDisabled = true;
+ if (pAlock)
+ pAlock->release();
+ int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG);
+ if (pAlock)
+ pAlock->acquire();
+ mVMStateChangeCallbackDisabled = false;
+ if (RT_FAILURE(rc))
+ return setErrorInternal(VBOX_E_INVALID_VM_STATE,
+ COM_IIDOF(IConsole),
+ getStaticComponentName(),
+ Utf8StrFmt("Couldn't suspend VM for medium change (%Rrc)", rc),
+ false /*aWarning*/,
+ true /*aLogIt*/);
+ *pfResume = true;
+ break;
+ }
+ case VMSTATE_SUSPENDED:
+ break;
+ default:
+ return setErrorInternal(VBOX_E_INVALID_VM_STATE,
+ COM_IIDOF(IConsole),
+ getStaticComponentName(),
+ Utf8StrFmt("Invalid VM state '%s' for changing medium",
+ VMR3GetStateName(enmVMState)),
+ false /*aWarning*/,
+ true /*aLogIt*/);
+ }
+
+ return S_OK;
+}
+
+/**
+ * Resume the VM after we did any medium or network attachment change.
+ * This is the counterpart to Console::suspendBeforeConfigChange().
+ *
+ * @param pUVM Safe VM handle.
+ */
+void Console::resumeAfterConfigChange(PUVM pUVM)
+{
+ LogFlowFunc(("Resuming the VM...\n"));
+ /* disable the callback to prevent Console-level state change */
+ mVMStateChangeCallbackDisabled = true;
+ int rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG);
+ mVMStateChangeCallbackDisabled = false;
+ AssertRC(rc);
+ if (RT_FAILURE(rc))
+ {
+ VMSTATE enmVMState = VMR3GetStateU(pUVM);
+ if (enmVMState == VMSTATE_SUSPENDED)
+ {
+ /* too bad, we failed. try to sync the console state with the VMM state */
+ vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, this);
+ }
+ }
+}
/**
* Process a medium change.
@@ -3574,26 +3651,23 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc
AssertComRC(rc);
/*
+ * Suspend the VM first. The VM must not be running since it might have
+ * pending I/O to the drive which is being changed.
+ */
+ bool fResume = false;
+ rc = suspendBeforeConfigChange(pUVM, &alock, &fResume);
+ if (FAILED(rc))
+ return rc;
+
+ /*
* Call worker in EMT, that's faster and safer than doing everything
* using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
- int vrc = VMR3ReqCallU(pUVM,
- VMCPUID_ANY,
- &pReq,
- 0 /* no wait! */,
- VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::changeRemovableMedium,
- 8,
- this,
- pUVM,
- pszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- aMediumAttachment,
- fForce);
+ int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)changeRemovableMedium, 8,
+ this, pUVM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fForce);
/* release the lock before waiting for a result (EMT will call us back!) */
alock.release();
@@ -3607,6 +3681,9 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc
}
VMR3ReqFree(pReq);
+ if (fResume)
+ resumeAfterConfigChange(pUVM);
+
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Returns S_OK\n"));
@@ -3642,8 +3719,9 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc
* @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable.
*
* @thread EMT
+ * @note The VM must not be running since it might have pending I/O to the drive which is being changed.
*/
-DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole,
+DECLCALLBACK(int) Console::changeRemovableMedium(Console *pThis,
PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
@@ -3652,112 +3730,49 @@ DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole,
IMediumAttachment *aMediumAtt,
bool fForce)
{
- LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p, fForce=%d\n",
- pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt, fForce));
+ LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p, fForce=%d\n",
+ pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt, fForce));
- AssertReturn(pConsole, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis, VERR_INVALID_PARAMETER);
- AutoCaller autoCaller(pConsole);
+ AutoCaller autoCaller(pThis);
AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
/*
- * Suspend the VM first.
- *
- * The VM must not be running since it might have pending I/O to
- * the drive which is being changed.
+ * Check the VM for correct state.
*/
- bool fResume;
VMSTATE enmVMState = VMR3GetStateU(pUVM);
- switch (enmVMState)
- {
- case VMSTATE_RESETTING:
- case VMSTATE_RUNNING:
- {
- LogFlowFunc(("Suspending the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pConsole->mVMStateChangeCallbackDisabled = true;
- int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRCReturn(rc, rc);
- fResume = true;
- break;
- }
-
- case VMSTATE_SUSPENDED:
- case VMSTATE_CREATED:
- case VMSTATE_OFF:
- fResume = false;
- break;
-
- case VMSTATE_RUNNING_LS:
- case VMSTATE_RUNNING_FT:
- return setErrorInternal(VBOX_E_INVALID_VM_STATE,
- COM_IIDOF(IConsole),
- getStaticComponentName(),
- (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")),
- false /*aWarning*/,
- true /*aLogIt*/);
-
- default:
- AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED);
- }
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
/* Determine the base path for the device instance. */
PCFGMNODE pCtlInst;
pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
- int rc = VINF_SUCCESS;
- int rcRet = VINF_SUCCESS;
-
- rcRet = pConsole->configMediumAttachment(pCtlInst,
- pcszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- false /* fSetupMerge */,
- false /* fBuiltinIOCache */,
- 0 /* uMergeSource */,
- 0 /* uMergeTarget */,
- aMediumAtt,
- pConsole->mMachineState,
- NULL /* phrc */,
- true /* fAttachDetach */,
- fForce /* fForceUnmount */,
- false /* fHotplug */,
- pUVM,
- NULL /* paLedDevType */);
- /** @todo this dumps everything attached to this device instance, which
- * is more than necessary. Dumping the changed LUN would be enough. */
- CFGMR3Dump(pCtlInst);
-
- /*
- * Resume the VM if necessary.
- */
- if (fResume)
- {
- LogFlowFunc(("Resuming the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pConsole->mVMStateChangeCallbackDisabled = true;
- rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pConsole);
- }
- /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume
- // error (if any) will be hidden from the caller. For proper reporting
- // of such multiple errors to the caller we need to enhance the
- // IVirtualBoxError interface. For now, give the first error the higher
- // priority.
- if (RT_SUCCESS(rcRet))
- rcRet = rc;
- }
-
- LogFlowFunc(("Returning %Rrc\n", rcRet));
- return rcRet;
+ PCFGMNODE pLunL0 = NULL;
+ int rc = pThis->configMediumAttachment(pCtlInst,
+ pcszDevice,
+ uInstance,
+ enmBus,
+ fUseHostIOCache,
+ false /* fSetupMerge */,
+ false /* fBuiltinIOCache */,
+ 0 /* uMergeSource */,
+ 0 /* uMergeTarget */,
+ aMediumAtt,
+ pThis->mMachineState,
+ NULL /* phrc */,
+ true /* fAttachDetach */,
+ fForce /* fForceUnmount */,
+ false /* fHotplug */,
+ pUVM,
+ NULL /* paLedDevType */,
+ &pLunL0);
+ /* Dump the changed LUN if possible, dump the complete device otherwise */
+ CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
+
+ LogFlowFunc(("Returning %Rrc\n", rc));
+ return rc;
}
@@ -3829,26 +3844,23 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUV
AssertComRC(rc);
/*
+ * Suspend the VM first. The VM must not be running since it might have
+ * pending I/O to the drive which is being changed.
+ */
+ bool fResume = false;
+ rc = suspendBeforeConfigChange(pUVM, &alock, &fResume);
+ if (FAILED(rc))
+ return rc;
+
+ /*
* Call worker in EMT, that's faster and safer than doing everything
* using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
- int vrc = VMR3ReqCallU(pUVM,
- VMCPUID_ANY,
- &pReq,
- 0 /* no wait! */,
- VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::attachStorageDevice,
- 8,
- this,
- pUVM,
- pszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- aMediumAttachment,
- fSilent);
+ int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)attachStorageDevice, 8,
+ this, pUVM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fSilent);
/* release the lock before waiting for a result (EMT will call us back!) */
alock.release();
@@ -3862,6 +3874,9 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUV
}
VMR3ReqFree(pReq);
+ if (fResume)
+ resumeAfterConfigChange(pUVM);
+
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Returns S_OK\n"));
@@ -3891,8 +3906,9 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUV
* @param fSilent Flag whether to inform the guest about the attached device.
*
* @thread EMT
+ * @note The VM must not be running since it might have pending I/O to the drive which is being changed.
*/
-DECLCALLBACK(int) Console::attachStorageDevice(Console *pConsole,
+DECLCALLBACK(int) Console::attachStorageDevice(Console *pThis,
PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
@@ -3901,113 +3917,49 @@ DECLCALLBACK(int) Console::attachStorageDevice(Console *pConsole,
IMediumAttachment *aMediumAtt,
bool fSilent)
{
- LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n",
- pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt));
+ LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n",
+ pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt));
- AssertReturn(pConsole, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis, VERR_INVALID_PARAMETER);
- AutoCaller autoCaller(pConsole);
+ AutoCaller autoCaller(pThis);
AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
/*
- * Suspend the VM first.
- *
- * The VM must not be running since it might have pending I/O to
- * the drive which is being changed.
+ * Check the VM for correct state.
*/
- bool fResume;
VMSTATE enmVMState = VMR3GetStateU(pUVM);
- switch (enmVMState)
- {
- case VMSTATE_RESETTING:
- case VMSTATE_RUNNING:
- {
- LogFlowFunc(("Suspending the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pConsole->mVMStateChangeCallbackDisabled = true;
- int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRCReturn(rc, rc);
- fResume = true;
- break;
- }
-
- case VMSTATE_SUSPENDED:
- case VMSTATE_CREATED:
- case VMSTATE_OFF:
- fResume = false;
- break;
-
- case VMSTATE_RUNNING_LS:
- case VMSTATE_RUNNING_FT:
- return setErrorInternal(VBOX_E_INVALID_VM_STATE,
- COM_IIDOF(IConsole),
- getStaticComponentName(),
- (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")),
- false /*aWarning*/,
- true /*aLogIt*/);
-
- default:
- AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED);
- }
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
/* Determine the base path for the device instance. */
PCFGMNODE pCtlInst;
pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
- int rc = VINF_SUCCESS;
- int rcRet = VINF_SUCCESS;
-
- rcRet = pConsole->configMediumAttachment(pCtlInst,
- pcszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- false /* fSetupMerge */,
- false /* fBuiltinIOCache */,
- 0 /* uMergeSource */,
- 0 /* uMergeTarget */,
- aMediumAtt,
- pConsole->mMachineState,
- NULL /* phrc */,
- true /* fAttachDetach */,
- false /* fForceUnmount */,
- !fSilent /* fHotplug */,
- pUVM,
- NULL /* paLedDevType */);
- /** @todo this dumps everything attached to this device instance, which
- * is more than necessary. Dumping the changed LUN would be enough. */
- CFGMR3Dump(pCtlInst);
-
- /*
- * Resume the VM if necessary.
- */
- if (fResume)
- {
- LogFlowFunc(("Resuming the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pConsole->mVMStateChangeCallbackDisabled = true;
- rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pConsole);
- }
- /** @todo if we failed with drive mount, then the VMR3Resume
- * error (if any) will be hidden from the caller. For proper reporting
- * of such multiple errors to the caller we need to enhance the
- * IVirtualBoxError interface. For now, give the first error the higher
- * priority.
- */
- if (RT_SUCCESS(rcRet))
- rcRet = rc;
- }
-
- LogFlowFunc(("Returning %Rrc\n", rcRet));
- return rcRet;
+ PCFGMNODE pLunL0 = NULL;
+ int rc = pThis->configMediumAttachment(pCtlInst,
+ pcszDevice,
+ uInstance,
+ enmBus,
+ fUseHostIOCache,
+ false /* fSetupMerge */,
+ false /* fBuiltinIOCache */,
+ 0 /* uMergeSource */,
+ 0 /* uMergeTarget */,
+ aMediumAtt,
+ pThis->mMachineState,
+ NULL /* phrc */,
+ true /* fAttachDetach */,
+ false /* fForceUnmount */,
+ !fSilent /* fHotplug */,
+ pUVM,
+ NULL /* paLedDevType */,
+ &pLunL0);
+ /* Dump the changed LUN if possible, dump the complete device otherwise */
+ CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
+
+ LogFlowFunc(("Returning %Rrc\n", rc));
+ return rc;
}
/**
@@ -4075,25 +4027,23 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUV
AssertComRC(rc);
/*
+ * Suspend the VM first. The VM must not be running since it might have
+ * pending I/O to the drive which is being changed.
+ */
+ bool fResume = false;
+ rc = suspendBeforeConfigChange(pUVM, &alock, &fResume);
+ if (FAILED(rc))
+ return rc;
+
+ /*
* Call worker in EMT, that's faster and safer than doing everything
* using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
- int vrc = VMR3ReqCallU(pUVM,
- VMCPUID_ANY,
- &pReq,
- 0 /* no wait! */,
- VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::detachStorageDevice,
- 7,
- this,
- pUVM,
- pszDevice,
- uInstance,
- enmBus,
- aMediumAttachment,
- fSilent);
+ int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)detachStorageDevice, 7,
+ this, pUVM, pszDevice, uInstance, enmBus, aMediumAttachment, fSilent);
/* release the lock before waiting for a result (EMT will call us back!) */
alock.release();
@@ -4107,6 +4057,9 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUV
}
VMR3ReqFree(pReq);
+ if (fResume)
+ resumeAfterConfigChange(pUVM);
+
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Returns S_OK\n"));
@@ -4135,8 +4088,9 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUV
* @param fSilent Flag whether to notify the guest about the detached device.
*
* @thread EMT
+ * @note The VM must not be running since it might have pending I/O to the drive which is being changed.
*/
-DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole,
+DECLCALLBACK(int) Console::detachStorageDevice(Console *pThis,
PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
@@ -4144,55 +4098,19 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole,
IMediumAttachment *pMediumAtt,
bool fSilent)
{
- LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n",
- pConsole, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt));
+ LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n",
+ pThis, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt));
- AssertReturn(pConsole, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis, VERR_INVALID_PARAMETER);
- AutoCaller autoCaller(pConsole);
+ AutoCaller autoCaller(pThis);
AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
/*
- * Suspend the VM first.
- *
- * The VM must not be running since it might have pending I/O to
- * the drive which is being changed.
+ * Check the VM for correct state.
*/
- bool fResume;
VMSTATE enmVMState = VMR3GetStateU(pUVM);
- switch (enmVMState)
- {
- case VMSTATE_RESETTING:
- case VMSTATE_RUNNING:
- {
- LogFlowFunc(("Suspending the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pConsole->mVMStateChangeCallbackDisabled = true;
- int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRCReturn(rc, rc);
- fResume = true;
- break;
- }
-
- case VMSTATE_SUSPENDED:
- case VMSTATE_CREATED:
- case VMSTATE_OFF:
- fResume = false;
- break;
-
- case VMSTATE_RUNNING_LS:
- case VMSTATE_RUNNING_FT:
- return setErrorInternal(VBOX_E_INVALID_VM_STATE,
- COM_IIDOF(IConsole),
- getStaticComponentName(),
- (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")),
- false /*aWarning*/,
- true /*aLogIt*/);
-
- default:
- AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED);
- }
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
/* Determine the base path for the device instance. */
PCFGMNODE pCtlInst;
@@ -4234,7 +4152,7 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole,
CFGMR3RemoveNode(pLunL0);
Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
- pConsole->mapMediumAttachments.erase(devicePath);
+ pThis->mapMediumAttachments.erase(devicePath);
}
else
@@ -4242,32 +4160,6 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole,
CFGMR3Dump(pCtlInst);
- /*
- * Resume the VM if necessary.
- */
- if (fResume)
- {
- LogFlowFunc(("Resuming the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pConsole->mVMStateChangeCallbackDisabled = true;
- rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pConsole);
- }
- /** @todo: if we failed with drive mount, then the VMR3Resume
- * error (if any) will be hidden from the caller. For proper reporting
- * of such multiple errors to the caller we need to enhance the
- * IVirtualBoxError interface. For now, give the first error the higher
- * priority.
- */
- if (RT_SUCCESS(rcRet))
- rcRet = rc;
- }
-
LogFlowFunc(("Returning %Rrc\n", rcRet));
return rcRet;
}
@@ -4507,13 +4399,21 @@ HRESULT Console::doNetworkAdapterChange(PUVM pUVM,
AssertComRCReturnRC(autoCaller.rc());
/*
+ * Suspend the VM first.
+ */
+ bool fResume = false;
+ int rc = suspendBeforeConfigChange(pUVM, NULL, &fResume);
+ if (FAILED(rc))
+ return rc;
+
+ /*
* Call worker in EMT, that's faster and safer than doing everything
* using VM3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
int vrc = VMR3ReqCallU(pUVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::changeNetworkAttachment, 6,
+ (PFNRT)changeNetworkAttachment, 6,
this, pUVM, pszDevice, uInstance, uLun, aNetworkAdapter);
if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
@@ -4525,6 +4425,9 @@ HRESULT Console::doNetworkAdapterChange(PUVM pUVM,
}
VMR3ReqFree(pReq);
+ if (fResume)
+ resumeAfterConfigChange(pUVM);
+
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Returns S_OK\n"));
@@ -4551,6 +4454,7 @@ HRESULT Console::doNetworkAdapterChange(PUVM pUVM,
*
* @thread EMT
* @note Locks the Console object for writing.
+ * @note The VM must not be running.
*/
DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis,
PUVM pUVM,
@@ -4586,76 +4490,21 @@ DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis,
Log(("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance));
/*
- * Suspend the VM first.
- *
- * The VM must not be running since it might have pending I/O to
- * the drive which is being changed.
+ * Check the VM for correct state.
*/
- bool fResume;
VMSTATE enmVMState = VMR3GetStateU(pUVM);
- switch (enmVMState)
- {
- case VMSTATE_RESETTING:
- case VMSTATE_RUNNING:
- {
- LogFlowFunc(("Suspending the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pThis->mVMStateChangeCallbackDisabled = true;
- int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG);
- pThis->mVMStateChangeCallbackDisabled = false;
- AssertRCReturn(rc, rc);
- fResume = true;
- break;
- }
-
- case VMSTATE_SUSPENDED:
- case VMSTATE_CREATED:
- case VMSTATE_OFF:
- fResume = false;
- break;
-
- default:
- AssertLogRelMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED);
- }
-
- int rc = VINF_SUCCESS;
- int rcRet = VINF_SUCCESS;
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
PCFGMNODE pInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%d/", pszDevice, uInstance);
AssertRelease(pInst);
- rcRet = pThis->configNetwork(pszDevice, uInstance, uLun, aNetworkAdapter, pCfg, pLunL0, pInst,
- true /*fAttachDetach*/, false /*fIgnoreConnectFailure*/);
-
- /*
- * Resume the VM if necessary.
- */
- if (fResume)
- {
- LogFlowFunc(("Resuming the VM...\n"));
- /* disable the callback to prevent Console-level state change */
- pThis->mVMStateChangeCallbackDisabled = true;
- rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG);
- pThis->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pThis);
- }
- /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume
- // error (if any) will be hidden from the caller. For proper reporting
- // of such multiple errors to the caller we need to enhance the
- // IVirtualBoxError interface. For now, give the first error the higher
- // priority.
- if (RT_SUCCESS(rcRet))
- rcRet = rc;
- }
+ int rc = pThis->configNetwork(pszDevice, uInstance, uLun, aNetworkAdapter, pCfg, pLunL0, pInst,
+ true /*fAttachDetach*/, false /*fIgnoreConnectFailure*/);
- LogFlowFunc(("Returning %Rrc\n", rcRet));
- return rcRet;
+ LogFlowFunc(("Returning %Rrc\n", rc));
+ return rc;
}
@@ -5703,23 +5552,11 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
AssertRCReturn(vrc2, E_FAIL);
}
- vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(),
- VMCPUID_ANY,
- (PFNRT)reconfigureMediumAttachment,
- 13,
- this,
- ptrVM.rawUVM(),
- pcszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- fBuiltinIOCache,
- true /* fSetupMerge */,
- aSourceIdx,
- aTargetIdx,
- aMediumAttachment,
- mMachineState,
- &rc);
+ vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
+ (PFNRT)reconfigureMediumAttachment, 13,
+ this, ptrVM.rawUVM(), pcszDevice, uInstance, enmBus, fUseHostIOCache,
+ fBuiltinIOCache, true /* fSetupMerge */, aSourceIdx, aTargetIdx,
+ aMediumAttachment, mMachineState, &rc);
/* error handling is after resuming the VM */
if (mMachineState == MachineState_DeletingSnapshotOnline)
@@ -5777,23 +5614,11 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
/* Update medium chain and state now, so that the VM can continue. */
rc = mControl->FinishOnlineMergeMedium();
- vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(),
- VMCPUID_ANY,
- (PFNRT)reconfigureMediumAttachment,
- 13,
- this,
- ptrVM.rawUVM(),
- pcszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- fBuiltinIOCache,
- false /* fSetupMerge */,
- 0 /* uMergeSource */,
- 0 /* uMergeTarget */,
- aMediumAttachment,
- mMachineState,
- &rc);
+ vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
+ (PFNRT)reconfigureMediumAttachment, 13,
+ this, ptrVM.rawUVM(), pcszDevice, uInstance, enmBus, fUseHostIOCache,
+ fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */,
+ 0 /* uMergeTarget */, aMediumAttachment, mMachineState, &rc);
/* error handling is after resuming the VM */
if (mMachineState == MachineState_DeletingSnapshotOnline)
@@ -8236,7 +8061,6 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
(PFNRT)usbAttachCallback, 9,
this, ptrVM.rawUVM(), aHostDevice, uuid.raw(), fRemote,
Address.c_str(), pvRemoteBackend, portVersion, aMaskedIfs);
-
if (RT_SUCCESS(vrc))
{
/* Create a OUSBDevice and add it to the device list */
@@ -9461,7 +9285,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
/**
* Reconfigures a medium attachment (part of taking or deleting an online snapshot).
*
- * @param pConsole Reference to the console object.
+ * @param pThis Reference to the console object.
* @param pUVM The VM handle.
* @param lInstance The instance of the controller.
* @param pcszDevice The name of the controller type.
@@ -9475,7 +9299,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
* @return VBox status code.
*/
/* static */
-DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
+DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pThis,
PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
@@ -9491,11 +9315,9 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
{
LogFlowFunc(("pUVM=%p aMediumAtt=%p phrc=%p\n", pUVM, aMediumAtt, phrc));
- int rc;
HRESULT hrc;
Bstr bstr;
*phrc = S_OK;
-#define RC_CHECK() do { if (RT_FAILURE(rc)) { AssertMsgFailed(("rc=%Rrc\n", rc)); return rc; } } while (0)
#define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%Rhrc (%#x)\n", hrc, hrc)); *phrc = hrc; return VERR_GENERAL_FAILURE; } } while (0)
/* Ignore attachments other than hard disks, since at the moment they are
@@ -9511,29 +9333,33 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
/* Update the device instance configuration. */
- rc = pConsole->configMediumAttachment(pCtlInst,
- pcszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- fBuiltinIOCache,
- fSetupMerge,
- uMergeSource,
- uMergeTarget,
- aMediumAtt,
- aMachineState,
- phrc,
- true /* fAttachDetach */,
- false /* fForceUnmount */,
- false /* fHotplug */,
- pUVM,
- NULL /* paLedDevType */);
- /** @todo this dumps everything attached to this device instance, which
- * is more than necessary. Dumping the changed LUN would be enough. */
- CFGMR3Dump(pCtlInst);
- RC_CHECK();
+ PCFGMNODE pLunL0 = NULL;
+ int rc = pThis->configMediumAttachment(pCtlInst,
+ pcszDevice,
+ uInstance,
+ enmBus,
+ fUseHostIOCache,
+ fBuiltinIOCache,
+ fSetupMerge,
+ uMergeSource,
+ uMergeTarget,
+ aMediumAtt,
+ aMachineState,
+ phrc,
+ true /* fAttachDetach */,
+ false /* fForceUnmount */,
+ false /* fHotplug */,
+ pUVM,
+ NULL /* paLedDevType */,
+ &pLunL0);
+ /* Dump the changed LUN if possible, dump the complete device otherwise */
+ CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
+ if (RT_FAILURE(rc))
+ {
+ AssertMsgFailed(("rc=%Rrc\n", rc));
+ return rc;
+ }
-#undef RC_CHECK
#undef H
LogFlowFunc(("Returns success\n"));
@@ -9715,23 +9541,11 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
* don't release the lock since reconfigureMediumAttachment
* isn't going to need the Console lock.
*/
- vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(),
- VMCPUID_ANY,
- (PFNRT)reconfigureMediumAttachment,
- 13,
- that,
- ptrVM.rawUVM(),
- pcszDevice,
- lInstance,
- enmBus,
- fUseHostIOCache,
- fBuiltinIOCache,
- false /* fSetupMerge */,
- 0 /* uMergeSource */,
- 0 /* uMergeTarget */,
- atts[i],
- that->mMachineState,
- &rc);
+ vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
+ (PFNRT)reconfigureMediumAttachment, 13,
+ that, ptrVM.rawUVM(), pcszDevice, lInstance, enmBus, fUseHostIOCache,
+ fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */,
+ 0 /* uMergeTarget */, atts[i], that->mMachineState, &rc);
if (RT_FAILURE(vrc))
throw setErrorStatic(E_FAIL, Console::tr("%Rrc"), vrc);
if (FAILED(rc))