VirtualBox

Changeset 61483 in vbox


Ignore:
Timestamp:
Jun 6, 2016 8:54:30 AM (9 years ago)
Author:
vboxsync
Message:

bugref:8344. First variant of "move" operation for medium. Standalone task "MoveTask". "setLocation" Medium API method was implemented.

Location:
trunk/src/VBox
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp

    r57358 r61483  
    478478    { "compact",        'c', RTGETOPT_REQ_NOTHING },    // deprecated
    479479    { "--resize",       'r', RTGETOPT_REQ_UINT64 },
    480     { "--resizebyte",   'R', RTGETOPT_REQ_UINT64 }
     480    { "--resizebyte",   'R', RTGETOPT_REQ_UINT64 },
     481    { "--move",         'm', RTGETOPT_REQ_STRING }
    481482};
    482483
     
    501502    bool fModifyCompact = false;
    502503    bool fModifyResize = false;
     504    bool fModifyLocation = false;
    503505    uint64_t cbResize = 0;
    504506    const char *pszFilenameOrUuid = NULL;
     507    const char *pszNewLocation = NULL;
    505508
    506509    int c;
     
    592595                break;
    593596
     597            case 'm':   // --move
     598                /* Get a new location  */
     599                pszNewLocation = RTStrDup(ValueUnion.psz);
     600                fModifyLocation = true;
     601                break;
     602
    594603            case VINF_GETOPT_NOT_OPTION:
    595604                if (!pszFilenameOrUuid)
     
    622631        return errorSyntax(USAGE_MODIFYMEDIUM, "Medium name or UUID required");
    623632
    624     if (!fModifyMediumType && !fModifyAutoReset && !fModifyProperties && !fModifyCompact && !fModifyResize)
     633    if (!fModifyMediumType && !fModifyAutoReset && !fModifyProperties && !fModifyCompact && !fModifyResize && !fModifyLocation)
    625634        return errorSyntax(USAGE_MODIFYMEDIUM, "No operation specified");
    626635
     
    703712                RTMsgError("Failed to resize medium!");
    704713        }
     714    }
     715
     716    if (fModifyLocation)
     717    {
     718        do
     719        {
     720            ComPtr<IProgress> pProgress;
     721            Utf8Str strLocation(pszNewLocation);
     722            CHECK_ERROR(pMedium, SetLocation(Bstr(pszNewLocation).raw(), pProgress.asOutParam()));
     723
     724            if (SUCCEEDED(rc) && !pProgress.isNull())
     725            {
     726                rc = showProgress(pProgress);
     727                CHECK_PROGRESS_ERROR(pProgress, ("Failed to move medium"));
     728            }
     729
     730            Bstr uuid;
     731            CHECK_ERROR_BREAK(pMedium, COMGETTER(Id)(uuid.asOutParam()));
     732
     733            RTPrintf("Move medium with UUID %s finished \n", Utf8Str(uuid).c_str());
     734        }
     735        while (0);
    705736    }
    706737
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp

    r61226 r61483  
    11351135                     "                            [--compact]\n"
    11361136                     "                            [--resize <megabytes>|--resizebyte <bytes>]\n"
     1137                     "                            [--move <full path to a new location>]"
    11371138                     "\n", SEP);
    11381139
  • trunk/src/VBox/Main/include/MediumImpl.h

    r61137 r61483  
    317317                                  std::vector<com::Utf8Str> &aReturnValues);
    318318
     319    HRESULT i_preparationForMoving(const Utf8Str &aLocation);
     320    bool    i_isMoveOperation(const ComObjPtr<Medium> &pTarget) const;
     321    bool    i_resetMoveOperationData();
     322    Utf8Str i_getNewLocationForMoving() const;
     323
    319324    static DECLCALLBACK(void) i_vdErrorCall(void *pvUser, int rc, RT_SRC_POS_DECL,
    320325                                            const char *pszFormat, va_list va);
     
    360365    class CreateDiffTask;
    361366    class CloneTask;
     367    class MoveTask;
    362368    class CompactTask;
    363369    class ResizeTask;
     
    372378    friend class CreateDiffTask;
    373379    friend class CloneTask;
     380    friend class MoveTask;
    374381    friend class CompactTask;
    375382    friend class ResizeTask;
     
    388395    HRESULT i_taskMergeHandler(Medium::MergeTask &task);
    389396    HRESULT i_taskCloneHandler(Medium::CloneTask &task);
     397    HRESULT i_taskMoveHandler(Medium::MoveTask &task);
    390398    HRESULT i_taskDeleteHandler(Medium::DeleteTask &task);
    391399    HRESULT i_taskResetHandler(Medium::ResetTask &task);
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r61174 r61483  
    108108          numCreateDiffTasks(0),
    109109          vdDiskIfaces(NULL),
    110           vdImageIfaces(NULL)
     110          vdImageIfaces(NULL),
     111          fMoveThisMedium(false)
    111112    { }
    112113
     
    181182    PVDINTERFACE vdDiskIfaces;
    182183    PVDINTERFACE vdImageIfaces;
     184
     185    /** Flag if the medium is going to move to a new
     186     *  location. */
     187    bool fMoveThisMedium;
     188    /** new location path  */
     189    Utf8Str strNewLocationFull;
    183190};
    184191
     
    405412};
    406413
     414class Medium::MoveTask : public Medium::Task
     415{
     416public:
     417    MoveTask(Medium *aMedium,
     418              Progress *aProgress,
     419              MediumVariant_T aVariant,
     420              MediumLockList *aMediumLockList,
     421              bool fKeepMediumLockList = false)
     422        : Medium::Task(aMedium, aProgress),
     423          mpMediumLockList(aMediumLockList),
     424          mVariant(aVariant),
     425          mfKeepMediumLockList(fKeepMediumLockList)
     426    {
     427        AssertReturnVoidStmt(aMediumLockList != NULL, mRC = E_FAIL);
     428    }
     429
     430    ~MoveTask()
     431    {
     432        if (!mfKeepMediumLockList && mpMediumLockList)
     433            delete mpMediumLockList;
     434    }
     435
     436    MediumLockList *mpMediumLockList;
     437    MediumVariant_T mVariant;
     438
     439private:
     440    virtual HRESULT handler();
     441
     442    bool mfKeepMediumLockList;
     443};
     444
    407445class Medium::CompactTask : public Medium::Task
    408446{
     
    854892{
    855893    return mMedium->i_taskCloneHandler(*this);
     894}
     895
     896/**
     897 * Implementation code for the "move" task.
     898 */
     899HRESULT Medium::MoveTask::handler()
     900{
     901    return mMedium->i_taskMoveHandler(*this);
    856902}
    857903
     
    28992945HRESULT Medium::setLocation(const com::Utf8Str &aLocation, ComPtr<IProgress> &aProgress)
    29002946{
    2901     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2902     NOREF(aLocation);
    2903     NOREF(aProgress);
    2904 
     2947
     2948    ComObjPtr<Medium> pParent;
     2949    ComObjPtr<Progress> pProgress;
     2950    HRESULT rc = S_OK;
     2951    Medium::Task *pTask = NULL;
     2952
     2953    try
     2954    {
    29052955    /// @todo NEWMEDIA for file names, add the default extension if no extension
    29062956    /// is present (using the information from the VD backend which also implies
     
    29122962    /// this medium), this will also require to add the mRegistered flag to data
    29132963
    2914     ReturnComNotImplemented();
     2964        // locking: we need the tree lock first because we access parent pointers
     2965        // and we need to write-lock the media involved
     2966        uint32_t    cHandles    = 2;
     2967        LockHandle* pHandles[2] = { &m->pVirtualBox->i_getMediaTreeLockHandle(),
     2968                                    this->lockHandle() };
     2969
     2970        AutoWriteLock alock(cHandles,
     2971                            pHandles
     2972                            COMMA_LOCKVAL_SRC_POS);
     2973
     2974        /* Set needed variables for "moving" procedure. It'll be used later in separate thread task */
     2975        rc = i_preparationForMoving(aLocation);
     2976        if (FAILED(rc))
     2977        {
     2978            rc = setError(VERR_NO_CHANGE,
     2979                       tr("Medium '%s' is already in the correct location"),
     2980                       i_getLocationFull().c_str());
     2981            return rc;
     2982        }
     2983
     2984        /* Check VMs which have this medium attached to*/
     2985        std::vector<com::Guid> aMachineIds;
     2986        rc = getMachineIds(aMachineIds);
     2987        std::vector<com::Guid>::const_iterator currMachineID = aMachineIds.begin();
     2988        std::vector<com::Guid>::const_iterator lastMachineID = aMachineIds.end();
     2989
     2990        while(currMachineID != lastMachineID)
     2991        {
     2992            Guid id(*currMachineID);
     2993            ComObjPtr<Machine> aMachine;
     2994
     2995            alock.release();
     2996            rc = m->pVirtualBox->i_findMachine(id, false, true, &aMachine);
     2997            alock.acquire();
     2998
     2999            if (SUCCEEDED(rc))
     3000            {
     3001                MachineState_T aState;
     3002                ComObjPtr<SessionMachine> sm;
     3003                ComPtr<IInternalSessionControl> ctl;
     3004
     3005                alock.release();
     3006                bool ses = aMachine->i_isSessionOpenVM(sm, &ctl);
     3007                alock.acquire();
     3008
     3009                if (ses)
     3010                {
     3011                    rc = setError(VERR_VM_UNEXPECTED_VM_STATE,
     3012                                  tr("At least VM '%s' to whom this medium '%s' attached has the opened session now. "
     3013                                     "Stop all needed VM before set a new location."),
     3014                                  id.toString().c_str(),
     3015                                  i_getLocationFull().c_str());
     3016                    throw rc;
     3017                }
     3018            }
     3019            ++currMachineID;
     3020        }
     3021
     3022        /* Build the source lock list. */
     3023        MediumLockList *pMediumLockList(new MediumLockList());
     3024        alock.release();
     3025        rc = i_createMediumLockList(true /* fFailIfInaccessible */,
     3026                                    this /* pToLockWrite */,
     3027                                    true /* fMediumLockWriteAll */,
     3028                                    NULL,
     3029                                    *pMediumLockList);
     3030        alock.acquire();
     3031        if (FAILED(rc))
     3032        {
     3033            delete pMediumLockList;
     3034            throw setError(rc,
     3035                           tr("Failed to create medium lock list for '%s'"),
     3036                           i_getLocationFull().c_str());
     3037        }
     3038        alock.release();
     3039        rc = pMediumLockList->Lock();
     3040        alock.acquire();
     3041        if (FAILED(rc))
     3042        {
     3043            delete pMediumLockList;
     3044            throw setError(rc,
     3045                           tr("Failed to lock media '%s'"),
     3046                           i_getLocationFull().c_str());
     3047        }
     3048
     3049        pProgress.createObject();
     3050        rc = pProgress->init(m->pVirtualBox,
     3051                             static_cast <IMedium *>(this),
     3052                             BstrFmt(tr("Moving medium '%s'"), m->strLocationFull.c_str()).raw(),
     3053                             TRUE /* aCancelable */);
     3054
     3055        /* Do the disk moving. */
     3056        if(SUCCEEDED(rc))
     3057        {
     3058            ULONG mediumVariantFlags = i_getVariant();
     3059
     3060            /* setup task object to carry out the operation asynchronously */
     3061            pTask = new Medium::MoveTask(this, pProgress,
     3062                                         (MediumVariant_T)mediumVariantFlags,
     3063                                         pMediumLockList);
     3064            rc = pTask->rc();
     3065            AssertComRC(rc);
     3066            if (FAILED(rc))
     3067                throw rc;
     3068        }
     3069
     3070    }
     3071    catch (HRESULT aRC) { rc = aRC; }
     3072
     3073    if (SUCCEEDED(rc))
     3074    {
     3075        rc = i_startThread(pTask);
     3076
     3077        if (SUCCEEDED(rc))
     3078            pProgress.queryInterfaceTo(aProgress.asOutParam());
     3079    }
     3080    else
     3081    {
     3082        if (pTask != NULL)
     3083            delete pTask;
     3084    }
     3085
     3086    return rc;
    29153087}
    29163088
     
    60996271}
    61006272
     6273/**
     6274 * Preparation to move this medium to a new location
     6275 *
     6276 * @param aLocation Location of the storage unit. If the location is a FS-path,
     6277 *                  then it can be relative to the VirtualBox home directory.
     6278 *
     6279 * @note Must be called from under this object's write lock.
     6280 */
     6281HRESULT Medium::i_preparationForMoving(const Utf8Str &aLocation)
     6282{
     6283    HRESULT rc = E_FAIL;
     6284
     6285    if (i_getLocationFull() != aLocation)
     6286    {
     6287        m->strNewLocationFull = aLocation;
     6288        m->fMoveThisMedium = true;
     6289        rc = S_OK;
     6290    }
     6291
     6292    return rc;
     6293}
     6294
     6295/**
     6296 * Checking whether current operation "moving" or not
     6297 */
     6298bool Medium::i_isMoveOperation(const ComObjPtr<Medium> &aTarget) const
     6299{
     6300    return (this == aTarget && m->fMoveThisMedium == true) ? true:false;
     6301}
     6302
     6303bool Medium::i_resetMoveOperationData()
     6304{
     6305    m->strNewLocationFull.setNull();
     6306    m->fMoveThisMedium = false;
     6307    return true;
     6308}
     6309
     6310Utf8Str Medium::i_getNewLocationForMoving() const
     6311{
     6312    if(m->fMoveThisMedium == true)
     6313        return m->strNewLocationFull;
     6314    else
     6315        return Utf8Str();
     6316}
    61016317////////////////////////////////////////////////////////////////////////////////
    61026318//
     
    82208436    {
    82218437        if (!pParent.isNull())
     8438        {
     8439
    82228440            if (pParent->i_getDepth() >= SETTINGS_MEDIUM_DEPTH_MAX)
    82238441            {
     
    82278445                               pParent->m->strLocationFull.c_str());
    82288446            }
     8447        }
    82298448
    82308449        /* Lock all in {parent,child} order. The lock is also used as a
     
    85208739
    85218740/**
     8741 * Implementation code for the "move" task.
     8742 *
     8743 * This only gets started from Medium::SetLocation() and always
     8744 * runs asynchronously.
     8745 *
     8746 * @param task
     8747 * @return
     8748 */
     8749HRESULT Medium::i_taskMoveHandler(Medium::MoveTask &task)
     8750{
     8751
     8752    HRESULT rcOut = S_OK;
     8753
     8754    /* pTarget is equal "this" in our case */
     8755    const ComObjPtr<Medium> &pTarget = task.mMedium;
     8756
     8757    uint64_t size = 0, logicalSize = 0;
     8758    MediumVariant_T variant = MediumVariant_Standard;
     8759
     8760    /*
     8761     * it's exactly moving, not cloning
     8762     */
     8763    if (!i_isMoveOperation(pTarget))
     8764    {
     8765        HRESULT rc = setError(VBOX_E_FILE_ERROR,
     8766                              tr("Wrong preconditions for moving the medium %s"),
     8767                              pTarget->m->strLocationFull.c_str());
     8768        return rc;
     8769    }
     8770
     8771    try
     8772    {
     8773        /* Lock all in {parent,child} order. The lock is also used as a
     8774         * signal from the task initiator (which releases it only after
     8775         * RTThreadCreate()) that we can start the job. */
     8776
     8777        AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
     8778
     8779        PVBOXHDD hdd;
     8780        int vrc = VDCreate(m->vdDiskIfaces, i_convertDeviceType(), &hdd);
     8781        ComAssertRCThrow(vrc, E_FAIL);
     8782
     8783        try
     8784        {
     8785            /* Open all media in the source chain. */
     8786            MediumLockList::Base::const_iterator sourceListBegin =
     8787                task.mpMediumLockList->GetBegin();
     8788            MediumLockList::Base::const_iterator sourceListEnd =
     8789                task.mpMediumLockList->GetEnd();
     8790            for (MediumLockList::Base::const_iterator it = sourceListBegin;
     8791                 it != sourceListEnd;
     8792                 ++it)
     8793            {
     8794                const MediumLock &mediumLock = *it;
     8795                const ComObjPtr<Medium> &pMedium = mediumLock.GetMedium();
     8796                AutoWriteLock alock(pMedium COMMA_LOCKVAL_SRC_POS);
     8797
     8798                /* sanity check */
     8799                Assert(pMedium->m->state == MediumState_LockedWrite);
     8800
     8801                vrc = VDOpen(hdd,
     8802                             pMedium->m->strFormat.c_str(),
     8803                             pMedium->m->strLocationFull.c_str(),
     8804                             VD_OPEN_FLAGS_NORMAL,
     8805                             pMedium->m->vdImageIfaces);
     8806                if (RT_FAILURE(vrc))
     8807                    throw setError(VBOX_E_FILE_ERROR,
     8808                                   tr("Could not open the medium storage unit '%s'%s"),
     8809                                   pMedium->m->strLocationFull.c_str(),
     8810                                   i_vdError(vrc).c_str());
     8811            }
     8812
     8813            /* we can directly use pTarget->m->"variables" but for better reading we use local copies */
     8814            Guid targetId = pTarget->m->id;
     8815            Utf8Str targetFormat(pTarget->m->strFormat);
     8816            uint64_t targetCapabilities = pTarget->m->formatObj->i_getCapabilities();
     8817
     8818            /*
     8819             * change target location
     8820             * m->strNewLocationFull has been set already together with m->fMoveThisMedium in
     8821             * i_preparationForMoving()
     8822             */
     8823            Utf8Str targetLocation = i_getNewLocationForMoving();
     8824
     8825            /* unlock before the potentially lengthy operation */
     8826            thisLock.release();
     8827
     8828            /* ensure the target directory exists */
     8829            if (targetCapabilities & MediumFormatCapabilities_File)
     8830            {
     8831                HRESULT rc = VirtualBox::i_ensureFilePathExists(targetLocation,
     8832                                                                !(task.mVariant & MediumVariant_NoCreateDir) /* fCreate */);
     8833                if (FAILED(rc))
     8834                    throw rc;
     8835            }
     8836
     8837            try
     8838            {
     8839                vrc = VDCopy(hdd,
     8840                             VD_LAST_IMAGE,
     8841                             hdd,
     8842                             targetFormat.c_str(),
     8843                             targetLocation.c_str(),
     8844                             true /* fMoveByRename */,
     8845                             0 /* cbSize */,
     8846                             VD_IMAGE_FLAGS_NONE,
     8847                             targetId.raw(),
     8848                             VD_OPEN_FLAGS_NORMAL,
     8849                             NULL /* pVDIfsOperation */,
     8850                             NULL,
     8851                             NULL);
     8852                if (RT_FAILURE(vrc))
     8853                    throw setError(VBOX_E_FILE_ERROR,
     8854                                   tr("Could not move medium '%s'%s"),
     8855                                   targetLocation.c_str(), i_vdError(vrc).c_str());
     8856                size = VDGetFileSize(hdd, VD_LAST_IMAGE);
     8857                logicalSize = VDGetSize(hdd, VD_LAST_IMAGE);
     8858                unsigned uImageFlags;
     8859                vrc = VDGetImageFlags(hdd, 0, &uImageFlags);
     8860                if (RT_SUCCESS(vrc))
     8861                    variant = (MediumVariant_T)uImageFlags;
     8862
     8863                /*
     8864                 * set current location, because VDCopy\VDCopyEx doesn't do it.
     8865                 * also reset moving flag
     8866                 */
     8867                i_resetMoveOperationData();
     8868                m->strLocationFull = targetLocation;
     8869
     8870            }
     8871            catch (HRESULT aRC) { rcOut = aRC; }
     8872
     8873        }
     8874        catch (HRESULT aRC) { rcOut = aRC; }
     8875
     8876        VDDestroy(hdd);
     8877    }
     8878    catch (HRESULT aRC) { rcOut = aRC; }
     8879
     8880    ErrorInfoKeeper eik;
     8881    MultiResult mrc(rcOut);
     8882
     8883    // now, at the end of this task (always asynchronous), save the settings
     8884    if (SUCCEEDED(mrc))
     8885    {
     8886        // save the settings
     8887        i_markRegistriesModified();
     8888        /* collect multiple errors */
     8889        eik.restore();
     8890        m->pVirtualBox->i_saveModifiedRegistries();
     8891        eik.fetch();
     8892    }
     8893
     8894    /* Everything is explicitly unlocked when the task exits,
     8895     * as the task destruction also destroys the source chain. */
     8896
     8897    task.mpMediumLockList->Clear();
     8898
     8899    return mrc;
     8900}
     8901
     8902/**
    85228903 * Implementation code for the "delete" task.
    85238904 *
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