VirtualBox

Changeset 36991 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
May 6, 2011 7:16:50 PM (14 years ago)
Author:
vboxsync
Message:

Main: Initial support for disk hotplugging, work in progress

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r36954 r36991  
    1354913549  <interface
    1355013550    name="IInternalSessionControl" extends="$unknown"
    13551     uuid="a2fbf834-149d-41da-ae52-0dc3b0f032b3"
     13551    uuid="3a975b65-27e7-42fa-9176-d097d7bd78d4"
    1355213552    internal="yes"
    1355313553    wsmap="suppress"
     
    1371513715      <param name="mediumAttachment" type="IMediumAttachment" dir="in"/>
    1371613716      <param name="force" type="boolean" dir="in"/>
     13717    </method>
     13718
     13719    <method name="onStorageDeviceChange">
     13720      <desc>
     13721        Triggered when attached storage devices of the
     13722        associated virtual machine have changed.
     13723
     13724        <result name="VBOX_E_INVALID_VM_STATE">
     13725          Session state prevents operation.
     13726        </result>
     13727        <result name="VBOX_E_INVALID_OBJECT_STATE">
     13728          Session type prevents operation.
     13729        </result>
     13730
     13731      </desc>
     13732
     13733      <param name="mediumAttachment" type="IMediumAttachment" dir="in"/>
     13734      <param name="remove" type="boolean" dir="in">
     13735        <desc>TRUE if the device is removed, FALSE if it was added.</desc>
     13736      </param>
    1371713737    </method>
    1371813738
     
    1543715457  <enum
    1543815458    name="VBoxEventType"
    15439     uuid="e71c487f-755e-46e9-a476-dd6a5d134597"
     15459    uuid="cce48db6-8561-479d-8d46-1358bab45d4e"
    1544015460    >
    1544115461
     
    1569015710      </desc>
    1569115711    </const>
     15712    <const name="OnStorageDeviceChanged" value="71">
     15713      <desc>
     15714        See <link to="IStorageDeviceChangedEvent">IStorageDeviceChangedEvent</link>.
     15715      </desc>
     15716    </const>
    1569215717
    1569315718    <!-- Last event marker -->
    15694     <const name="Last" value="71">
     15719    <const name="Last" value="72">
    1569515720      <desc>
    1569615721        Must be last event, used for iterations and structures relying on numerical event values.
     
    1708817113  </interface>
    1708917114
     17115  <interface
     17116    name="IStorageDeviceChangedEvent" extends="IEvent"
     17117    uuid="8a5c2dce-e341-49d4-afce-c95979f7d70c"
     17118    wsmap="managed" autogen="VBoxEvent" id="OnStorageDeviceChanged"
     17119    >
     17120    <desc>
     17121      Notification when a
     17122      <link to="IMachine::mediumAttachments">storage device</link>
     17123      is attached or removed.
     17124    </desc>
     17125    <attribute name="storageDevice" type="IMediumAttachment" readonly="yes">
     17126      <desc>
     17127        Storage device that is subject to change.
     17128      </desc>
     17129    </attribute>
     17130    <attribute name="removed" type="boolean" readonly="yes">
     17131      <desc>
     17132        Flag whether the device was removed or added to the VM.
     17133      </desc>
     17134    </attribute>
     17135  </interface>
     17136
    1709017137  <module name="VBoxSVC" context="LocalServer">
    1709117138    <class name="VirtualBox" uuid="B1A7A4F2-47B9-4A1E-82B2-07CCD5323C3F"
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r36439 r36991  
    191191    HRESULT onUSBDeviceDetach(IN_BSTR aId, IVirtualBoxErrorInfo *aError);
    192192    HRESULT onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup);
     193    HRESULT onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove);
    193194    HRESULT getGuestProperty(IN_BSTR aKey, BSTR *aValue, LONG64 *aTimestamp, BSTR *aFlags);
    194195    HRESULT setGuestProperty(IN_BSTR aKey, IN_BSTR aValue, IN_BSTR aFlags);
     
    505506                               bool fAttachDetach,
    506507                               bool fForceUnmount,
     508                               bool fHotplug,
    507509                               PVM pVM,
    508510                               DeviceType_T *paLedDevType);
     
    571573#endif
    572574
     575    static DECLCALLBACK(int) attachStorageDevice(Console *pThis,
     576                                                 PVM pVM,
     577                                                 const char *pcszDevice,
     578                                                 unsigned uInstance,
     579                                                 StorageBus_T enmBus,
     580                                                 bool fUseHostIOCache,
     581                                                 IMediumAttachment *aMediumAtt);
     582    static DECLCALLBACK(int) detachStorageDevice(Console *pThis,
     583                                                 PVM pVM,
     584                                                 const char *pcszDevice,
     585                                                 unsigned uInstance,
     586                                                 StorageBus_T enmBus,
     587                                                 IMediumAttachment *aMediumAtt);
     588    HRESULT doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM pVM);
     589    HRESULT doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM pVM);
     590
    573591    static DECLCALLBACK(int)    fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser);
    574592
  • trunk/src/VBox/Main/include/MachineImpl.h

    r36898 r36991  
    638638    virtual HRESULT onSharedFolderChange() { return S_OK; }
    639639    virtual HRESULT onBandwidthGroupChange(IBandwidthGroup * /* aBandwidthGroup */) { return S_OK; }
     640    virtual HRESULT onStorageDeviceChange(IMediumAttachment * /* mediumAttachment */, BOOL /* remove */) { return S_OK; }
    640641
    641642    HRESULT saveRegistryEntry(settings::MachineRegistryEntry &data);
     
    833834    void commit();
    834835    void copyFrom(Machine *aThat);
     836    bool isControllerHotplugCapable(StorageControllerType_T enmCtrlType);
    835837
    836838    struct DeleteTask;
     
    10051007    HRESULT onSharedFolderChange();
    10061008    HRESULT onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup);
     1009    HRESULT onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove);
    10071010
    10081011    bool hasMatchingUSBFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs);
  • trunk/src/VBox/Main/include/SessionImpl.h

    r35638 r36991  
    9999    STDMETHOD(OnShowWindow)(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId);
    100100    STDMETHOD(OnBandwidthGroupChange)(IBandwidthGroup *aBandwidthGroup);
     101    STDMETHOD(OnStorageDeviceChange)(IMediumAttachment *aMediumAttachment, BOOL aRemove);
    101102    STDMETHOD(AccessGuestProperty)(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags,
    102103                                   BOOL aIsSetter, BSTR *aRetValue, LONG64 *aRetTimestamp, BSTR *aRetFlags);
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r36976 r36991  
    35563556                                             true /* fAttachDetach */,
    35573557                                             fForce /* fForceUnmount */,
     3558                                             false  /* fHotplug */,
    35583559                                             pVM,
    35593560                                             NULL /* paLedDevType */);
     
    35913592}
    35923593
     3594
     3595/**
     3596 * Attach a new storage device to the VM.
     3597 *
     3598 * @param aMediumAttachment The medium attachmentwhich is added.
     3599 * @param pVM               Safe VM handle.
     3600 *
     3601 * @note Locks this object for writing.
     3602 */
     3603HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM pVM)
     3604{
     3605    AutoCaller autoCaller(this);
     3606    AssertComRCReturnRC(autoCaller.rc());
     3607
     3608    /* We will need to release the write lock before calling EMT */
     3609    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     3610
     3611    HRESULT rc = S_OK;
     3612    const char *pszDevice = NULL;
     3613
     3614    SafeIfaceArray<IStorageController> ctrls;
     3615    rc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
     3616    AssertComRC(rc);
     3617    IMedium *pMedium;
     3618    rc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
     3619    AssertComRC(rc);
     3620    Bstr mediumLocation;
     3621    if (pMedium)
     3622    {
     3623        rc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
     3624        AssertComRC(rc);
     3625    }
     3626
     3627    Bstr attCtrlName;
     3628    rc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
     3629    AssertComRC(rc);
     3630    ComPtr<IStorageController> pStorageController;
     3631    for (size_t i = 0; i < ctrls.size(); ++i)
     3632    {
     3633        Bstr ctrlName;
     3634        rc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
     3635        AssertComRC(rc);
     3636        if (attCtrlName == ctrlName)
     3637        {
     3638            pStorageController = ctrls[i];
     3639            break;
     3640        }
     3641    }
     3642    if (pStorageController.isNull())
     3643        return setError(E_FAIL,
     3644                        tr("Could not find storage controller '%ls'"), attCtrlName.raw());
     3645
     3646    StorageControllerType_T enmCtrlType;
     3647    rc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
     3648    AssertComRC(rc);
     3649    pszDevice = convertControllerTypeToDev(enmCtrlType);
     3650
     3651    StorageBus_T enmBus;
     3652    rc = pStorageController->COMGETTER(Bus)(&enmBus);
     3653    AssertComRC(rc);
     3654    ULONG uInstance;
     3655    rc = pStorageController->COMGETTER(Instance)(&uInstance);
     3656    AssertComRC(rc);
     3657    BOOL fUseHostIOCache;
     3658    rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
     3659    AssertComRC(rc);
     3660
     3661    /*
     3662     * Call worker in EMT, that's faster and safer than doing everything
     3663     * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
     3664     * here to make requests from under the lock in order to serialize them.
     3665     */
     3666    PVMREQ pReq;
     3667    int vrc = VMR3ReqCall(pVM,
     3668                          VMCPUID_ANY,
     3669                          &pReq,
     3670                          0 /* no wait! */,
     3671                          VMREQFLAGS_VBOX_STATUS,
     3672                          (PFNRT)Console::attachStorageDevice,
     3673                          7,
     3674                          this,
     3675                          pVM,
     3676                          pszDevice,
     3677                          uInstance,
     3678                          enmBus,
     3679                          fUseHostIOCache,
     3680                          aMediumAttachment);
     3681
     3682    /* leave the lock before waiting for a result (EMT will call us back!) */
     3683    alock.leave();
     3684
     3685    if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
     3686    {
     3687        vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
     3688        AssertRC(vrc);
     3689        if (RT_SUCCESS(vrc))
     3690            vrc = pReq->iStatus;
     3691    }
     3692    VMR3ReqFree(pReq);
     3693
     3694    if (RT_SUCCESS(vrc))
     3695    {
     3696        LogFlowThisFunc(("Returns S_OK\n"));
     3697        return S_OK;
     3698    }
     3699
     3700    if (!pMedium)
     3701        return setError(E_FAIL,
     3702                        tr("Could not mount the media/drive '%ls' (%Rrc)"),
     3703                        mediumLocation.raw(), vrc);
     3704
     3705    return setError(E_FAIL,
     3706                    tr("Could not unmount the currently mounted media/drive (%Rrc)"),
     3707                    vrc);
     3708}
     3709
     3710
     3711/**
     3712 * Performs the storage attach operation in EMT.
     3713 *
     3714 * @returns VBox status code.
     3715 *
     3716 * @param   pThis           Pointer to the Console object.
     3717 * @param   pVM             The VM handle.
     3718 * @param   pcszDevice      The PDM device name.
     3719 * @param   uInstance       The PDM device instance.
     3720 *
     3721 * @thread  EMT
     3722 */
     3723DECLCALLBACK(int) Console::attachStorageDevice(Console *pConsole,
     3724                                               PVM pVM,
     3725                                               const char *pcszDevice,
     3726                                               unsigned uInstance,
     3727                                               StorageBus_T enmBus,
     3728                                               bool fUseHostIOCache,
     3729                                               IMediumAttachment *aMediumAtt)
     3730{
     3731    LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n",
     3732                 pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt));
     3733
     3734    AssertReturn(pConsole, VERR_INVALID_PARAMETER);
     3735
     3736    AutoCaller autoCaller(pConsole);
     3737    AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
     3738
     3739    /*
     3740     * Suspend the VM first.
     3741     *
     3742     * The VM must not be running since it might have pending I/O to
     3743     * the drive which is being changed.
     3744     */
     3745    bool fResume;
     3746    VMSTATE enmVMState = VMR3GetState(pVM);
     3747    switch (enmVMState)
     3748    {
     3749        case VMSTATE_RESETTING:
     3750        case VMSTATE_RUNNING:
     3751        {
     3752            LogFlowFunc(("Suspending the VM...\n"));
     3753            /* disable the callback to prevent Console-level state change */
     3754            pConsole->mVMStateChangeCallbackDisabled = true;
     3755            int rc = VMR3Suspend(pVM);
     3756            pConsole->mVMStateChangeCallbackDisabled = false;
     3757            AssertRCReturn(rc, rc);
     3758            fResume = true;
     3759            break;
     3760        }
     3761
     3762        case VMSTATE_SUSPENDED:
     3763        case VMSTATE_CREATED:
     3764        case VMSTATE_OFF:
     3765            fResume = false;
     3766            break;
     3767
     3768        case VMSTATE_RUNNING_LS:
     3769        case VMSTATE_RUNNING_FT:
     3770            return setErrorInternal(VBOX_E_INVALID_VM_STATE,
     3771                                    COM_IIDOF(IConsole),
     3772                                    getStaticComponentName(),
     3773                                    (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")),
     3774                                    false /*aWarning*/,
     3775                                    true /*aLogIt*/);
     3776
     3777        default:
     3778            AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED);
     3779    }
     3780
     3781    /* Determine the base path for the device instance. */
     3782    PCFGMNODE pCtlInst;
     3783    pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance);
     3784    AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
     3785
     3786    int rc = VINF_SUCCESS;
     3787    int rcRet = VINF_SUCCESS;
     3788
     3789    rcRet = pConsole->configMediumAttachment(pCtlInst,
     3790                                             pcszDevice,
     3791                                             uInstance,
     3792                                             enmBus,
     3793                                             fUseHostIOCache,
     3794                                             false /* fSetupMerge */,
     3795                                             false /* fBuiltinIoCache */,
     3796                                             0 /* uMergeSource */,
     3797                                             0 /* uMergeTarget */,
     3798                                             aMediumAtt,
     3799                                             pConsole->mMachineState,
     3800                                             NULL /* phrc */,
     3801                                             true /* fAttachDetach */,
     3802                                             false /* fForceUnmount */,
     3803                                             true   /* fHotplug */,
     3804                                             pVM,
     3805                                             NULL /* paLedDevType */);
     3806    /** @todo this dumps everything attached to this device instance, which
     3807     * is more than necessary. Dumping the changed LUN would be enough. */
     3808    CFGMR3Dump(pCtlInst);
     3809
     3810    /*
     3811     * Resume the VM if necessary.
     3812     */
     3813    if (fResume)
     3814    {
     3815        LogFlowFunc(("Resuming the VM...\n"));
     3816        /* disable the callback to prevent Console-level state change */
     3817        pConsole->mVMStateChangeCallbackDisabled = true;
     3818        rc = VMR3Resume(pVM);
     3819        pConsole->mVMStateChangeCallbackDisabled = false;
     3820        AssertRC(rc);
     3821        if (RT_FAILURE(rc))
     3822        {
     3823            /* too bad, we failed. try to sync the console state with the VMM state */
     3824            vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, pConsole);
     3825        }
     3826        /** @todo: if we failed with drive mount, then the VMR3Resume
     3827         * error (if any) will be hidden from the caller. For proper reporting
     3828         * of such multiple errors to the caller we need to enhance the
     3829         * IVirtualBoxError interface. For now, give the first error the higher
     3830         * priority.
     3831         */
     3832        if (RT_SUCCESS(rcRet))
     3833            rcRet = rc;
     3834    }
     3835
     3836    LogFlowFunc(("Returning %Rrc\n", rcRet));
     3837    return rcRet;
     3838}
     3839
     3840/**
     3841 * Attach a new storage device to the VM.
     3842 *
     3843 * @param aMediumAttachment The medium attachmentwhich is added.
     3844 * @param pVM               Safe VM handle.
     3845 *
     3846 * @note Locks this object for writing.
     3847 */
     3848HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM pVM)
     3849{
     3850    AutoCaller autoCaller(this);
     3851    AssertComRCReturnRC(autoCaller.rc());
     3852
     3853    /* We will need to release the write lock before calling EMT */
     3854    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     3855
     3856    HRESULT rc = S_OK;
     3857    const char *pszDevice = NULL;
     3858
     3859    SafeIfaceArray<IStorageController> ctrls;
     3860    rc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
     3861    AssertComRC(rc);
     3862    IMedium *pMedium;
     3863    rc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
     3864    AssertComRC(rc);
     3865    Bstr mediumLocation;
     3866    if (pMedium)
     3867    {
     3868        rc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
     3869        AssertComRC(rc);
     3870    }
     3871
     3872    Bstr attCtrlName;
     3873    rc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
     3874    AssertComRC(rc);
     3875    ComPtr<IStorageController> pStorageController;
     3876    for (size_t i = 0; i < ctrls.size(); ++i)
     3877    {
     3878        Bstr ctrlName;
     3879        rc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
     3880        AssertComRC(rc);
     3881        if (attCtrlName == ctrlName)
     3882        {
     3883            pStorageController = ctrls[i];
     3884            break;
     3885        }
     3886    }
     3887    if (pStorageController.isNull())
     3888        return setError(E_FAIL,
     3889                        tr("Could not find storage controller '%ls'"), attCtrlName.raw());
     3890
     3891    StorageControllerType_T enmCtrlType;
     3892    rc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
     3893    AssertComRC(rc);
     3894    pszDevice = convertControllerTypeToDev(enmCtrlType);
     3895
     3896    StorageBus_T enmBus;
     3897    rc = pStorageController->COMGETTER(Bus)(&enmBus);
     3898    AssertComRC(rc);
     3899    ULONG uInstance;
     3900    rc = pStorageController->COMGETTER(Instance)(&uInstance);
     3901    AssertComRC(rc);
     3902
     3903    /*
     3904     * Call worker in EMT, that's faster and safer than doing everything
     3905     * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
     3906     * here to make requests from under the lock in order to serialize them.
     3907     */
     3908    PVMREQ pReq;
     3909    int vrc = VMR3ReqCall(pVM,
     3910                          VMCPUID_ANY,
     3911                          &pReq,
     3912                          0 /* no wait! */,
     3913                          VMREQFLAGS_VBOX_STATUS,
     3914                          (PFNRT)Console::detachStorageDevice,
     3915                          6,
     3916                          this,
     3917                          pVM,
     3918                          pszDevice,
     3919                          uInstance,
     3920                          enmBus,
     3921                          aMediumAttachment);
     3922
     3923    /* leave the lock before waiting for a result (EMT will call us back!) */
     3924    alock.leave();
     3925
     3926    if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
     3927    {
     3928        vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
     3929        AssertRC(vrc);
     3930        if (RT_SUCCESS(vrc))
     3931            vrc = pReq->iStatus;
     3932    }
     3933    VMR3ReqFree(pReq);
     3934
     3935    if (RT_SUCCESS(vrc))
     3936    {
     3937        LogFlowThisFunc(("Returns S_OK\n"));
     3938        return S_OK;
     3939    }
     3940
     3941    if (!pMedium)
     3942        return setError(E_FAIL,
     3943                        tr("Could not mount the media/drive '%ls' (%Rrc)"),
     3944                        mediumLocation.raw(), vrc);
     3945
     3946    return setError(E_FAIL,
     3947                    tr("Could not unmount the currently mounted media/drive (%Rrc)"),
     3948                    vrc);
     3949}
     3950
     3951/**
     3952 * Performs the storage detach operation in EMT.
     3953 *
     3954 * @returns VBox status code.
     3955 *
     3956 * @param   pThis           Pointer to the Console object.
     3957 * @param   pVM             The VM handle.
     3958 * @param   pcszDevice      The PDM device name.
     3959 * @param   uInstance       The PDM device instance.
     3960 *
     3961 * @thread  EMT
     3962 */
     3963DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole,
     3964                                               PVM pVM,
     3965                                               const char *pcszDevice,
     3966                                               unsigned uInstance,
     3967                                               StorageBus_T enmBus,
     3968                                               IMediumAttachment *pMediumAtt)
     3969{
     3970    LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n",
     3971                 pConsole, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt));
     3972
     3973    AssertReturn(pConsole, VERR_INVALID_PARAMETER);
     3974
     3975    AutoCaller autoCaller(pConsole);
     3976    AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
     3977
     3978    /*
     3979     * Suspend the VM first.
     3980     *
     3981     * The VM must not be running since it might have pending I/O to
     3982     * the drive which is being changed.
     3983     */
     3984    bool fResume;
     3985    VMSTATE enmVMState = VMR3GetState(pVM);
     3986    switch (enmVMState)
     3987    {
     3988        case VMSTATE_RESETTING:
     3989        case VMSTATE_RUNNING:
     3990        {
     3991            LogFlowFunc(("Suspending the VM...\n"));
     3992            /* disable the callback to prevent Console-level state change */
     3993            pConsole->mVMStateChangeCallbackDisabled = true;
     3994            int rc = VMR3Suspend(pVM);
     3995            pConsole->mVMStateChangeCallbackDisabled = false;
     3996            AssertRCReturn(rc, rc);
     3997            fResume = true;
     3998            break;
     3999        }
     4000
     4001        case VMSTATE_SUSPENDED:
     4002        case VMSTATE_CREATED:
     4003        case VMSTATE_OFF:
     4004            fResume = false;
     4005            break;
     4006
     4007        case VMSTATE_RUNNING_LS:
     4008        case VMSTATE_RUNNING_FT:
     4009            return setErrorInternal(VBOX_E_INVALID_VM_STATE,
     4010                                    COM_IIDOF(IConsole),
     4011                                    getStaticComponentName(),
     4012                                    (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")),
     4013                                    false /*aWarning*/,
     4014                                    true /*aLogIt*/);
     4015
     4016        default:
     4017            AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED);
     4018    }
     4019
     4020    /* Determine the base path for the device instance. */
     4021    PCFGMNODE pCtlInst;
     4022    pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance);
     4023    AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
     4024
     4025#define H()         AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE)
     4026
     4027    HRESULT hrc;
     4028    int rc = VINF_SUCCESS;
     4029    int rcRet = VINF_SUCCESS;
     4030    unsigned uLUN;
     4031    LONG lDev;
     4032    LONG lPort;
     4033    DeviceType_T lType;
     4034    PCFGMNODE pLunL0 = NULL;
     4035    PCFGMNODE pCfg = NULL;
     4036
     4037    hrc = pMediumAtt->COMGETTER(Device)(&lDev);                             H();
     4038    hrc = pMediumAtt->COMGETTER(Port)(&lPort);                              H();
     4039    hrc = pMediumAtt->COMGETTER(Type)(&lType);                              H();
     4040    hrc = Console::convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN);    H();
     4041
     4042#undef H
     4043
     4044    /* First check if the LUN really exists. */
     4045    pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
     4046    if (pLunL0)
     4047    {
     4048            rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, 0);
     4049            if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
     4050                rc = VINF_SUCCESS;
     4051            AssertRCReturn(rc, rc);
     4052            CFGMR3RemoveNode(pLunL0);
     4053    }
     4054    else
     4055        AssertFailedReturn(VERR_INTERNAL_ERROR);
     4056
     4057    CFGMR3Dump(pCtlInst);
     4058
     4059    /*
     4060     * Resume the VM if necessary.
     4061     */
     4062    if (fResume)
     4063    {
     4064        LogFlowFunc(("Resuming the VM...\n"));
     4065        /* disable the callback to prevent Console-level state change */
     4066        pConsole->mVMStateChangeCallbackDisabled = true;
     4067        rc = VMR3Resume(pVM);
     4068        pConsole->mVMStateChangeCallbackDisabled = false;
     4069        AssertRC(rc);
     4070        if (RT_FAILURE(rc))
     4071        {
     4072            /* too bad, we failed. try to sync the console state with the VMM state */
     4073            vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, pConsole);
     4074        }
     4075        /** @todo: if we failed with drive mount, then the VMR3Resume
     4076         * error (if any) will be hidden from the caller. For proper reporting
     4077         * of such multiple errors to the caller we need to enhance the
     4078         * IVirtualBoxError interface. For now, give the first error the higher
     4079         * priority.
     4080         */
     4081        if (RT_SUCCESS(rcRet))
     4082            rcRet = rc;
     4083    }
     4084
     4085    LogFlowFunc(("Returning %Rrc\n", rcRet));
     4086    return rcRet;
     4087}
    35934088
    35944089/**
     
    45135008
    45145009/**
     5010 * Called by IInternalSessionControl::OnStorageDeviceChange().
     5011 *
     5012 * @note Locks this object for writing.
     5013 */
     5014HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove)
     5015{
     5016    LogFlowThisFunc(("\n"));
     5017
     5018    AutoCaller autoCaller(this);
     5019    AssertComRCReturnRC(autoCaller.rc());
     5020
     5021    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     5022
     5023    HRESULT rc = S_OK;
     5024
     5025    /* don't trigger medium change if the VM isn't running */
     5026    SafeVMPtrQuiet ptrVM(this);
     5027    if (ptrVM.isOk())
     5028    {
     5029        if (aRemove)
     5030            rc = doStorageDeviceDetach(aMediumAttachment, ptrVM);
     5031        else
     5032            rc = doStorageDeviceAttach(aMediumAttachment, ptrVM);
     5033        ptrVM.release();
     5034    }
     5035
     5036    /* notify console callbacks on success */
     5037    if (SUCCEEDED(rc))
     5038        fireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove);
     5039
     5040    LogFlowThisFunc(("Leaving rc=%#x\n", rc));
     5041    return rc;
     5042}
     5043
     5044/**
    45155045 * @note Temporarily locks this object for writing.
    45165046 */
     
    83328862                                          true /* fAttachDetach */,
    83338863                                          false /* fForceUnmount */,
     8864                                          false /* fHotplug */,
    83348865                                          pVM,
    83358866                                          NULL /* paLedDevType */);
  • trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp

    r36837 r36991  
    16511651                                            false /* fAttachDetach */,
    16521652                                            false /* fForceUnmount */,
     1653                                            false /* fHotplug */,
    16531654                                            pVM,
    16541655                                            paLedDevType);
     
    28132814                                    bool fAttachDetach,
    28142815                                    bool fForceUnmount,
     2816                                    bool fHotplug,
    28152817                                    PVM pVM,
    28162818                                    DeviceType_T *paLedDevType)
     
    28702872                }
    28712873
    2872                 rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, PDM_TACH_FLAGS_NOT_HOT_PLUG);
     2874                rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
    28732875                if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
    28742876                    rc = VINF_SUCCESS;
     
    31093111            /* Attach the new driver. */
    31103112            rc = PDMR3DeviceAttach(pVM, pcszDevice, uInstance, uLUN,
    3111                                 PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
     3113                                fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
    31123114            AssertRCReturn(rc, rc);
    31133115
  • trunk/src/VBox/Main/src-client/SessionImpl.cpp

    r35638 r36991  
    725725
    726726    return mConsole->onBandwidthGroupChange(aBandwidthGroup);
     727}
     728
     729STDMETHODIMP Session::OnStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove)
     730{
     731    LogFlowThisFunc(("\n"));
     732
     733    AutoCaller autoCaller(this);
     734    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
     735
     736    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     737    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
     738    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
     739
     740    return mConsole->onStorageDeviceChange(aMediumAttachment, aRemove);
    727741}
    728742
  • trunk/src/VBox/Main/src-server/MachineImpl.cpp

    r36898 r36991  
    34043404    AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
    34053405
    3406     if (Global::IsOnlineOrTransient(mData->mMachineState))
    3407         return setError(VBOX_E_INVALID_VM_STATE,
    3408                         tr("Invalid machine state: %s"),
    3409                         Global::stringifyMachineState(mData->mMachineState));
    3410 
    34113406    /* Check for an existing controller. */
    34123407    ComObjPtr<StorageController> ctl;
    34133408    rc = getStorageControllerByName(aControllerName, ctl, true /* aSetError */);
    34143409    if (FAILED(rc)) return rc;
     3410
     3411    StorageControllerType_T ctrlType;
     3412    rc = ctl->COMGETTER(ControllerType)(&ctrlType);
     3413    if (FAILED(rc))
     3414        return setError(E_FAIL,
     3415                        tr("Could not get type of controller '%ls'"),
     3416                        aControllerName);
     3417
     3418    /* Check that the controller can do hotplugging if we detach the device while the VM is running. */
     3419    bool fHotplug = false;
     3420    if (Global::IsOnlineOrTransient(mData->mMachineState))
     3421        fHotplug = true;
     3422
     3423    if (fHotplug && !isControllerHotplugCapable(ctrlType))
     3424        return setError(VBOX_E_INVALID_VM_STATE,
     3425                        tr("Invalid machine state: %s"),
     3426                        Global::stringifyMachineState(mData->mMachineState));
    34153427
    34163428    // check that the port and device are not out of range
     
    37843796    alock.release();
    37853797
     3798    if (fHotplug)
     3799        rc = onStorageDeviceChange(attachment, FALSE /* aRemove */);
     3800
    37863801    mParent->saveRegistries(llRegistriesThatNeedSaving);
    37873802
     
    38093824    AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
    38103825
     3826    /* Check for an existing controller. */
     3827    ComObjPtr<StorageController> ctl;
     3828    rc = getStorageControllerByName(aControllerName, ctl, true /* aSetError */);
     3829    if (FAILED(rc)) return rc;
     3830
     3831    StorageControllerType_T ctrlType;
     3832    rc = ctl->COMGETTER(ControllerType)(&ctrlType);
     3833    if (FAILED(rc))
     3834        return setError(E_FAIL,
     3835                        tr("Could not get type of controller '%ls'"),
     3836                        aControllerName);
     3837
     3838    /* Check that the controller can do hotplugging if we detach the device while the VM is running. */
     3839    bool fHotplug = false;
    38113840    if (Global::IsOnlineOrTransient(mData->mMachineState))
     3841        fHotplug = true;
     3842
     3843    if (fHotplug && !isControllerHotplugCapable(ctrlType))
    38123844        return setError(VBOX_E_INVALID_VM_STATE,
    38133845                        tr("Invalid machine state: %s"),
     
    38233855                        aDevice, aControllerPort, aControllerName);
    38243856
     3857    /*
     3858     * The VM has to detach the device before we delete any implicit diffs.
     3859     * If this fails we can roll back without loosing data.
     3860     */
     3861    if (fHotplug)
     3862    {
     3863        alock.leave();
     3864        rc = onStorageDeviceChange(pAttach, TRUE /* aRemove */);
     3865        alock.enter();
     3866    }
     3867    if (FAILED(rc)) return rc;
     3868
     3869    /* If we are here everything went well and we can delete the implicit now. */
    38253870    rc = detachDevice(pAttach, alock, NULL /* pSnapshot */, &llRegistriesThatNeedSaving);
    38263871
     
    1011610161    for (ULONG slot = 0; slot < RT_ELEMENTS(mParallelPorts); slot++)
    1011710162        mParallelPorts[slot]->copyFrom(aThat->mParallelPorts[slot]);
     10163}
     10164
     10165/**
     10166 * Returns whether the given storage controller is hotplug capable.
     10167 *
     10168 * @returns true if the controller supports hotplugging
     10169 *          false otherwise.
     10170 * @param   enmCtrlType    The controller type to check for.
     10171 */
     10172bool Machine::isControllerHotplugCapable(StorageControllerType_T enmCtrlType)
     10173{
     10174    switch (enmCtrlType)
     10175    {
     10176        case StorageControllerType_IntelAhci:
     10177            return true;
     10178        case StorageControllerType_LsiLogic:
     10179        case StorageControllerType_LsiLogicSas:
     10180        case StorageControllerType_BusLogic:
     10181        case StorageControllerType_PIIX3:
     10182        case StorageControllerType_PIIX4:
     10183        case StorageControllerType_ICH6:
     10184        case StorageControllerType_I82078:
     10185        default:
     10186            return false;
     10187    }
    1011810188}
    1011910189
     
    1183611906
    1183711907/**
     11908 *  @note Locks this object for reading.
     11909 */
     11910HRESULT SessionMachine::onStorageDeviceChange(IMediumAttachment *aAttachment, BOOL aRemove)
     11911{
     11912    LogFlowThisFunc(("\n"));
     11913
     11914    AutoCaller autoCaller(this);
     11915    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
     11916
     11917    ComPtr<IInternalSessionControl> directControl;
     11918    {
     11919        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     11920        directControl = mData->mSession.mDirectControl;
     11921    }
     11922
     11923    /* ignore notifications sent after #OnSessionEnd() is called */
     11924    if (!directControl)
     11925        return S_OK;
     11926
     11927    return directControl->OnStorageDeviceChange(aAttachment, aRemove);
     11928}
     11929
     11930/**
    1183811931 *  Returns @c true if this machine's USB controller reports it has a matching
    1183911932 *  filter for the given USB device and @c false otherwise.
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette