VirtualBox

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


Ignore:
Timestamp:
Mar 20, 2009 1:10:58 PM (16 years ago)
Author:
vboxsync
Message:

Main/HardDisk: implement flattenTo() API. a bit code duplication left to be cleaned up later.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/HardDiskImpl.cpp

    r17974 r18115  
    5959{
    6060    enum Operation { CreateBase, CreateDiff,
    61                      Merge, Clone, Delete, Reset };
     61                     Merge, Clone, Flatten, Delete, Reset };
    6262
    6363    HardDisk *that;
     
    9191    }
    9292
     93    void setData (CloneChain *aChain)
     94    {
     95        AssertReturnVoid (aChain != NULL);
     96        d.source.reset (aChain);
     97    }
     98
    9399    HRESULT startThread();
    94100    HRESULT runNow();
     
    106112        HardDiskVariant_T variant;
    107113
    108         /* CreateDiff */
     114        /* CreateDiff, Flatten */
    109115
    110116        ComObjPtr<HardDisk> target;
     117
     118        /* Flatten */
     119
     120        /** Hard disks to open, in {parent,child} order */
     121        std::auto_ptr <CloneChain> source;
    111122
    112123        /* Merge */
     
    423434    /** Children of the source when backward merge (if any) */
    424435    List mChildren;
     436};
     437
     438////////////////////////////////////////////////////////////////////////////////
     439
     440/**
     441 * Helper class for clone operations.
     442 *
     443 * @note It is assumed that when modifying methods of this class are called,
     444 *       HardDisk::treeLock() is held in read mode.
     445 */
     446class HardDisk::CloneChain : public HardDisk::List,
     447                             public com::SupportErrorInfoBase
     448{
     449public:
     450
     451    CloneChain () {}
     452
     453    ~CloneChain()
     454    {
     455        for (iterator it = begin(); it != end(); ++ it)
     456        {
     457            AutoWriteLock alock (*it);
     458            Assert ((*it)->m.state == MediaState_LockedRead);
     459            if ((*it)->m.state == MediaState_LockedRead)
     460                (*it)->UnlockRead (NULL);
     461
     462            (*it)->releaseCaller();
     463        }
     464    }
     465
     466    HRESULT addImage (HardDisk *aHardDisk)
     467    {
     468        HRESULT rc = aHardDisk->addCaller();
     469        CheckComRCReturnRC (rc);
     470
     471        push_front (aHardDisk);
     472
     473        return S_OK;
     474    }
     475
     476    HRESULT lockImagesRead ()
     477    {
     478        /* Lock all disks in the chain in {parent, child} order,
     479         * and make sure they are accessible. */
     480        /// @todo code duplication with SessionMachine::lockMedia, see below
     481        ErrorInfoKeeper eik (true /* aIsNull */);
     482        MultiResult mrc (S_OK);
     483        for (List::const_iterator it = begin(); it != end(); ++ it)
     484        {
     485            HRESULT rc = S_OK;
     486            MediaState_T mediaState;
     487            rc = (*it)->LockRead(&mediaState);
     488            CheckComRCReturnRC (rc);
     489
     490            if (mediaState == MediaState_Inaccessible)
     491            {
     492                rc = (*it)->COMGETTER(State) (&mediaState);
     493                CheckComRCReturnRC (rc);
     494                Assert (mediaState == MediaState_LockedRead);
     495
     496                /* Note that we locked the medium already, so use the error
     497                 * value to see if there was an accessibility failure */
     498                Bstr error;
     499                rc = (*it)->COMGETTER(LastAccessError) (error.asOutParam());
     500                CheckComRCReturnRC (rc);
     501
     502                if (!error.isNull())
     503                {
     504                    Bstr loc;
     505                    rc = (*it)->COMGETTER(Location) (loc.asOutParam());
     506                    CheckComRCThrowRC (rc);
     507
     508                    /* collect multiple errors */
     509                    eik.restore();
     510
     511                    /* be in sync with MediumBase::setStateError() */
     512                    Assert (!error.isEmpty());
     513                    mrc = setError (E_FAIL,
     514                        tr ("Medium '%ls' is not accessible. %ls"),
     515                        loc.raw(), error.raw());
     516
     517                    eik.fetch();
     518                }
     519            }
     520        }
     521
     522        eik.restore();
     523        CheckComRCReturnRC ((HRESULT) mrc);
     524
     525        return S_OK;
     526    }
     527
     528protected:
     529
     530    // SupportErrorInfoBase interface
     531    const GUID &mainInterfaceID() const { return COM_IIDOF (IHardDisk); }
     532    const char *componentName() const { return HardDisk::ComponentName(); }
     533
     534private:
     535
    425536};
    426537
     
    713824     * they will still be read and accessible (for possible backward
    714825     * compatibility; we can also clean them up from the XML upon next
    715      * XML format versino change if we wish) */
     826     * XML format version change if we wish) */
    716827    Key::List properties = aNode.keys ("Property");
    717828    for (Key::List::const_iterator it = properties.begin();
     
    13301441    AutoMultiWriteLock2 alock (this, target);
    13311442
    1332     /* We want to be locked for reading as long as the clone hard disk is being
    1333      * created*/
     1443    /* We want to be locked for reading as long as the clone hard disk is
     1444     * being created. */
    13341445    rc = LockRead (NULL);
    13351446    CheckComRCReturnRC (rc);
     
    13881499
    13891500STDMETHODIMP HardDisk::FlattenTo (IHardDisk *aTarget,
    1390                                   HardDiskVariant_T /* aVariant */,
     1501                                  HardDiskVariant_T aVariant,
    13911502                                  IProgress **aProgress)
    13921503{
     
    13971508    CheckComRCReturnRC (autoCaller.rc());
    13981509
    1399     ReturnComNotImplemented();
     1510    ComObjPtr <HardDisk> target;
     1511    HRESULT rc = mVirtualBox->cast (aTarget, target);
     1512    CheckComRCReturnRC (rc);
     1513
     1514    AutoMultiWriteLock2 alock (this, target);
     1515
     1516    ComObjPtr <Progress> progress;
     1517
     1518    try
     1519    {
     1520        if (target->m.state != MediaState_NotCreated)
     1521            throw target->setStateError();
     1522
     1523        /** @todo separate out creating/locking an image chain from
     1524         * SessionMachine::lockMedia and use it from here too.
     1525         * logically this belongs into HardDisk functionality. */
     1526
     1527        /* we walk the tree */
     1528        AutoReadLock treeLock (this->treeLock());
     1529
     1530        /* Build the chain and at the end lock images in the proper order. */
     1531        std::auto_ptr <CloneChain> chain (new CloneChain ());
     1532        HardDisk *hd = this;
     1533        do
     1534        {
     1535            rc = chain->addImage(hd);
     1536            CheckComRCThrowRC (rc);
     1537
     1538            hd = hd->mParent;
     1539        } while (hd);
     1540        rc = chain->lockImagesRead();
     1541        CheckComRCThrowRC (rc);
     1542
     1543        progress.createObject();
     1544        rc = progress->init (mVirtualBox, static_cast <IHardDisk *> (this),
     1545            BstrFmt (tr ("Creating flattened clone hard disk '%ls'"),
     1546                     target->m.locationFull.raw()),
     1547            FALSE /* aCancelable */);
     1548        CheckComRCThrowRC (rc);
     1549
     1550        /* setup task object and thread to carry out the operation
     1551         * asynchronously */
     1552
     1553        std::auto_ptr <Task> task (new Task (this, progress, Task::Flatten));
     1554        AssertComRCThrowRC (task->autoCaller.rc());
     1555
     1556        task->setData (target);
     1557        task->d.variant = aVariant;
     1558        task->setData (chain.release());
     1559
     1560        rc = task->startThread();
     1561        CheckComRCThrowRC (rc);
     1562
     1563        /* go to Creating state before leaving the lock */
     1564        target->m.state = MediaState_Creating;
     1565
     1566        /* task is now owned (or already deleted) by taskThread() so release it */
     1567        task.release();
     1568    }
     1569    catch (HRESULT aRC)
     1570    {
     1571        rc = aRC;
     1572    }
     1573
     1574    if (FAILED (rc))
     1575    {
     1576        HRESULT rc2 = UnlockRead (NULL);
     1577        AssertComRC (rc2);
     1578        /* Note: on success, taskThread() will unlock this */
     1579    }
     1580    else
     1581    {
     1582        /* return progress to the caller */
     1583        progress.queryInterfaceTo (aProgress);
     1584    }
     1585
     1586    return rc;
    14001587}
    14011588
     
    17511938 * changes.
    17521939 *
    1753  * This method is to be called prior to calling the #discrad() to perform
     1940 * This method is to be called prior to calling the #discard() to perform
    17541941 * necessary consistency checks and place involved hard disks to appropriate
    17551942 * states. If #discard() is not called or fails, the state modifications
     
    34363623            else
    34373624            {
    3438                 /* back to NotCreated on failiure */
     3625                /* back to NotCreated on failure */
    34393626                that->m.state = MediaState_NotCreated;
    34403627
     
    35863773            else
    35873774            {
    3588                 /* back to NotCreated on failiure */
     3775                /* back to NotCreated on failure */
    35893776                target->m.state = MediaState_NotCreated;
    35903777
     
    36443831                try
    36453832                {
    3646                     /* open all hard disks in the chain (they are in the
     3833                    /* Open all hard disks in the chain (they are in the
    36473834                     * {parent,child} order in there. Note that we don't lock
    36483835                     * objects in this chain since they must be in states
    3649                      * (Deleting and LockedWrite) that prevent from chaning
     3836                     * (Deleting and LockedWrite) that prevent from changing
    36503837                     * their format and location fields from outside. */
    36513838
     
    39264113            /* Lock both in {parent,child} order. The lock is also used as a
    39274114             * signal from the task initiator (which releases it only after
    3928              * RTThreadCreate()) that we can start the job*/
     4115             * RTThreadCreate()) that we can start the job. */
    39294116            AutoMultiWriteLock2 thatLock (that, target);
    39304117
     
    40624249            else
    40634250            {
    4064                 /* back to NotCreated on failiure */
     4251                /* back to NotCreated on failure */
    40654252                target->m.state = MediaState_NotCreated;
    40664253
     
    40834270            /* Note that in sync mode, it's the caller's responsibility to
    40844271             * unlock the hard disk */
     4272
     4273            break;
     4274        }
     4275
     4276        ////////////////////////////////////////////////////////////////////////
     4277
     4278        case Task::Flatten:
     4279        {
     4280            ComObjPtr<HardDisk> &target = task->d.target;
     4281
     4282            /* Lock both in {parent,child} order. The lock is also used as a
     4283             * signal from the task initiator (which releases it only after
     4284             * RTThreadCreate()) that we can start the job. */
     4285            AutoMultiWriteLock2 thatLock (that, target);
     4286
     4287            CloneChain *chain = task->d.source.get();
     4288
     4289            uint64_t size = 0, logicalSize = 0;
     4290
     4291            /* The object may request a specific UUID (through a special form of
     4292             * the setLocation() argument). Otherwise we have to generate it */
     4293            Guid targetId = target->m.id;
     4294            bool generateUuid = targetId.isEmpty();
     4295            if (generateUuid)
     4296            {
     4297                targetId.create();
     4298                /* VirtualBox::registerHardDisk() will need UUID */
     4299                unconst (target->m.id) = targetId;
     4300            }
     4301
     4302            try
     4303            {
     4304                PVBOXHDD hdd;
     4305                int vrc = VDCreate (that->mm.vdDiskIfaces, &hdd);
     4306                ComAssertRCThrow (vrc, E_FAIL);
     4307
     4308                try
     4309                {
     4310                    /* Open all hard disk images in the chain. */
     4311                    for (List::const_iterator it = chain->begin();
     4312                         it != chain->end(); ++ it)
     4313                    {
     4314                        /* sanity check */
     4315                        Assert ((*it)->m.state == MediaState_LockedRead);
     4316
     4317                        /** Open all diff images in read-only mode. */
     4318                        vrc = VDOpen (hdd, Utf8Str ((*it)->mm.format),
     4319                                      Utf8Str ((*it)->m.locationFull),
     4320                                      VD_OPEN_FLAGS_READONLY,
     4321                                      (*it)->mm.vdDiskIfaces);
     4322                        if (RT_FAILURE (vrc))
     4323                        {
     4324                            throw setError (E_FAIL,
     4325                                tr ("Could not open the hard disk storage "
     4326                                    "unit '%s'%s"),
     4327                                Utf8Str ((*it)->m.locationFull).raw(),
     4328                                that->vdError (vrc).raw());
     4329                        }
     4330                    }
     4331
     4332                    /* unlock before the potentially lengthy operation */
     4333                    thatLock.leave();
     4334
     4335                    Utf8Str targetFormat (target->mm.format);
     4336                    Utf8Str targetLocation (target->m.locationFull);
     4337
     4338                    Assert (target->m.state == MediaState_Creating);
     4339
     4340                    /* ensure the target directory exists */
     4341                    rc = VirtualBox::ensureFilePathExists (targetLocation);
     4342                    CheckComRCThrowRC (rc);
     4343
     4344                    /* needed for vdProgressCallback */
     4345                    that->mm.vdProgress = task->progress;
     4346
     4347                    PVBOXHDD targetHdd;
     4348                    int vrc = VDCreate (that->mm.vdDiskIfaces, &targetHdd);
     4349                    ComAssertRCThrow (vrc, E_FAIL);
     4350
     4351                    vrc = VDCopy (hdd, VD_LAST_IMAGE, targetHdd, targetFormat,
     4352                                  targetLocation, false, 0, task->d.variant,
     4353                                  targetId.raw(), NULL,
     4354                                  target->mm.vdDiskIfaces,
     4355                                  that->mm.vdDiskIfaces);
     4356
     4357                    that->mm.vdProgress = NULL;
     4358
     4359                    if (RT_FAILURE (vrc))
     4360                    {
     4361                        VDDestroy (targetHdd);
     4362
     4363                        throw setError (E_FAIL,
     4364                            tr ("Could not create the flattened hard disk "
     4365                                "'%s'%s"),
     4366                            targetLocation.raw(), that->vdError (vrc).raw());
     4367                    }
     4368
     4369                    size = VDGetFileSize (targetHdd, 0);
     4370                    logicalSize = VDGetSize (targetHdd, 0) / _1M;
     4371
     4372                    VDDestroy (targetHdd);
     4373                }
     4374                catch (HRESULT aRC) { rc = aRC; }
     4375
     4376                VDDestroy (hdd);
     4377            }
     4378            catch (HRESULT aRC) { rc = aRC; }
     4379
     4380            if (SUCCEEDED (rc))
     4381            {
     4382                Assert (target->mParent.isNull());
     4383
     4384                /* just register  */
     4385                rc = that->mVirtualBox->registerHardDisk(target);
     4386            }
     4387
     4388            thatLock.maybeEnter();
     4389
     4390            if (SUCCEEDED (rc))
     4391            {
     4392                target->m.state = MediaState_Created;
     4393
     4394                target->m.size = size;
     4395                target->mm.logicalSize = logicalSize;
     4396            }
     4397            else
     4398            {
     4399                /* back to NotCreated on failure */
     4400                target->m.state = MediaState_NotCreated;
     4401
     4402                /* reset UUID to prevent it from being reused next time */
     4403                if (generateUuid)
     4404                    unconst (target->m.id).clear();
     4405            }
     4406
     4407            /* Everything is explicitly unlocked when the task exits,
     4408             * as the task destruction also destroys the source chain. */
    40854409
    40864410            break;
  • trunk/src/VBox/Main/MachineImpl.cpp

    r17942 r18115  
    1092310923            bool first = true;
    1092410924
     10925            /** @todo split out the media locking, and put it into
     10926             * HardDiskImpl.cpp, as it needs this functionality too. */
    1092510927            while (!hd.isNull())
    1092610928            {
  • trunk/src/VBox/Main/include/HardDiskImpl.h

    r17970 r18115  
    5656
    5757    class MergeChain;
     58    class CloneChain;
    5859
    5960    VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE (HardDisk)
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