VirtualBox

Changeset 38875 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Sep 27, 2011 9:01:41 AM (13 years ago)
Author:
vboxsync
Message:

Storage/QCOW: Fix v1 support, compatible with qemu now

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/QCOW.cpp

    r38623 r38875  
    120120#define QCOW_V2_HDR_SIZE                      (72)
    121121
     122/** Cluster is compressed flag for QCOW images. */
     123#define QCOW_V1_COMPRESSED_FLAG               RT_BIT_64(63)
     124
     125/** Copied flag for QCOW2 images. */
     126#define QCOW_V2_COPIED_FLAG                   RT_BIT_64(63)
     127/** Cluster is compressed flag for QCOW2 images. */
     128#define QCOW_V2_COMPRESSED_FLAG               RT_BIT_64(62)
     129
     130
    122131/*******************************************************************************
    123132*   Constants And Macros, Structures and Typedefs                              *
     
    193202    uint32_t            cbBackingFilename;
    194203
    195     /** Size of the image, multiple of clusters. */
    196     uint64_t            cbImage;
     204    /** Next offset of a new cluster, aligned to sector size. */
     205    uint64_t            offNextCluster;
    197206    /** Cluster size in bytes. */
    198207    uint32_t            cbCluster;
     
    221230    /** Size of the refcount table in bytes. */
    222231    uint32_t            cbRefcountTable;
     232    /** Number of entries in the refcount table. */
     233    uint32_t            cRefcountTableEntries;
     234    /** Pointer to the refcount table. */
     235    uint64_t           *paRefcountTable;
    223236
    224237    /** Offset mask for a cluster. */
     
    260273    QCOWCLUSTERASYNCALLOCSTATE enmAllocState;
    261274    /** Old image size to rollback in case of an error. */
    262     uint64_t                   cbImageOld;
     275    uint64_t                   offNextClusterOld;
    263276    /** L1 index to link if any. */
    264277    uint32_t                   idxL1;
     
    383396        pHeader->Version.v2.u64BackingFileOffset     = RT_H2BE_U64(pImage->offBackingFilename);
    384397        pHeader->Version.v2.u32BackingFileSize       = RT_H2BE_U32(pImage->cbBackingFilename);
    385         pHeader->Version.v2.u32ClusterBits           = qcowGetPowerOfTwo(pImage->cbCluster);
     398        pHeader->Version.v2.u32ClusterBits           = RT_H2BE_U32(qcowGetPowerOfTwo(pImage->cbCluster));
    386399        pHeader->Version.v2.u64Size                  = RT_H2BE_U64(pImage->cbSize);
    387400        pHeader->Version.v2.u32CryptMethod           = RT_H2BE_U32(0);
     
    428441    {
    429442        *paTblImg = RT_H2BE_U64(*paTbl);
     443        paTbl++;
     444        paTblImg++;
     445    }
     446}
     447
     448/**
     449 * Convert refcount table entries from little endian to host endianess.
     450 *
     451 * @returns nothing.
     452 * @param   paTbl       Pointer to the table.
     453 * @param   cEntries    Number of entries in the table.
     454 */
     455static void qcowRefcountTableConvertToHostEndianess(uint16_t *paTbl, uint32_t cEntries)
     456{
     457    while(cEntries-- > 0)
     458    {
     459        *paTbl = RT_BE2H_U16(*paTbl);
     460        paTbl++;
     461    }
     462}
     463
     464/**
     465 * Convert table entries from host to little endian format.
     466 *
     467 * @returns nothing.
     468 * @param   paTblImg    Pointer to the table which will store the little endian table.
     469 * @param   paTbl       The source table to convert.
     470 * @param   cEntries    Number of entries in the table.
     471 */
     472static void qcowRefcountTableConvertFromHostEndianess(uint16_t *paTblImg, uint16_t *paTbl,
     473                                                      uint32_t cEntries)
     474{
     475    while(cEntries-- > 0)
     476    {
     477        *paTblImg = RT_H2BE_U16(*paTbl);
    430478        paTbl++;
    431479        paTblImg++;
     
    815863    uint64_t offCluster;
    816864
    817     offCluster = pImage->cbImage;
    818     pImage->cbImage += cClusters*pImage->cbCluster;
     865    offCluster = pImage->offNextCluster;
     866    pImage->offNextCluster += cClusters*pImage->cbCluster;
    819867
    820868    return offCluster;
     
    853901            /* Get real file offset. */
    854902            if (pL2Entry->paL2Tbl[idxL2])
    855                 *poffImage = pL2Entry->paL2Tbl[idxL2] + offCluster;
     903            {
     904                uint64_t off = pL2Entry->paL2Tbl[idxL2];
     905
     906                /* Strip flags */
     907                if (pImage->uVersion == 2)
     908                {
     909                    if (RT_UNLIKELY(off & QCOW_V2_COMPRESSED_FLAG))
     910                        rc = VERR_NOT_SUPPORTED;
     911                    else
     912                        off &= ~(QCOW_V2_COMPRESSED_FLAG | QCOW_V2_COPIED_FLAG);
     913                }
     914                else
     915                {
     916                    if (RT_UNLIKELY(off & QCOW_V1_COMPRESSED_FLAG))
     917                        rc = VERR_NOT_SUPPORTED;
     918                    else
     919                        off &= ~QCOW_V1_COMPRESSED_FLAG;
     920                }
     921
     922                *poffImage = off + offCluster;
     923            }
    856924            else
    857925                rc = VERR_VD_BLOCK_FREE;
     
    897965            /* Get real file offset. */
    898966            if (pL2Entry->paL2Tbl[idxL2])
    899                 *poffImage = pL2Entry->paL2Tbl[idxL2] + offCluster;
     967            {
     968                uint64_t off = pL2Entry->paL2Tbl[idxL2];
     969
     970                /* Strip flags */
     971                if (pImage->uVersion == 2)
     972                {
     973                    if (RT_UNLIKELY(off & QCOW_V2_COMPRESSED_FLAG))
     974                        rc = VERR_NOT_SUPPORTED;
     975                    else
     976                        off &= ~(QCOW_V2_COMPRESSED_FLAG | QCOW_V2_COPIED_FLAG);
     977                }
     978                else
     979                {
     980                    if (RT_UNLIKELY(off & QCOW_V1_COMPRESSED_FLAG))
     981                        rc = VERR_NOT_SUPPORTED;
     982                    else
     983                        off &= ~QCOW_V1_COMPRESSED_FLAG;
     984                }
     985
     986                *poffImage = off + offCluster;
     987            }
    900988            else
    901989                rc = VERR_VD_BLOCK_FREE;
     
    9171005
    9181006    if (   pImage->pStorage
    919         && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     1007        && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     1008        && pImage->cbL1Table)
    9201009    {
    9211010        QCowHeader Header;
     
    10821171            && qcowHdrConvertToHostEndianess(&Header))
    10831172        {
    1084             pImage->cbImage = cbFile;
     1173            pImage->offNextCluster = RT_ALIGN_64(cbFile, 512); /* Align image to sector boundary. */
     1174            Assert(pImage->offNextCluster >= cbFile);
     1175
     1176            rc = qcowL2TblCacheCreate(pImage);
     1177            AssertRC(rc);
    10851178
    10861179            if (Header.u32Version == 1)
     
    11191212                else
    11201213                {
    1121                     rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
    1122                                    N_("QCow: Image '%s' uses version 2 which is not supported"),
    1123                                    pImage->pszFilename);
    1124 #if 0 /** @todo: Add support for the reference count table. */
    1125                     pImage->uVersion           = 2;
    1126                     pImage->offBackingFilename = Header.Version.v2.u64BackingFileOffset;
    1127                     pImage->cbBackingFilename  = Header.Version.v2.u32BackingFileSize;
    1128                     pImage->cbSize             = Header.Version.v2.u64Size;
    1129                     pImage->cbCluster          = RT_BIT_32(Header.Version.v2.u32ClusterBits);
    1130                     pImage->cL2TableEntries    = pImage->cbCluster / sizeof(uint8_t);
    1131                     pImage->cbL2Table          = pImage->cbCluster;
    1132                     pImage->offL1Table         = Header.Version.v2.u64L1TableOffset;
    1133                     pImage->cL1TableEntries    = 0; /** @todo */
    1134                     pImage->cbL1Table          = RT_ALIGN_64(pImage->cL1TableEntries * sizeof(uint64_t), pImage->cbCluster);
    1135                     pImage->offRefcountTable   = Header.Version.v2.u64RefcountTableOffset;
    1136                     pImage->cbRefcountTable    = qcowCluster2Byte(pImage, Header.Version.v2.u32RefcountTableClusters);
    1137 #endif
     1214                    pImage->uVersion              = 2;
     1215                    pImage->offBackingFilename    = Header.Version.v2.u64BackingFileOffset;
     1216                    pImage->cbBackingFilename     = Header.Version.v2.u32BackingFileSize;
     1217                    pImage->cbSize                = Header.Version.v2.u64Size;
     1218                    pImage->cbCluster             = RT_BIT_32(Header.Version.v2.u32ClusterBits);
     1219                    pImage->cL2TableEntries       = pImage->cbCluster / sizeof(uint64_t);
     1220                    pImage->cbL2Table             = pImage->cbCluster;
     1221                    pImage->offL1Table            = Header.Version.v2.u64L1TableOffset;
     1222                    pImage->cL1TableEntries       = Header.Version.v2.u32L1Size;
     1223                    pImage->cbL1Table             = RT_ALIGN_64(pImage->cL1TableEntries * sizeof(uint64_t), pImage->cbCluster);
     1224                    pImage->offRefcountTable      = Header.Version.v2.u64RefcountTableOffset;
     1225                    pImage->cbRefcountTable       = qcowCluster2Byte(pImage, Header.Version.v2.u32RefcountTableClusters);
     1226                    pImage->cRefcountTableEntries = pImage->cbRefcountTable / sizeof(uint64_t);
    11381227                }
    11391228            }
    11401229            else
    1141                 AssertMsgFailed(("Invalid version of image %d\n", Header.u32Version));
     1230                rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
     1231                               N_("QCow: Image '%s' uses version %u which is not supported"),
     1232                               pImage->pszFilename, Header.u32Version);
     1233
     1234            /** @todo: Check that there are no compressed clusters in the image
     1235             *  (by traversing the L2 tables and checking each offset).
     1236             *  Refuse to open such images.
     1237             */
    11421238
    11431239            if (   RT_SUCCESS(rc)
     
    11621258            {
    11631259                /* Load refcount table. */
    1164                 AssertMsgFailed(("TODO\n"));
     1260                Assert(pImage->cRefcountTableEntries);
     1261                pImage->paRefcountTable = (uint64_t *)RTMemAllocZ(pImage->cbRefcountTable);
     1262                if (RT_LIKELY(pImage->paRefcountTable))
     1263                {
     1264                    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
     1265                                               pImage->offRefcountTable, pImage->paRefcountTable,
     1266                                               pImage->cbRefcountTable, NULL);
     1267                    if (RT_SUCCESS(rc))
     1268                        qcowTableConvertToHostEndianess(pImage->paRefcountTable,
     1269                                                        pImage->cRefcountTableEntries);
     1270                    else
     1271                        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
     1272                                       N_("QCow: Reading refcount table of image '%s' failed"),
     1273                                       pImage->pszFilename);
     1274                }
     1275                else
     1276                    rc = vdIfError(pImage->pIfError, VERR_NO_MEMORY, RT_SRC_POS,
     1277                                   N_("QCow: Allocating memory for refcount table of image '%s' failed"),
     1278                                   pImage->pszFilename);
    11651279            }
    11661280
     
    11781292                                               pImage->cbL1Table, NULL);
    11791293                    if (RT_SUCCESS(rc))
    1180                     {
    11811294                        qcowTableConvertToHostEndianess(pImage->paL1Table, pImage->cL1TableEntries);
    1182                         rc = qcowL2TblCacheCreate(pImage);
    1183                         if (RT_FAILURE(rc))
    1184                             rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    1185                                            N_("QCow: Creating the L2 table cache for image '%s' failed"),
    1186                                            pImage->pszFilename);
    1187                     }
    11881295                    else
    11891296                        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
     
    12591366    pImage->cbBackingFilename  = 0;
    12601367    pImage->offBackingFilename = 0;
    1261     pImage->cbImage            = RT_ALIGN_64(QCOW_V1_HDR_SIZE + pImage->cbL1Table, pImage->cbCluster);
     1368    pImage->offNextCluster     = RT_ALIGN_64(QCOW_V1_HDR_SIZE + pImage->cbL1Table, pImage->cbCluster);
    12621369    qcowTableMasksInit(pImage);
    12631370
     
    12841391    rc = qcowFlushImage(pImage);
    12851392    if (RT_SUCCESS(rc))
    1286         rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbImage);
     1393        rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->offNextCluster);
    12871394
    12881395out:
     
    13131420        {
    13141421            /* Assumption right now is that the L1 table is not modified if the link fails. */
    1315             rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pClusterAlloc->cbImageOld);
     1422            rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pClusterAlloc->offNextClusterOld);
    13161423            qcowL2TblCacheEntryRelease(pClusterAlloc->pL2Entry); /* Release L2 cache entry. */
    13171424            qcowL2TblCacheEntryFree(pImage, pClusterAlloc->pL2Entry); /* Free it, it is not in the cache yet. */
     
    13211428        {
    13221429            /* Assumption right now is that the L2 table is not modified if the link fails. */
    1323             rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pClusterAlloc->cbImageOld);
     1430            rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pClusterAlloc->offNextClusterOld);
    13241431            qcowL2TblCacheEntryRelease(pClusterAlloc->pL2Entry); /* Release L2 cache entry. */
    13251432        }
     
    13841491            qcowL2TblCacheEntryInsert(pImage, pClusterAlloc->pL2Entry);
    13851492
    1386             pClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC;
    1387             pClusterAlloc->cbImageOld    = offData;
    1388             pClusterAlloc->offClusterNew = offData;
     1493            pClusterAlloc->enmAllocState     = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC;
     1494            pClusterAlloc->offNextClusterOld = offData;
     1495            pClusterAlloc->offClusterNew     = offData;
    13891496
    13901497            /* Write data. */
     
    24322539    /* Get offset in image. */
    24332540    rc = qcowConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster,
    2434                                       &offFile);
     2541                                       &offFile);
    24352542    if (RT_SUCCESS(rc))
    24362543        rc = vdIfIoIntFileReadUserAsync(pImage->pIfIo, pImage->pStorage, offFile,
     
    25392646                    memset(pL2Entry->paL2Tbl, 0, pImage->cbL2Table);
    25402647
    2541                     pL2ClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC;
    2542                     pL2ClusterAlloc->cbImageOld    = offL2Tbl;
    2543                     pL2ClusterAlloc->offClusterNew = offL2Tbl;
    2544                     pL2ClusterAlloc->idxL1         = idxL1;
    2545                     pL2ClusterAlloc->idxL2         = idxL2;
    2546                     pL2ClusterAlloc->cbToWrite     = cbToWrite;
    2547                     pL2ClusterAlloc->pL2Entry      = pL2Entry;
     2648                    pL2ClusterAlloc->enmAllocState     = QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC;
     2649                    pL2ClusterAlloc->offNextClusterOld = offL2Tbl;
     2650                    pL2ClusterAlloc->offClusterNew     = offL2Tbl;
     2651                    pL2ClusterAlloc->idxL1             = idxL1;
     2652                    pL2ClusterAlloc->idxL2             = idxL2;
     2653                    pL2ClusterAlloc->cbToWrite         = cbToWrite;
     2654                    pL2ClusterAlloc->pL2Entry          = pL2Entry;
    25482655
    25492656                    /*
     
    25862693                        uint64_t offData = qcowClusterAllocate(pImage, 1);
    25872694
    2588                         pDataClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC;
    2589                         pDataClusterAlloc->cbImageOld    = offData;
    2590                         pDataClusterAlloc->offClusterNew = offData;
    2591                         pDataClusterAlloc->idxL1         = idxL1;
    2592                         pDataClusterAlloc->idxL2         = idxL2;
    2593                         pDataClusterAlloc->cbToWrite     = cbToWrite;
    2594                         pDataClusterAlloc->pL2Entry      = pL2Entry;
     2695                        pDataClusterAlloc->enmAllocState     = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC;
     2696                        pDataClusterAlloc->offNextClusterOld = offData;
     2697                        pDataClusterAlloc->offClusterNew     = offData;
     2698                        pDataClusterAlloc->idxL1             = idxL1;
     2699                        pDataClusterAlloc->idxL2             = idxL2;
     2700                        pDataClusterAlloc->cbToWrite         = cbToWrite;
     2701                        pDataClusterAlloc->pL2Entry          = pL2Entry;
    25952702
    25962703                        /* Write data. */
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