Changeset 38875 in vbox for trunk/src/VBox
- Timestamp:
- Sep 27, 2011 9:01:41 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/QCOW.cpp
r38623 r38875 120 120 #define QCOW_V2_HDR_SIZE (72) 121 121 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 122 131 /******************************************************************************* 123 132 * Constants And Macros, Structures and Typedefs * … … 193 202 uint32_t cbBackingFilename; 194 203 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; 197 206 /** Cluster size in bytes. */ 198 207 uint32_t cbCluster; … … 221 230 /** Size of the refcount table in bytes. */ 222 231 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; 223 236 224 237 /** Offset mask for a cluster. */ … … 260 273 QCOWCLUSTERASYNCALLOCSTATE enmAllocState; 261 274 /** Old image size to rollback in case of an error. */ 262 uint64_t cbImageOld;275 uint64_t offNextClusterOld; 263 276 /** L1 index to link if any. */ 264 277 uint32_t idxL1; … … 383 396 pHeader->Version.v2.u64BackingFileOffset = RT_H2BE_U64(pImage->offBackingFilename); 384 397 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)); 386 399 pHeader->Version.v2.u64Size = RT_H2BE_U64(pImage->cbSize); 387 400 pHeader->Version.v2.u32CryptMethod = RT_H2BE_U32(0); … … 428 441 { 429 442 *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 */ 455 static 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 */ 472 static void qcowRefcountTableConvertFromHostEndianess(uint16_t *paTblImg, uint16_t *paTbl, 473 uint32_t cEntries) 474 { 475 while(cEntries-- > 0) 476 { 477 *paTblImg = RT_H2BE_U16(*paTbl); 430 478 paTbl++; 431 479 paTblImg++; … … 815 863 uint64_t offCluster; 816 864 817 offCluster = pImage-> cbImage;818 pImage-> cbImage+= cClusters*pImage->cbCluster;865 offCluster = pImage->offNextCluster; 866 pImage->offNextCluster += cClusters*pImage->cbCluster; 819 867 820 868 return offCluster; … … 853 901 /* Get real file offset. */ 854 902 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 } 856 924 else 857 925 rc = VERR_VD_BLOCK_FREE; … … 897 965 /* Get real file offset. */ 898 966 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 } 900 988 else 901 989 rc = VERR_VD_BLOCK_FREE; … … 917 1005 918 1006 if ( pImage->pStorage 919 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 1007 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 1008 && pImage->cbL1Table) 920 1009 { 921 1010 QCowHeader Header; … … 1082 1171 && qcowHdrConvertToHostEndianess(&Header)) 1083 1172 { 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); 1085 1178 1086 1179 if (Header.u32Version == 1) … … 1119 1212 else 1120 1213 { 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); 1138 1227 } 1139 1228 } 1140 1229 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 */ 1142 1238 1143 1239 if ( RT_SUCCESS(rc) … … 1162 1258 { 1163 1259 /* 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); 1165 1279 } 1166 1280 … … 1178 1292 pImage->cbL1Table, NULL); 1179 1293 if (RT_SUCCESS(rc)) 1180 {1181 1294 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 }1188 1295 else 1189 1296 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, … … 1259 1366 pImage->cbBackingFilename = 0; 1260 1367 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); 1262 1369 qcowTableMasksInit(pImage); 1263 1370 … … 1284 1391 rc = qcowFlushImage(pImage); 1285 1392 if (RT_SUCCESS(rc)) 1286 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage-> cbImage);1393 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->offNextCluster); 1287 1394 1288 1395 out: … … 1313 1420 { 1314 1421 /* 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); 1316 1423 qcowL2TblCacheEntryRelease(pClusterAlloc->pL2Entry); /* Release L2 cache entry. */ 1317 1424 qcowL2TblCacheEntryFree(pImage, pClusterAlloc->pL2Entry); /* Free it, it is not in the cache yet. */ … … 1321 1428 { 1322 1429 /* 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); 1324 1431 qcowL2TblCacheEntryRelease(pClusterAlloc->pL2Entry); /* Release L2 cache entry. */ 1325 1432 } … … 1384 1491 qcowL2TblCacheEntryInsert(pImage, pClusterAlloc->pL2Entry); 1385 1492 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; 1389 1496 1390 1497 /* Write data. */ … … 2432 2539 /* Get offset in image. */ 2433 2540 rc = qcowConvertToImageOffsetAsync(pImage, pIoCtx, idxL1, idxL2, offCluster, 2434 &offFile);2541 &offFile); 2435 2542 if (RT_SUCCESS(rc)) 2436 2543 rc = vdIfIoIntFileReadUserAsync(pImage->pIfIo, pImage->pStorage, offFile, … … 2539 2646 memset(pL2Entry->paL2Tbl, 0, pImage->cbL2Table); 2540 2647 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; 2548 2655 2549 2656 /* … … 2586 2693 uint64_t offData = qcowClusterAllocate(pImage, 1); 2587 2694 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; 2595 2702 2596 2703 /* Write data. */
Note:
See TracChangeset
for help on using the changeset viewer.