VirtualBox

Changeset 75373 in vbox


Ignore:
Timestamp:
Nov 9, 2018 6:12:30 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
126508
Message:

Main: bugref:6598: Added ability to merge mediums with different sizes in the offline mode

Location:
trunk/src/VBox
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/MediumImpl.h

    r74353 r75373  
    202202    void i_cancelMergeTo(MediumLockList *aChildrenToReparent,
    203203                       MediumLockList *aMediumLockList);
     204
     205    HRESULT i_resize(LONG64 aLogicalSize,
     206                     MediumLockList *aMediumLockList,
     207                     ComObjPtr<Progress> *aProgress,
     208                     bool aWait);
    204209
    205210    HRESULT i_fixParentUuidOfChildren(MediumLockList *pChildrenToReparent);
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r74822 r75373  
    33793379    HRESULT rc = S_OK;
    33803380    ComObjPtr<Progress> pProgress;
    3381     Medium::Task *pTask = NULL;
     3381
     3382    /* Build the medium lock list. */
     3383    MediumLockList *pMediumLockList(new MediumLockList());
    33823384
    33833385    try
    33843386    {
    3385         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3386 
    3387         /* Build the medium lock list. */
    3388         MediumLockList *pMediumLockList(new MediumLockList());
    3389         alock.release();
     3387        const char *pszError = NULL;
     3388
    33903389        rc = i_createMediumLockList(true /* fFailIfInaccessible */ ,
    33913390                                    this /* pToLockWrite */,
     
    33933392                                    NULL,
    33943393                                    *pMediumLockList);
    3395         alock.acquire();
    33963394        if (FAILED(rc))
    33973395        {
     3396            pszError = tr("Failed to create medium lock list when resize '%s'");
     3397        }
     3398        else
     3399        {
     3400            rc = pMediumLockList->Lock();
     3401            if (FAILED(rc))
     3402                pszError = tr("Failed to lock media when compacting '%s'");
     3403        }
     3404
     3405
     3406        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     3407
     3408        if (FAILED(rc))
     3409        {
    33983410            delete pMediumLockList;
    3399             throw rc;
    3400         }
    3401 
    3402         alock.release();
    3403         rc = pMediumLockList->Lock();
    3404         alock.acquire();
    3405         if (FAILED(rc))
    3406         {
    3407             delete pMediumLockList;
    3408             throw setError(rc,
    3409                            tr("Failed to lock media when compacting '%s'"),
    3410                            i_getLocationFull().c_str());
     3411            throw setError(rc, pszError, i_getLocationFull().c_str());
    34113412        }
    34123413
     
    34143415        rc = pProgress->init(m->pVirtualBox,
    34153416                             static_cast <IMedium *>(this),
    3416                              BstrFmt(tr("Compacting medium '%s'"), m->strLocationFull.c_str()).raw(),
     3417                             BstrFmt(tr("Resizing medium '%s'"), m->strLocationFull.c_str()).raw(),
    34173418                             TRUE /* aCancelable */);
    34183419        if (FAILED(rc))
     
    34213422            throw rc;
    34223423        }
    3423 
    3424         /* setup task object to carry out the operation asynchronously */
    3425         pTask = new Medium::ResizeTask(this, aLogicalSize, pProgress, pMediumLockList);
    3426         rc = pTask->rc();
    3427         AssertComRC(rc);
    3428         if (FAILED(rc))
    3429             throw rc;
    34303424    }
    34313425    catch (HRESULT aRC) { rc = aRC; }
    34323426
    34333427    if (SUCCEEDED(rc))
    3434     {
    3435         rc = pTask->createThread();
    3436 
    3437         if (SUCCEEDED(rc))
    3438             pProgress.queryInterfaceTo(aProgress.asOutParam());
    3439     }
    3440     else if (pTask != NULL)
    3441         delete pTask;
     3428        rc = i_resize(aLogicalSize, pMediumLockList, &pProgress, false /* aWait */);
     3429
     3430    if (SUCCEEDED(rc))
     3431        pProgress.queryInterfaceTo(aProgress.asOutParam());
     3432    else
     3433        delete pMediumLockList;
    34423434
    34433435    return rc;
     
    55305522                 * media are used by a running VM.
    55315523                 */
    5532                 bool fMergeIntoThis = cbMediumThis > cbMediumOther;
     5524
     5525                uint32_t mediumVariants =  MediumVariant_Fixed | MediumVariant_VmdkStreamOptimized;
     5526                uint32_t mediumCaps = MediumFormatCapabilities_CreateDynamic | MediumFormatCapabilities_File;
     5527
     5528                bool fDynamicOther =    pOther->i_getMediumFormat()->i_getCapabilities() & mediumCaps
     5529                                     && pOther->i_getVariant() & ~mediumVariants;
     5530                bool fDynamicThis =    i_getMediumFormat()->i_getCapabilities() & mediumCaps
     5531                                    && i_getVariant() & ~mediumVariants;
     5532                bool fMergeIntoThis =    (fDynamicThis && !fDynamicOther)
     5533                                      || (fDynamicThis == fDynamicOther && cbMediumThis > cbMediumOther);
    55335534                fMergeForward = fMergeIntoThis != fThisParent;
    55345535            }
     
    60046005                                             i_getName().c_str(),
    60056006                                             tgtName.c_str()).raw(),
    6006                                      TRUE /* aCancelable */);
     6007                                     TRUE, /* aCancelable */
     6008                                     2, /* Number of opearations */
     6009                                     BstrFmt(tr("Resizing medium '%s' before merge"),
     6010                                             tgtName.c_str()).raw()
     6011                                     );
    60076012                if (FAILED(rc))
    60086013                    throw rc;
     
    60516056 * @param aMediumLockList Medium locking information.
    60526057 *
    6053  * @note Locks the media from the chain for writing.
     6058 * @note Locks the tree lock for writing. Locks the media from the chain
     6059 *       for writing.
    60546060 */
    60556061void Medium::i_cancelMergeTo(MediumLockList *aChildrenToReparent,
     
    60966102    if (aChildrenToReparent)
    60976103        delete aChildrenToReparent;
     6104}
     6105
     6106/**
     6107 * Resizes the media.
     6108 *
     6109 * If @a aWait is @c true then this method will perform the operation on the
     6110 * calling thread and will not return to the caller until the operation is
     6111 * completed. When this method succeeds, the state of the target medium (and all
     6112 * involved extra media) will be restored. @a aMediumLockList will not be
     6113 * deleted, whether the operation is successful or not. The caller has to do
     6114 * this if appropriate.
     6115 *
     6116 * If @a aWait is @c false then this method will create a thread to perform the
     6117 * operation asynchronously and will return immediately. The thread will reset
     6118 * the state of the target medium (and all involved extra media) and delete
     6119 * @a aMediumLockList.
     6120 *
     6121 * When this method fails (regardless of the @a aWait mode), it is a caller's
     6122 * responsibility to undo state changes and delete @a aMediumLockList.
     6123 *
     6124 * If @a aProgress is not NULL but the object it points to is @c null then a new
     6125 * progress object will be created and assigned to @a *aProgress on success,
     6126 * otherwise the existing progress object is used. If Progress is NULL, then no
     6127 * progress object is created/used at all. Note that @a aProgress cannot be
     6128 * NULL when @a aWait is @c false (this method will assert in this case).
     6129 *
     6130 * @param aLogicalSize  New nominal capacity of the medium in bytes.
     6131 * @param aMediumLockList Medium locking information.
     6132 * @param aProgress     Where to find/store a Progress object to track operation
     6133 *                      completion.
     6134 * @param aWait         @c true if this method should block instead of creating
     6135 *                      an asynchronous thread.
     6136 *
     6137 * @note Locks the media from the chain for writing.
     6138 */
     6139
     6140HRESULT Medium::i_resize(LONG64 aLogicalSize,
     6141                         MediumLockList *aMediumLockList,
     6142                         ComObjPtr<Progress> *aProgress,
     6143                         bool aWait)
     6144{
     6145    AssertReturn(aMediumLockList != NULL, E_FAIL);
     6146    AssertReturn(aProgress != NULL || aWait == true, E_FAIL);
     6147
     6148    AutoCaller autoCaller(this);
     6149    AssertComRCReturnRC(autoCaller.rc());
     6150
     6151    HRESULT rc = S_OK;
     6152    ComObjPtr<Progress> pProgress;
     6153    Medium::Task *pTask = NULL;
     6154
     6155    try
     6156    {
     6157        if (aProgress != NULL)
     6158        {
     6159            /* use the existing progress object... */
     6160            pProgress = *aProgress;
     6161
     6162            /* ...but create a new one if it is null */
     6163            if (pProgress.isNull())
     6164            {
     6165                AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     6166
     6167                pProgress.createObject();
     6168                rc = pProgress->init(m->pVirtualBox,
     6169                                     static_cast <IMedium *>(this),
     6170                                     BstrFmt(tr("Resizing medium '%s'"), m->strLocationFull.c_str()).raw(),
     6171                                     TRUE /* aCancelable */);
     6172                if (FAILED(rc))
     6173                    throw rc;
     6174            }
     6175        }
     6176
     6177        /* setup task object to carry out the operation asynchronously */
     6178        pTask = new Medium::ResizeTask(this,
     6179                                       aLogicalSize,
     6180                                       pProgress,
     6181                                       aMediumLockList,
     6182                                       aWait /* fKeepMediumLockList */);
     6183        rc = pTask->rc();
     6184        AssertComRC(rc);
     6185        if (FAILED(rc))
     6186            throw rc;
     6187    }
     6188    catch (HRESULT aRC) { rc = aRC; }
     6189
     6190    if (SUCCEEDED(rc))
     6191    {
     6192        if (aWait)
     6193        {
     6194            rc = pTask->runNow();
     6195            delete pTask;
     6196        }
     6197        else
     6198            rc = pTask->createThread();
     6199
     6200        if (SUCCEEDED(rc) && aProgress != NULL)
     6201            *aProgress = pProgress;
     6202    }
     6203    else if (pTask != NULL)
     6204        delete pTask;
     6205
     6206    return rc;
    60986207}
    60996208
     
    86538762                               task.mParentForTarget->m->strLocationFull.c_str());
    86548763            }
     8764
     8765        // Resize target to source size, if possible. Otherwise throw an error.
     8766        // It's offline resizing. Online resizing will be called in the
     8767        // SessionMachine::onlineMergeMedium.
     8768
     8769        uint64_t sourceSize = 0;
     8770        Utf8Str sourceName;
     8771        {
     8772            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     8773            sourceSize = i_getLogicalSize();
     8774            sourceName = i_getName();
     8775        }
     8776        uint64_t targetSize = 0;
     8777        Utf8Str targetName;
     8778        {
     8779            AutoReadLock alock(pTarget COMMA_LOCKVAL_SRC_POS);
     8780            targetSize = pTarget->i_getLogicalSize();
     8781            targetName = pTarget->i_getName();
     8782        }
     8783
     8784        //reducing vm disks are not implemented yet
     8785        if (sourceSize > targetSize)
     8786        {
     8787            if (i_isMediumFormatFile())
     8788            {
     8789                // Have to make own lock list, because "resize" method resizes only last image
     8790                // in the lock chain. The lock chain already in the task.mpMediumLockList, so
     8791                // just make new lock list based on it. In fact the own lock list neither makes
     8792                // double locking of mediums nor unlocks them during delete, because medium
     8793                // already locked by task.mpMediumLockList and own list is used just to specify
     8794                // what "resize" method should resize.
     8795
     8796                MediumLockList* pMediumLockListForResize = new MediumLockList();
     8797
     8798                for (MediumLockList::Base::iterator it = task.mpMediumLockList->GetBegin();
     8799                     it != task.mpMediumLockList->GetEnd();
     8800                     ++it)
     8801                {
     8802                    ComObjPtr<Medium> pMedium = it->GetMedium();
     8803                    pMediumLockListForResize->Append(pMedium, pMedium->m->state == MediumState_LockedWrite);
     8804                    if (pMedium == pTarget)
     8805                        break;
     8806                }
     8807
     8808                // just to switch internal state of the lock list to avoid errors during list deletion,
     8809                // because all meduims in the list already locked by task.mpMediumLockList
     8810                HRESULT rc = pMediumLockListForResize->Lock(true /* fSkipOverLockedMedia */);
     8811                if (FAILED(rc))
     8812                {
     8813                    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     8814                    rc = setError(rc,
     8815                                  tr("Failed to lock the medium '%s' to resize before merge"),
     8816                                  targetName.c_str());
     8817                    delete pMediumLockListForResize;
     8818                    throw rc;
     8819                }
     8820
     8821                ComObjPtr<Progress> pProgress(task.GetProgressObject());
     8822                rc = pTarget->i_resize(sourceSize, pMediumLockListForResize, &pProgress, true);
     8823                if (FAILED(rc))
     8824                {
     8825                    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     8826                    rc = setError(rc,
     8827                                  tr("Failed to set size of '%s' to size of '%s'"),
     8828                                  targetName.c_str(), sourceName.c_str());
     8829                    delete pMediumLockListForResize;
     8830                    throw rc;
     8831                }
     8832                delete pMediumLockListForResize;
     8833            }
     8834            else
     8835            {
     8836                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     8837                HRESULT rc = setError(VBOX_E_NOT_SUPPORTED,
     8838                                      tr("Sizes of '%s' and '%s' are different and medium format does not support resing"),
     8839                                      sourceName.c_str(), targetName.c_str());
     8840                throw rc;
     8841            }
     8842        }
     8843
     8844        task.GetProgressObject()->SetNextOperation(BstrFmt(tr("Merging medium '%s' to '%s'"),
     8845                                                           i_getName().c_str(),
     8846                                                           targetName.c_str()).raw(),
     8847                                                   1);
    86558848
    86568849        PVDISK hdd;
     
    97869979                    Assert(pMedium->m->state == MediumState_LockedWrite);
    97879980                else
    9788                     Assert(pMedium->m->state == MediumState_LockedRead);
     9981                    Assert(pMedium->m->state == MediumState_LockedRead ||
     9982                           // Allow resize the target image during mergeTo in case
     9983                           // of direction from parent to child because all intermediate
     9984                           // images are marked to MediumState_Deleting and will be
     9985                           // destroyed after successful merge
     9986                           pMedium->m->state == MediumState_Deleting);
    97899987
    97909988                /* Open all media but last in read-only mode. Do not handle
  • trunk/src/VBox/Main/src-server/SnapshotImpl.cpp

    r75361 r75373  
    25042504    }
    25052505
     2506    bool fDeleteOnline = mData->mMachineState == MachineState_Running || mData->mMachineState == MachineState_Paused;
     2507
    25062508    // count normal hard disks and add their sizes to the weight
    25072509    for (MediumAttachmentList::iterator
     
    25272529                // normal or immutable media need attention
    25282530                ++ulOpCount;
     2531                // offline merge includes medium resizing
     2532                if (!fDeleteOnline)
     2533                    ++ulOpCount;
    25292534                ulTotalWeight += (ULONG)(pHD->i_getSize() / _1M);
    25302535            }
     
    25422547                    Bstr(tr("Setting up")).raw(),
    25432548                    1);
    2544 
    2545     bool fDeleteOnline = (   (mData->mMachineState == MachineState_Running)
    2546                           || (mData->mMachineState == MachineState_Paused));
    25472549
    25482550    /* create and start the task on a separate thread */
     
    28142816            // a file representation such as iSCSI.
    28152817
    2816             // not going to merge a big source into a small target
    2817             if (pSource->i_getLogicalSize() > pTarget->i_getLogicalSize())
     2818            // not going to merge a big source into a small target on online merge. Otherwise it will be resized
     2819            if (fNeedsOnlineMerge && pSource->i_getLogicalSize() > pTarget->i_getLogicalSize())
    28182820            {
    28192821                rc = setError(E_FAIL,
     
    30393041            }
    30403042
    3041             task.m_pProgress->SetNextOperation(BstrFmt(tr("Merging differencing image '%s'"),
     3043            const char *pszOperationText = it->mfNeedsOnlineMerge ?
     3044                                             tr("Merging differencing image '%s'")
     3045                                           : tr("Resizing before merge differencing image '%s'");
     3046
     3047            task.m_pProgress->SetNextOperation(BstrFmt(pszOperationText,
    30423048                                               pMedium->i_getName().c_str()).raw(),
    30433049                                               ulWeight);
  • trunk/src/VBox/Storage/VD.cpp

    r75351 r75373  
    3636#include <iprt/sg.h>
    3737#include <iprt/semaphore.h>
     38#include <iprt/vector.h>
    3839
    3940#include "VDInternal.h"
     
    362363    uint8_t          abData[1];
    363364} VDMETAXFER;
     365
     366/* vector for temporary storing image sizes */
     367RTVEC_DECL(VDImgSzVec, uint64_t)
    364368
    365369/**
     
    70467050            uint64_t uOffset = 0;
    70477051            uint64_t cbRemaining = cbSize;
     7052
    70487053            do
    70497054            {
  • trunk/src/VBox/ValidationKit/tests/storage/tdStorageSnapshotMerging1.py

    r69111 r75373  
    2828terms and conditions of either the GPL or the CDDL or both.
    2929"""
    30 __version__ = "$Id$"
    31 
     30__version__ = "$Revision$"
    3231
    3332# Standard Python imports.
     
    3534import sys;
    3635import uuid;
     36import zlib;
    3737
    3838# Only the main script needs to modify the path.
     
    4747from testdriver import vbox;
    4848from testdriver import vboxcon;
     49from testdriver import vboxwrappers;
    4950
    5051def _ControllerTypeToName(eControllerType):
     
    6263    return sType;
    6364
     65def crc32_of_file(filepath):
     66    fileobj = open(filepath,'rb');
     67    current = 0;
     68   
     69    while True:
     70        buf = fileobj.read(1024 * 1024);
     71        if not buf:
     72            break
     73        current = zlib.crc32(buf, current);
     74       
     75    fileobj.close();
     76    return current % 2**32;
     77
    6478class tdStorageSnapshot(vbox.TestDriver):                                      # pylint: disable=R0902
    6579    """
    6680    Storage benchmark.
    6781    """
    68 
    6982    def __init__(self):
    7083        vbox.TestDriver.__init__(self);
     
    7386        self.oGuestToGuestSess = None;
    7487        self.oGuestToGuestTxs  = None;
    75         self.asTestVMsDef      = ['tst-win7-vhd', 'tst-debian-vhd', 'tst-debian-vdi'];
    76         self.asTestVMs         = self.asTestVMsDef;
    77         self.asSkipVMs         = [];
    7888        self.asStorageCtrlsDef = ['AHCI', 'IDE', 'LsiLogicSAS', 'LsiLogic', 'BusLogic'];
    7989        self.asStorageCtrls    = self.asStorageCtrlsDef;
    80         self.asDiskFormatsDef  = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
     90        #self.asDiskFormatsDef  = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
     91        self.asDiskFormatsDef  = ['VDI', 'VMDK', 'VHD'];
    8192        self.asDiskFormats     = self.asDiskFormatsDef;
    8293        self.sRndData          = os.urandom(100*1024*1024);
     
    93104        reporter.log('  --disk-formats  <type1[:type2[:...]]>');
    94105        reporter.log('      Default: %s' % (':'.join(self.asDiskFormats)));
    95         reporter.log('  --test-vms      <vm1[:vm2[:...]]>');
    96         reporter.log('      Test the specified VMs in the given order. Use this to change');
    97         reporter.log('      the execution order or limit the choice of VMs');
    98         reporter.log('      Default: %s  (all)' % (':'.join(self.asTestVMsDef)));
    99         reporter.log('  --skip-vms      <vm1[:vm2[:...]]>');
    100         reporter.log('      Skip the specified VMs when testing.');
    101106        return rc;
    102107
     
    111116            if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-formats" takes a colon separated list of disk formats');
    112117            self.asDiskFormats = asArgs[iArg].split(':');
    113         elif asArgs[iArg] == '--test-vms':
    114             iArg += 1;
    115             if iArg >= len(asArgs): raise base.InvalidOption('The "--test-vms" takes colon separated list');
    116             self.asTestVMs = asArgs[iArg].split(':');
    117             for s in self.asTestVMs:
    118                 if s not in self.asTestVMsDef:
    119                     raise base.InvalidOption('The "--test-vms" value "%s" is not valid; valid values are: %s' \
    120                         % (s, ' '.join(self.asTestVMsDef)));
    121         elif asArgs[iArg] == '--skip-vms':
    122             iArg += 1;
    123             if iArg >= len(asArgs): raise base.InvalidOption('The "--skip-vms" takes colon separated list');
    124             self.asSkipVMs = asArgs[iArg].split(':');
    125             for s in self.asSkipVMs:
    126                 if s not in self.asTestVMsDef:
    127                     reporter.log('warning: The "--test-vms" value "%s" does not specify any of our test VMs.' % (s));
    128118        else:
    129119            return vbox.TestDriver.parseOption(self, asArgs, iArg);
    130120        return iArg + 1;
    131121
    132     def completeOptions(self):
    133         # Remove skipped VMs from the test list.
    134         for sVM in self.asSkipVMs:
    135             try:    self.asTestVMs.remove(sVM);
    136             except: pass;
    137 
    138         return vbox.TestDriver.completeOptions(self);
    139 
    140122    def getResourceSet(self):
    141123        # Construct the resource list the first time it's queried.
    142124        if self.asRsrcs is None:
    143             self.asRsrcs = [];
    144             if 'tst-win7-vhd' in self.asTestVMs:
    145                 self.asRsrcs.append('4.2/storage/win7.vhd');
    146 
    147             if 'tst-debian-vhd' in self.asTestVMs:
    148                 self.asRsrcs.append('4.2/storage/debian.vhd');
    149 
    150             if 'tst-debian-vdi' in self.asTestVMs:
    151                 self.asRsrcs.append('4.2/storage/debian.vdi');
    152 
     125            self.asRsrcs = ['5.3/storage/mergeMedium/t-orig.vdi', '5.3/storage/mergeMedium/t-fixed.vdi', '5.3/storage/mergeMedium/t-resized.vdi'];
    153126        return self.asRsrcs;
    154 
    155     def actionConfig(self):
    156 
    157         # Make sure vboxapi has been imported so we can use the constants.
    158         if not self.importVBoxApi():
    159             return False;
    160 
    161         #
    162         # Configure the VMs we're going to use.
    163         #
    164 
    165         # Windows VMs
    166         if 'tst-win7-vhd' in self.asTestVMs:
    167             oVM = self.createTestVM('tst-win7-vhd', 1, '4.2/storage/win7.vhd', sKind = 'Windows7', fIoApic = True, \
    168                                     eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
    169                                     eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
    170             if oVM is None:
    171                 return False;
    172 
    173         # Linux VMs
    174         if 'tst-debian-vhd' in self.asTestVMs:
    175             oVM = self.createTestVM('tst-debian-vhd', 1, '4.2/storage/debian.vhd', sKind = 'Debian_64', fIoApic = True, \
    176                                     eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
    177                                     eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
    178             if oVM is None:
    179                 return False;
    180 
    181         if 'tst-debian-vdi' in self.asTestVMs:
    182             oVM = self.createTestVM('tst-debian-vdi', 1, '4.2/storage/debian.vdi', sKind = 'Debian_64', fIoApic = True, \
    183                                     eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
    184                                     eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
    185             if oVM is None:
    186                 return False;
    187 
    188         return True;
    189127
    190128    def actionExecute(self):
     
    194132        fRc = self.test1();
    195133        return fRc;
    196 
    197 
     134   
     135    def resizeMedium(self, oMedium, cbNewSize):
     136        if oMedium.deviceType is not vboxcon.DeviceType_HardDisk:
     137            return False;
     138       
     139        if oMedium.type is not vboxcon.MediumType_Normal:
     140            return False;
     141       
     142        #currently only VDI can be resizable. Medium variant is not checked, because testcase creates disks itself
     143        oMediumFormat = oMedium.mediumFormat;
     144        if oMediumFormat.id != 'VDI':
     145            return False;
     146       
     147        cbCurrSize = oMedium.logicalSize;
     148        # currently reduce is not supported
     149        if cbNewSize < cbCurrSize:
     150            return False;
     151       
     152        try:
     153            oProgressCom = oMedium.resize(cbNewSize);
     154            oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oVBox.oTstDrv, 'Resize medium %s' % (oMedium.name));
     155            oProgress.wait(cMsTimeout = 60 * 1000);
     156            oProgress.logResult();
     157        except:
     158            reporter.logXcpt('IMedium::resize failed on %s' % (oMedium.name));
     159            return False;
     160       
     161        return True;
     162   
     163    def getMedium(self, oVM, sController):
     164        oMediumAttachments = oVM.getMediumAttachmentsOfController(sController);
     165       
     166        for oAttachment in oMediumAttachments:
     167            oMedium = oAttachment.medium;
     168            if oMedium.deviceType is not vboxcon.DeviceType_HardDisk:
     169                continue;
     170            if oMedium.type is not vboxcon.MediumType_Normal:
     171                continue;
     172            return oMedium;
     173       
     174        return None;
     175   
     176    def getSnapshotMedium(self, oSnapshot, sController):
     177        oVM = oSnapshot.machine;
     178        oMedium = self.getMedium(oVM, sController);
     179       
     180        for oChildMedium in oMedium.children:
     181            for uSnapshotId in oChildMedium.getSnapshotIds(oVM.id):
     182                if uSnapshotId == oVM.id:
     183                    return oChildMedium;
     184               
     185        return None;
     186   
     187    def openMedium(self, sHd, fImmutable = False):
     188        """
     189        Opens medium in readonly mode.
     190        Returns Medium object on success and None on failure.  Error information is logged.
     191        """
     192        sFullName = self.oVBox.oTstDrv.getFullResourceName(sHd);
     193        try:
     194            oHd = self.oVBox.findHardDisk(sFullName);
     195        except:
     196            try:
     197                if self.fpApiVer >= 4.1:
     198                    oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly, False);
     199                elif self.fpApiVer >= 4.0:
     200                    oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly);
     201                else:
     202                    oHd = self.oVBox.openHardDisk(sFullName, vboxcon.AccessMode_ReadOnly, False, "", False, "");
     203                   
     204            except:
     205                reporter.errorXcpt('failed to open hd "%s"' % (sFullName));
     206                return False;
     207           
     208        try:
     209            if fImmutable:
     210                oHd.type = vboxcon.MediumType_Immutable;
     211            else:
     212                oHd.type = vboxcon.MediumType_Normal;
     213               
     214        except:
     215            if fImmutable:
     216                reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
     217            else:
     218                reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
     219           
     220            return None;
     221       
     222        return oHd;
     223   
     224    def cloneMedium(self, oSrcHd, oTgtHd):
     225        """
     226        Clones medium into target medium.
     227        """
     228        try:
     229            oProgressCom = oSrcHd.cloneTo(oTgtHd, (vboxcon.MediumVariant_Standard, ), None);
     230            oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oVBox.oTstDrv, 'clone base disk %s to %s' % (oSrcHd.name, oTgtHd.name));
     231            oProgress.wait(cMsTimeout = 60 * 1000);
     232            oProgress.logResult();
     233        except:
     234            reporter.errorXcpt('failed to clone medium %s to %s' % (oSrcHd.name, oTgtHd.name));
     235            return False;
     236       
     237        return True;
     238   
     239    def deleteVM(self, oVM):
     240        try:
     241            oVM.unregister(vboxcon.CleanupMode_DetachAllReturnNone);
     242        except:
     243            reporter.logXcpt();
     244            pass;
     245       
     246        if self.fpApiVer >= 4.0:
     247            try:
     248                if self.fpApiVer >= 4.3:
     249                    oProgress = oVM.deleteConfig([]);
     250                else:
     251                    oProgress = oVM.delete(None);
     252                self.waitOnProgress(oProgress);
     253               
     254            except:
     255                reporter.logXcpt();
     256               
     257        else:
     258            try:    oVM.deleteSettings();
     259            except: reporter.logXcpt();
     260           
     261        return None;
     262   
    198263    #
    199264    # Test execution helpers.
    200265    #
    201266
    202     def test1UploadFile(self, oSession, oTxsSession):
    203         """
    204         Uploads a test file to the test machine.
    205         """
    206         reporter.testStart('Upload file');
    207 
    208         fRc = self.txsUploadString(oSession, oTxsSession, self.sRndData, '${SCRATCH}/' + str(uuid.uuid4()), \
    209                                    cMsTimeout = 3600 * 1000);
    210 
    211         reporter.testDone(not fRc);
    212         return fRc;
    213 
    214     def test1OneCfg(self, sVmName, eStorageController, sDiskFormat):
     267    def test1OneCfg(self, eStorageController, oDskFmt):
    215268        """
    216269        Runs the specified VM thru test #1.
     
    219272        the actual test result.
    220273        """
    221         oVM = self.getVmByName(sVmName);
    222 
    223         # @ŧodo: Implement support for different formats.
    224         _ = sDiskFormat;
    225 
     274       
     275        (asExts, aTypes) = oDskFmt.describeFileExtensions()
     276        for i in range(0, len(asExts)): #pylint: disable=consider-using-enumerate
     277            if aTypes[i] is vboxcon.DeviceType_HardDisk:
     278                sExt = '.' + asExts[i]
     279                break
     280           
     281        if sExt is None:
     282            return False;
     283       
     284        oOrigBaseHd = self.openMedium('5.3/storage/mergeMedium/t-orig.vdi');
     285        if oOrigBaseHd is None:
     286            return False;
     287       
     288        #currently only VDI can be resizable. Medium variant is not checked, because testcase creates disks itself
     289        fFmtDynamic = oDskFmt.id == 'VDI';
     290        sOrigWithDiffHd = '5.3/storage/mergeMedium/t-fixed.vdi'
     291        uOrigCrc = 0x7a417cbb;
     292       
     293        if fFmtDynamic:
     294            sOrigWithDiffHd = '5.3/storage/mergeMedium/t-resized.vdi';
     295            uOrigCrc = 0xa8f5daa3;
     296           
     297        oOrigWithDiffHd = self.openMedium(sOrigWithDiffHd);
     298        if oOrigWithDiffHd is None:
     299            return False;
     300       
     301        oVM = self.createTestVM('testvm', 1, None);
     302        if oVM is None:
     303            return False;
     304       
     305        sController = _ControllerTypeToName(eStorageController);
     306       
    226307        # Reconfigure the VM
     308        oSession = self.openSession(oVM);
     309        if oSession is None:
     310            return False;
     311        # Attach HD
     312
    227313        fRc = True;
    228         oSession = self.openSession(oVM);
     314        sFile = 't-base' + sExt;
     315        sHddPath = os.path.join(self.oVBox.oTstDrv.sScratchPath, sFile);
     316        oHd = oSession.createBaseHd(sHddPath, sFmt=oDskFmt.id, cb=oOrigBaseHd.logicalSize);
     317        #if oSession.createBaseHd can't create disk because it exists, oHd will point to some stub object anyway
     318        fRc = fRc and oHd is not None and oHd.logicalSize == oOrigBaseHd.logicalSize;
     319        fRc = fRc and self.cloneMedium(oOrigBaseHd, oHd);
     320           
     321        fRc = fRc and oSession.ensureControllerAttached(sController);
     322        fRc = fRc and oSession.setStorageControllerType(eStorageController, sController);
     323        fRc = fRc and oSession.saveSettings();
     324        fRc = fRc and oSession.attachHd(sHddPath, sController, iPort = 0, fImmutable=False, fForceResource=False)
     325       
     326        if fRc:
     327            oSession.takeSnapshot('Base snapshot');
     328            oSnapshot = oSession.findSnapshot('Base snapshot');
     329           
     330            if oSnapshot is not None:
     331                oSnapshotMedium = self.getSnapshotMedium(oSnapshot, sController);
     332                fRc = oSnapshotMedium is not None;
     333               
     334                if fFmtDynamic:
     335                    fRc = fRc and self.resizeMedium(oSnapshotMedium, oOrigWithDiffHd.logicalSize);
     336                fRc = fRc and self.cloneMedium(oOrigWithDiffHd, oSnapshotMedium);
     337                fRc = fRc and oSession.deleteSnapshot(oSnapshot.id, cMsTimeout = 120 * 1000);
     338               
     339                if fRc:
     340                    # disk for result test by checksum
     341                    sResFilePath = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res.vmdk');
     342                    sResFilePathRaw = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res-flat.vmdk');
     343                    oResHd = oSession.createBaseHd(sResFilePath, sFmt='VMDK', cb=oOrigWithDiffHd.logicalSize, tMediumVariant = (vboxcon.MediumVariant_Fixed, ));
     344                    fRc = oResHd is not None;
     345                    fRc = fRc and self.cloneMedium(oHd, oResHd);
     346                   
     347                    uResCrc32 = 0;
     348                    if fRc:
     349                        uResCrc32 = crc32_of_file(sResFilePathRaw);
     350                        if uResCrc32 == uOrigCrc:
     351                            reporter.log('Snapshot merged successfully. Data of the result medium are correspond to data of the original medium');
     352                            fRc = True;
     353                        else:
     354                            reporter.error('Snapshot merging failed. Data of the result medium not correspond to data of the original medium');
     355                            fRc = False;
     356                   
     357                    self.oVBox.deleteHdByMedium(oResHd);
     358
    229359        if oSession is not None:
    230             # Attach HD
    231             fRc = oSession.ensureControllerAttached(_ControllerTypeToName(eStorageController));
    232             fRc = fRc and oSession.setStorageControllerType(eStorageController, _ControllerTypeToName(eStorageController));
    233             fRc = fRc and oSession.saveSettings();
    234             fRc = oSession.close() and fRc and True; # pychecker hack.
    235             oSession = None;
    236         else:
    237             fRc = False;
    238 
    239         # Start up.
    240         if fRc is True:
    241             self.logVmInfo(oVM);
    242             oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(sVmName, fCdWait = False, fNatForwardingForTxs = True);
    243             if oSession is not None:
    244                 self.addTask(oTxsSession);
    245 
    246                 # Fudge factor - Allow the guest to finish starting up.
    247                 self.sleep(5);
    248 
    249                 # Do a snapshot first.
    250                 oSession.takeSnapshot('Base snapshot');
    251 
    252                 for i in range(0, 10):
    253                     oSession.takeSnapshot('Snapshot ' + str(i));
    254                     self.test1UploadFile(oSession, oTxsSession);
    255                     msNow = base.timestampMilli();
    256                     oSnapshot = oSession.findSnapshot('Snapshot ' + str(i));
    257                     oSession.deleteSnapshot(oSnapshot.id, cMsTimeout = 60 * 1000);
    258                     msElapsed = base.timestampMilli() - msNow;
    259                     reporter.log('Deleting snapshot %d took %d ms' % (i, msElapsed));
    260 
    261                 # cleanup.
    262                 self.removeTask(oTxsSession);
    263                 self.terminateVmBySession(oSession)
    264             else:
    265                 fRc = False;
     360            if oHd is not None:
     361                oSession.detachHd(sController, iPort = 0, iDevice = 0);
     362               
     363            oSession.saveSettings(fClose = True);
     364            if oHd is not None:
     365                self.oVBox.deleteHdByMedium(oHd);
     366       
     367        self.deleteVM(oVM);
    266368        return fRc;
    267369
    268     def test1OneVM(self, sVmName):
    269         """
    270         Runs one VM thru the various configurations.
    271         """
     370    def test1(self):
     371        """
     372        Executes test #1 thru the various configurations.
     373        """
     374        if not self.importVBoxApi():
     375            return False;
     376       
     377        sVmName = 'testvm';
    272378        reporter.testStart(sVmName);
     379
     380        aoDskFmts = self.oVBoxMgr.getArray(self.oVBox.systemProperties, 'mediumFormats')
     381        if aoDskFmts is None or len(aoDskFmts) < 1:
     382            return False;
     383       
    273384        fRc = True;
    274385        for sStorageCtrl in self.asStorageCtrls:
    275386            reporter.testStart(sStorageCtrl);
    276 
    277387            if sStorageCtrl == 'AHCI':
    278388                eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
     
    287397            else:
    288398                eStorageCtrl = None;
    289 
    290             for sDiskFormat in self.asDiskFormats:
    291                 reporter.testStart('%s' % (sDiskFormat));
    292                 self.test1OneCfg(sVmName, eStorageCtrl, sDiskFormat);
    293                 reporter.testDone();
     399           
     400            for oDskFmt in aoDskFmts:
     401                if (oDskFmt.id in self.asDiskFormats):
     402                    reporter.testStart('%s' % (oDskFmt.id));
     403                    fRc = self.test1OneCfg(eStorageCtrl, oDskFmt);
     404                    reporter.testDone();
     405                    if not fRc:
     406                        break;
     407       
    294408            reporter.testDone();
     409            if not fRc:
     410                break;
     411       
    295412        reporter.testDone();
    296413        return fRc;
    297414
    298     def test1(self):
    299         """
    300         Executes test #1.
    301         """
    302 
    303         # Loop thru the test VMs.
    304         for sVM in self.asTestVMs:
    305             # run test on the VM.
    306             if not self.test1OneVM(sVM):
    307                 fRc = False;
    308             else:
    309                 fRc = True;
    310 
    311         return fRc;
    312 
    313 
    314 
    315415if __name__ == '__main__':
    316416    sys.exit(tdStorageSnapshot().main(sys.argv));
Note: See TracChangeset for help on using the changeset viewer.

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