VirtualBox

Changeset 32642 in vbox


Ignore:
Timestamp:
Sep 20, 2010 2:30:08 PM (14 years ago)
Author:
vboxsync
Message:

Storage/VMDK: Make sure that streamOptimized VMDK files we create contain only one grain directory (was a long-standing bug in our code before which wasted a few KB without being noticed by anyone including VMware), optimize out any zero block writes and remove some @todos and other comments which are obsolete. VMDKstr
eam is working as intended now.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r32625 r32642  
    3131#include <iprt/rand.h>
    3232#include <iprt/zip.h>
     33#include <iprt/asm.h>
    3334
    3435
     
    921922        {
    922923            Marker.uType = RT_LE2H_U32(Marker.uType);
    923             if (Marker.uType == VMDK_MARKER_EOS)
    924             {
    925                 Assert(uMarker != VMDK_MARKER_EOS);
    926                 return VERR_VD_VMDK_INVALID_FORMAT;
    927             }
    928             else if (   Marker.uType == VMDK_MARKER_GT
    929                      || Marker.uType == VMDK_MARKER_GD
    930                      || Marker.uType == VMDK_MARKER_FOOTER)
    931             {
    932                 uCompOffset = uOffset + 512;
    933                 cbComp = VMDK_SECTOR2BYTE(Marker.uSector);
    934                 if (pcbMarkerData)
    935                     *pcbMarkerData = cbComp + 512;
    936             }
    937             else
    938             {
    939                 AssertMsgFailed(("VMDK: unknown marker type %u\n", Marker.uType));
    940                 return VERR_VD_VMDK_INVALID_FORMAT;
    941             }
     924            AssertMsgFailed(("VMDK: unexpected marker type %u\n", Marker.uType));
     925            return VERR_VD_VMDK_INVALID_FORMAT;
    942926        }
    943927        InflateState.pImage = pImage;
     
    10181002        else
    10191003        {
    1020             /** @todo implement creating the other marker types */
     1004            /* The other markers don't contain compressed data. */
    10211005            return VERR_NOT_IMPLEMENTED;
    10221006        }
     
    10651049            else
    10661050            {
    1067                 /** @todo implement creating the other marker types */
     1051                /* The other markers don't contain compressed data. */
    10681052                return VERR_NOT_IMPLEMENTED;
    10691053            }
     
    14551439        if (RT_FAILURE(rc))
    14561440            goto out;
    1457         pExtent->uSectorRGD = uStartSector;
    1458         pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
     1441        if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     1442        {
     1443            pExtent->uSectorRGD = 0;
     1444            pExtent->uSectorGD = uStartSector;
     1445        }
     1446        else
     1447        {
     1448            pExtent->uSectorRGD = uStartSector;
     1449            pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
     1450        }
    14591451    }
    14601452    else
     
    14691461        uint64_t uOffsetSectors;
    14701462
    1471         uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded);
    1472         for (i = 0; i < pExtent->cGDEntries; i++)
    1473         {
    1474             pRGD[i] = uOffsetSectors;
    1475             uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    1476             /* Write the redundant grain directory entry to disk. */
    1477             rc = vmdkFileWriteSync(pImage, pExtent->pFile,
    1478                                    VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
    1479                                    &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    1480             if (RT_FAILURE(rc))
     1463        if (pRGD)
     1464        {
     1465            uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded);
     1466            for (i = 0; i < pExtent->cGDEntries; i++)
    14811467            {
    1482                 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
    1483                 goto out;
     1468                pRGD[i] = uOffsetSectors;
     1469                uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
     1470                /* Write the redundant grain directory entry to disk. */
     1471                rc = vmdkFileWriteSync(pImage, pExtent->pFile,
     1472                                       VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
     1473                                       &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     1474                if (RT_FAILURE(rc))
     1475                {
     1476                    rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
     1477                    goto out;
     1478                }
     1479                uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
    14841480            }
    1485             uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
    14861481        }
    14871482
     
    27852780        &&  RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
    27862781    {
    2787         /* Read the footer, which isn't compressed and comes before the
    2788          * end-of-stream marker. This is bending the VMDK 1.1 spec, but that's
    2789          * VMware reality. Theory and practice have very little in common. */
     2782        /* Read the footer, which comes before the end-of-stream marker. */
    27902783        uint64_t cbSize;
    27912784        rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbSize);
     
    40864079    uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
    40874080
     4081    /* VMware does not write out completely empty grain tables in the case
     4082     * of streamOptimized images, which according to my interpretation of
     4083     * the VMDK 1.1 spec is bending the rules. Since they do it and we can
     4084     * handle it without problems do it the same way and save some bytes. */
     4085    bool fAllZero = true;
     4086    for (uint32_t i = 0; i < cCacheLines; i++)
     4087    {
     4088        /* Convert the grain table to little endian in place, as it will not
     4089         * be used at all after this function has been called. */
     4090        uint32_t *pGTTmp = &pImage->pGTCache->aGTCache[i].aGTData[0];
     4091        for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
     4092            if (*pGTTmp)
     4093            {
     4094                fAllZero = false;
     4095                break;
     4096            }
     4097        if (!fAllZero)
     4098            break;
     4099    }
     4100    if (fAllZero)
     4101        return VINF_SUCCESS;
     4102
    40884103    uint64_t uFileOffset;
    40894104    rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset);
     
    40934108
    40944109    /* Grain table marker. */
    4095     /** @todo check me! */
    40964110    uint8_t aMarker[512];
    4097     memset(aMarker, '\0', sizeof(aMarker));
    40984111    PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
    4099     pMarker->cbSize = RT_H2LE_U32(pExtent->cGTEntries * sizeof(uint32_t));
     4112    memset(pMarker, '\0', sizeof(aMarker));
     4113    pMarker->uSector = RT_H2LE_U64(VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)));
    41004114    pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GT);
    41014115    rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     
    41214135                               VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t),
    41224136                               NULL);
    4123     }
     4137        uFileOffset += VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t);
     4138        if (RT_FAILURE(rc))
     4139            break;
     4140    }
     4141    Assert(!(uFileOffset % 512));
    41244142    return rc;
    41254143}
     
    41464164        }
    41474165
    4148         /* No need to write any pending data if the file will be deleted. */
    4149         if (!fDelete && pImage->pExtents)
     4166        /* No need to write any pending data if the file will be deleted or if
     4167         * the new file wasn't successfully created. */
     4168        if (!fDelete && pImage->pExtents && pImage->pExtents[0].cGTEntries)
    41504169        {
    41514170            PVMDKEXTENT pExtent = &pImage->pExtents[0];
    41524171            uint32_t uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries;
    4153             if (uLastGDEntry != pExtent->cGDEntries)
     4172            if (uLastGDEntry != pExtent->cGDEntries - 1)
    41544173            {
    41554174                rc = vmdksFlushGT(pImage, pExtent, uLastGDEntry);
     
    41694188
    41704189            /* Grain directory marker. */
    4171             /** @todo check me! */
    41724190            uint8_t aMarker[512];
    4173             memset(aMarker, '\0', sizeof(aMarker));
    41744191            PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
    4175             pMarker->cbSize = RT_H2LE_U32(pExtent->cGDEntries * sizeof(uint32_t));
     4192            memset(pMarker, '\0', sizeof(aMarker));
     4193            pMarker->uSector = VMDK_BYTE2SECTOR(RT_ALIGN_64(RT_H2LE_U64(pExtent->cGDEntries * sizeof(uint32_t)), 512));
    41764194            pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GD);
    41774195            rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     
    41954213            uFileOffset = RT_ALIGN_64(uFileOffset + pExtent->cGDEntries * sizeof(uint32_t), 512);
    41964214
    4197             /* End of stream marker. */
    4198             memset(aMarker, '\0', sizeof(aMarker));
    4199             /** @todo check me! */
     4215            /* Footer marker. */
     4216            memset(pMarker, '\0', sizeof(aMarker));
     4217            pMarker->uSector = VMDK_BYTE2SECTOR(512);
     4218            pMarker->uType = RT_H2LE_U32(VMDK_MARKER_FOOTER);
    42004219            rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
    42014220                                   aMarker, sizeof(aMarker), NULL);
     
    42044223            uFileOffset += 512;
    42054224            rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
     4225            AssertRC(rc);
     4226
     4227            uFileOffset += 512;
     4228            /* End-of-stream marker. */
     4229            memset(pMarker, '\0', sizeof(aMarker));
     4230            rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4231                                   aMarker, sizeof(aMarker), NULL);
    42064232            AssertRC(rc);
    42074233        }
     
    49985024        return VINF_SUCCESS;
    49995025    }
    5000 
    5001     LogFlowFunc(("uGTSector=%llu\n", uGTSector));
    50025026
    50035027    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
     
    58585882    /* Do not allow to go back. */
    58595883    uGrain = VMDK_BYTE2SECTOR(uOffset) / pExtent->cSectorsPerGrain;
    5860     uCacheLine = uGrain / VMDK_GT_CACHELINE_SIZE % VMDK_GT_CACHE_SIZE;
     5884    uCacheLine = uGrain % pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
    58615885    uCacheEntry = uGrain % VMDK_GT_CACHELINE_SIZE;
    58625886    uGDEntry = uGrain / pExtent->cGTEntries;
     
    58655889    {
    58665890        rc = VERR_VD_VMDK_INVALID_WRITE;
     5891        goto out;
     5892    }
     5893
     5894    /* Zero byte write optimization. Since we don't tell VBoxHDD that we need
     5895     * to allocate something, we also need to detect the situation ourself. */
     5896    if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
     5897        && ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbToWrite * 8) == -1)
     5898    {
     5899        rc = VINF_SUCCESS;
     5900        if (pcbWriteProcess)
     5901            *pcbWriteProcess = cbToWrite;
    58675902        goto out;
    58685903    }
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