Changeset 32370 in vbox
- Timestamp:
- Sep 9, 2010 9:39:15 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 65720
- Location:
- trunk
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/VBoxHDD-Plugin.h
r31776 r32370 24 24 */ 25 25 26 #ifndef __VBoxHDD_ Internal_h__27 26 #ifndef __VBoxHDD_Plugin_h__ 27 #define __VBoxHDD_Plugin_h__ 28 28 29 29 #include <VBox/pdm.h> -
trunk/include/VBox/VBoxHDD.h
r32277 r32370 1912 1912 1913 1913 /** 1914 * Opens a cache image. 1915 * 1916 * @return VBox status code. 1917 * @param pDisk Pointer to the HDD container which should use the cache image. 1918 * @param pszBackend Name of the cache file backend to use (case insensitive). 1919 * @param pszFilename Name of the cache image to open. 1920 * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. 1921 * @param pVDIfsCache Pointer to the per-cache VD interface list. 1922 */ 1923 VBOXDDU_DECL(int) VDCacheOpen(PVBOXHDD pDisk, const char *pszBackend, 1924 const char *pszFilename, unsigned uOpenFlags, 1925 PVDINTERFACE pVDIfsCache); 1926 1927 /** 1914 1928 * Creates and opens a new base image file. 1915 1929 * … … 1959 1973 PVDINTERFACE pVDIfsImage, 1960 1974 PVDINTERFACE pVDIfsOperation); 1975 1976 /** 1977 * Creates and opens new cache image file in HDD container. 1978 * 1979 * @return VBox status code. 1980 * @param pDisk Name of the cache file backend to use (case insensitive). 1981 * @param pszFilename Name of the differencing cache file to create. 1982 * @param cbSize Maximum size of the cache. 1983 * @param uImageFlags Flags specifying special cache features. 1984 * @param pszComment Pointer to image comment. NULL is ok. 1985 * @param pUuid New UUID of the image. If NULL, a new UUID is created. 1986 * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. 1987 * @param pVDIfsCache Pointer to the per-cache VD interface list. 1988 * @param pVDIfsOperation Pointer to the per-operation VD interface list. 1989 */ 1990 VBOXDDU_DECL(int) VDCreateCache(PVBOXHDD pDisk, const char *pszBackend, 1991 const char *pszFilename, uint64_t cbSize, 1992 unsigned uImageFlags, const char *pszComment, 1993 PCRTUUID pUuid, unsigned uOpenFlags, 1994 PVDINTERFACE pVDIfsCache, PVDINTERFACE pVDIfsOperation); 1961 1995 1962 1996 /** … … 2044 2078 2045 2079 /** 2046 * Resizes the thegiven disk image to the given size.2080 * Resizes the given disk image to the given size. 2047 2081 * 2048 2082 * @return VBox status … … 2073 2107 */ 2074 2108 VBOXDDU_DECL(int) VDClose(PVBOXHDD pDisk, bool fDelete); 2109 2110 /** 2111 * Closes the currently opened cache image file in HDD container. 2112 * 2113 * @return VBox status code. 2114 * @return VERR_VD_NOT_OPENED if no cache is opened in HDD container. 2115 * @param pDisk Pointer to HDD container. 2116 * @param fDelete If true, delete the image from the host disk. 2117 */ 2118 VBOXDDU_DECL(int) VDCacheClose(PVBOXHDD pDisk, bool fDelete); 2075 2119 2076 2120 /** -
trunk/include/VBox/err.h
r31491 r32370 1255 1255 /** Halt the current I/O context until further notification from the backend. */ 1256 1256 #define VERR_VD_IOCTX_HALT (-3273) 1257 /** The disk has a cache attached alreay. */ 1258 #define VERR_VD_CACHE_ALREADY_EXISTS (-3274) 1259 /** There is no cache attached to the disk. */ 1260 #define VERR_VD_CACHE_NOT_FOUND (-3275) 1261 /** The cache is not up to date with the image. */ 1262 #define VERR_VD_CACHE_NOT_UP_TO_DATE (-3276) 1257 1263 /** @} */ 1258 1264 -
trunk/src/VBox/Devices/Makefile.kmk
r32342 r32370 86 86 Storage/RawHDDCore.cpp \ 87 87 Storage/ParallelsHDDCore.cpp \ 88 Storage/VCICacheCore.cpp \ 88 89 Storage/VSCSI/VSCSIDevice.cpp \ 89 90 Storage/VSCSI/VSCSILun.cpp \ -
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r32021 r32370 42 42 43 43 #include <VBox/VBoxHDD-Plugin.h> 44 44 #include <VBox/VBoxHDD-CachePlugin.h> 45 45 46 46 #define VBOXHDDDISK_SIGNATURE 0x6f0e2a7d … … 103 103 104 104 /** 105 * VBox HDD Cache image descriptor. 106 */ 107 typedef struct VDCACHE 108 { 109 /** Cache base filename. (UTF-8) */ 110 char *pszFilename; 111 /** Data managed by the backend which keeps the actual info. */ 112 void *pvBackendData; 113 /** Cached sanitized image flags. */ 114 unsigned uImageFlags; 115 /** Image open flags (only those handled generically in this code and which 116 * the backends will never ever see). */ 117 unsigned uOpenFlags; 118 119 /** Function pointers for the various backend methods. */ 120 PCVDCACHEBACKEND Backend; 121 /** Per image I/O interface. */ 122 VDINTERFACE VDIIO; 123 /** Pointer to list of VD interfaces, per-cache. */ 124 PVDINTERFACE pVDIfsCache; 125 /** Disk this image is part of */ 126 PVBOXHDD pDisk; 127 } VDCACHE, *PVDCACHE; 128 129 /** 105 130 * VBox HDD Container main structure, private part. 106 131 */ … … 170 195 /** List of waiting requests. - Protected by the critical section. */ 171 196 RTLISTNODE ListWriteGrowing; 197 198 /** Pointer to the L2 disk cache if any. */ 199 PVDCACHE pCache; 172 200 }; 173 201 … … 419 447 420 448 /** 449 * Supported backends for the disk cache. 450 */ 451 extern VDCACHEBACKEND g_VciCacheBackend; 452 453 static unsigned g_cCacheBackends = 0; 454 static PVDCACHEBACKEND *g_apCacheBackends = NULL; 455 static PVDCACHEBACKEND aStaticCacheBackends[] = 456 { 457 &g_VciCacheBackend 458 }; 459 460 /** 421 461 * internal: add several backends. 422 462 */ … … 442 482 443 483 /** 484 * internal: add several cache backends. 485 */ 486 static int vdAddCacheBackends(PVDCACHEBACKEND *ppBackends, unsigned cBackends) 487 { 488 PVDCACHEBACKEND *pTmp = (PVDCACHEBACKEND*)RTMemRealloc(g_apCacheBackends, 489 (g_cCacheBackends + cBackends) * sizeof(PVDCACHEBACKEND)); 490 if (RT_UNLIKELY(!pTmp)) 491 return VERR_NO_MEMORY; 492 g_apCacheBackends = pTmp; 493 memcpy(&g_apCacheBackends[g_cCacheBackends], ppBackends, cBackends * sizeof(PVDCACHEBACKEND)); 494 g_cCacheBackends += cBackends; 495 return VINF_SUCCESS; 496 } 497 498 /** 499 * internal: add single cache backend. 500 */ 501 DECLINLINE(int) vdAddCacheBackend(PVDCACHEBACKEND pBackend) 502 { 503 return vdAddCacheBackends(&pBackend, 1); 504 } 505 506 /** 444 507 * internal: issue error message. 445 508 */ … … 523 586 524 587 /** 588 * internal: find cache format backend. 589 */ 590 static int vdFindCacheBackend(const char *pszBackend, PCVDCACHEBACKEND *ppBackend) 591 { 592 int rc = VINF_SUCCESS; 593 PCVDCACHEBACKEND pBackend = NULL; 594 595 if (!g_apCacheBackends) 596 VDInit(); 597 598 for (unsigned i = 0; i < g_cCacheBackends; i++) 599 { 600 if (!RTStrICmp(pszBackend, g_apCacheBackends[i]->pszBackendName)) 601 { 602 pBackend = g_apCacheBackends[i]; 603 break; 604 } 605 } 606 *ppBackend = pBackend; 607 return rc; 608 } 609 610 /** 525 611 * internal: add image structure to the end of images list. 526 612 */ … … 587 673 588 674 /** 675 * Internal: Tries to read the desired range from the given cache. 676 * 677 * @returns VBox status code. 678 * @retval VERR_VD_BLOCK_FREE if the block is not in the cache. 679 * pcbRead will be set to the number of bytes not in the cache. 680 * Everything thereafter might be in the cache. 681 * @param pCache The cache to read from. 682 * @param uOffset Offset of the virtual disk to read. 683 * @param pvBuf Where to store the read data. 684 * @param cbRead How much to read. 685 * @param pcbRead Where to store the number of bytes actually read. 686 * On success this indicates the number of bytes read from the cache. 687 * If VERR_VD_BLOCK_FREE is returned this gives the number of bytes 688 * whih are not in the cache. 689 * In both cases everything beyond this value 690 * might or might not be in the cache. 691 */ 692 static int vdCacheReadHelper(PVDCACHE pCache, uint64_t uOffset, 693 void *pvBuf, size_t cbRead, size_t *pcbRead) 694 { 695 int rc = VINF_SUCCESS; 696 697 LogFlowFunc(("pCache=%#p uOffset=%llu pvBuf=%#p cbRead=%zu pcbRead=%#p\n", 698 pCache, uOffset, pvBuf, cbRead, pcbRead)); 699 700 AssertPtr(pCache); 701 AssertPtr(pcbRead); 702 703 rc = pCache->Backend->pfnRead(pCache->pvBackendData, uOffset, pvBuf, 704 cbRead, pcbRead); 705 706 LogFlowFunc(("returns rc=%Rrc pcbRead=%zu\n", rc, *pcbRead)); 707 return rc; 708 } 709 710 /** 711 * Internal: Writes data for the given block into the cache. 712 * 713 * @returns VBox status code. 714 * @param pCache The cache to write to. 715 * @param uOffset Offset of the virtual disk to write to teh cache. 716 * @param pcvBuf The data to write. 717 * @param cbWrite How much to write. 718 * @param pcbWritten How much data could be written, optional. 719 */ 720 static int vdCacheWriteHelper(PVDCACHE pCache, uint64_t uOffset, const void *pcvBuf, 721 size_t cbWrite, size_t *pcbWritten) 722 { 723 int rc = VINF_SUCCESS; 724 725 LogFlowFunc(("pCache=%#p uOffset=%llu pvBuf=%#p cbWrite=%zu pcbWritten=%#p\n", 726 pCache, uOffset, pcvBuf, cbWrite, pcbWritten)); 727 728 AssertPtr(pCache); 729 AssertPtr(pcvBuf); 730 Assert(cbWrite > 0); 731 732 if (pcbWritten) 733 rc = pCache->Backend->pfnWrite(pCache->pvBackendData, uOffset, pcvBuf, 734 cbWrite, pcbWritten); 735 else 736 { 737 size_t cbWritten = 0; 738 739 do 740 { 741 rc = pCache->Backend->pfnWrite(pCache->pvBackendData, uOffset, pcvBuf, 742 cbWrite, &cbWritten); 743 uOffset += cbWritten; 744 pcvBuf = (char *)pcvBuf + cbWritten; 745 cbWrite -= cbWritten; 746 } while ( cbWrite 747 && RT_SUCCESS(rc)); 748 } 749 750 LogFlowFunc(("returns rc=%Rrc pcbWritten=%zu\n", 751 rc, pcbWritten ? *pcbWritten : cbWrite)); 752 return rc; 753 } 754 755 /** 756 * Internal: Reads a given amount of data from the image chain of the disk. 757 **/ 758 static int vdDiskReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride, 759 uint64_t uOffset, void *pvBuf, size_t cbRead, size_t *pcbThisRead) 760 { 761 int rc = VINF_SUCCESS; 762 size_t cbThisRead = cbRead; 763 764 AssertPtr(pcbThisRead); 765 766 *pcbThisRead = 0; 767 768 /* 769 * Try to read from the given image. 770 * If the block is not allocated read from override chain if present. 771 */ 772 rc = pImage->Backend->pfnRead(pImage->pvBackendData, 773 uOffset, pvBuf, cbThisRead, 774 &cbThisRead); 775 776 if (rc == VERR_VD_BLOCK_FREE) 777 { 778 for (PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev; 779 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE; 780 pCurrImage = pCurrImage->pPrev) 781 { 782 rc = pCurrImage->Backend->pfnRead(pCurrImage->pvBackendData, 783 uOffset, pvBuf, cbThisRead, 784 &cbThisRead); 785 } 786 } 787 788 if (RT_SUCCESS(rc)) 789 *pcbThisRead = cbThisRead; 790 791 return rc; 792 } 793 794 /** 589 795 * internal: read the specified amount of data in whatever blocks the backend 590 796 * will give us. 591 797 */ 592 798 static int vdReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride, 593 uint64_t uOffset, void *pvBuf, size_t cbRead, bool fHandleFreeBlocks) 594 { 595 int rc; 799 uint64_t uOffset, void *pvBuf, size_t cbRead, 800 bool fZeroFreeBlocks, bool fUpdateCache) 801 { 802 int rc = VINF_SUCCESS; 596 803 size_t cbThisRead; 597 804 bool fAllFree = true; … … 606 813 cbThisRead = cbRead; 607 814 608 /* 609 * Try to read from the given image. 610 * If the block is not allocated read from override chain if present. 611 */ 612 rc = pImage->Backend->pfnRead(pImage->pvBackendData, 613 uOffset, pvBuf, cbThisRead, 614 &cbThisRead); 615 616 if (rc == VERR_VD_BLOCK_FREE) 617 { 618 for (PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev; 619 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE; 620 pCurrImage = pCurrImage->pPrev) 815 if ( pDisk->pCache 816 && !pImageParentOverride) 817 { 818 rc = vdCacheReadHelper(pDisk->pCache, uOffset, pvBuf, 819 cbThisRead, &cbThisRead); 820 821 if (rc == VERR_VD_BLOCK_FREE) 621 822 { 622 rc = pCurrImage->Backend->pfnRead(pCurrImage->pvBackendData, 623 uOffset, pvBuf, cbThisRead, 624 &cbThisRead); 823 rc = vdDiskReadHelper(pDisk, pImage, pImageParentOverride, 824 uOffset, pvBuf, cbThisRead, &cbThisRead); 825 826 /* If the read was successful, write the data back into the cache. */ 827 if ( RT_SUCCESS(rc) 828 && fUpdateCache) 829 { 830 rc = vdCacheWriteHelper(pDisk->pCache, uOffset, pvBuf, 831 cbThisRead, NULL); 832 } 833 } 834 } 835 else 836 { 837 /** @todo can be be replaced by vdDiskReadHelper if it proves to be reliable, 838 * don't want to be responsible for data corruption... 839 */ 840 /* 841 * Try to read from the given image. 842 * If the block is not allocated read from override chain if present. 843 */ 844 rc = pImage->Backend->pfnRead(pImage->pvBackendData, 845 uOffset, pvBuf, cbThisRead, 846 &cbThisRead); 847 848 if (rc == VERR_VD_BLOCK_FREE) 849 { 850 for (PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev; 851 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE; 852 pCurrImage = pCurrImage->pPrev) 853 { 854 rc = pCurrImage->Backend->pfnRead(pCurrImage->pvBackendData, 855 uOffset, pvBuf, cbThisRead, 856 &cbThisRead); 857 } 625 858 } 626 859 } … … 631 864 /* Fill the free space with 0 if we are told to do so 632 865 * or a previous read returned valid data. */ 633 if (f HandleFreeBlocks || !fAllFree)866 if (fZeroFreeBlocks || !fAllFree) 634 867 memset(pvBuf, '\0', cbThisRead); 635 868 else … … 641 874 { 642 875 /* First not free block, fill the space before with 0. */ 643 if (!f HandleFreeBlocks)876 if (!fZeroFreeBlocks) 644 877 { 645 878 memset((char *)pvBuf - cbBufClear, '\0', cbBufClear); … … 654 887 } while (cbRead != 0 && RT_SUCCESS(rc)); 655 888 656 return (!f HandleFreeBlocks && fAllFree) ? VERR_VD_BLOCK_FREE : rc;889 return (!fZeroFreeBlocks && fAllFree) ? VERR_VD_BLOCK_FREE : rc; 657 890 } 658 891 … … 1019 1252 PVDPARENTSTATEDESC pParentState = (PVDPARENTSTATEDESC)pvUser; 1020 1253 return vdReadHelper(pParentState->pDisk, pParentState->pImage, NULL, uOffset, 1021 pvBuf, cbRead, true); 1254 pvBuf, cbRead, true /* fZeroFreeBlocks */, 1255 false /* fUpdateCache */); 1022 1256 } 1023 1257 … … 1037 1271 pDisk->pLast->Backend->pfnSetModificationUuid(pDisk->pLast->pvBackendData, 1038 1272 &Uuid); 1273 1274 if (pDisk->pCache) 1275 pDisk->pCache->Backend->pfnSetModificationUuid(pDisk->pCache->pvBackendData, 1276 &Uuid); 1039 1277 } 1040 1278 … … 1056 1294 vdResetModifiedFlag(pDisk); 1057 1295 1058 if (!(pDisk->uModified |VD_IMAGE_MODIFIED_DISABLE_UUID_UPDATE))1296 if (!(pDisk->uModified & VD_IMAGE_MODIFIED_DISABLE_UUID_UPDATE)) 1059 1297 pDisk->pLast->Backend->pfnFlush(pDisk->pLast->pvBackendData); 1060 1298 } … … 1079 1317 if (cbPreRead) 1080 1318 { 1319 /* 1320 * Updating the cache doesn't make sense here because 1321 * this will be done after the complete block was written. 1322 */ 1081 1323 rc = vdReadHelper(pDisk, pImage, pImageParentOverride, 1082 uOffset - cbPreRead, pvTmp, cbPreRead, true); 1324 uOffset - cbPreRead, pvTmp, cbPreRead, 1325 true /* fZeroFreeBlocks*/, 1326 false /* fUpdateCache */); 1083 1327 if (RT_FAILURE(rc)) 1084 1328 return rc; … … 1117 1361 uOffset + cbThisWrite + cbWriteCopy, 1118 1362 (char *)pvTmp + cbPreRead + cbThisWrite + cbWriteCopy, 1119 cbReadImage, true); 1363 cbReadImage, true /* fZeroFreeBlocks */, 1364 false /* fUpdateCache */); 1120 1365 if (RT_FAILURE(rc)) 1121 1366 return rc; … … 1177 1422 * be modified by the write or not. */ 1178 1423 rc = vdReadHelper(pDisk, pImage, pImageParentOverride, uOffset - cbPreRead, pvTmp, 1179 cbPreRead + cbThisWrite + cbPostRead - cbFill, true); 1424 cbPreRead + cbThisWrite + cbPostRead - cbFill, 1425 true /* fZeroFreeBlocks */, 1426 false /* fUpdateCache */); 1180 1427 if (RT_FAILURE(rc)) 1181 1428 return rc; … … 1224 1471 */ 1225 1472 static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride, 1226 uint64_t uOffset, const void *pvBuf, size_t cbWrite) 1473 uint64_t uOffset, const void *pvBuf, size_t cbWrite, 1474 bool fUpdateCache) 1227 1475 { 1228 1476 int rc; … … 1230 1478 size_t cbThisWrite; 1231 1479 size_t cbPreRead, cbPostRead; 1480 uint64_t uOffsetCur = uOffset; 1481 size_t cbWriteCur = cbWrite; 1482 const void *pcvBufCur = pvBuf; 1232 1483 1233 1484 /* Loop until all written. */ … … 1240 1491 * to avoid unnecessarily allocating unchanged blocks. This prevents 1241 1492 * unwanted expanding of images. VMDK is an example. */ 1242 cbThisWrite = cbWrite ;1493 cbThisWrite = cbWriteCur; 1243 1494 fWrite = (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME) 1244 1495 ? 0 : VD_WRITE_NO_ALLOC; 1245 rc = pImage->Backend->pfnWrite(pImage->pvBackendData, uOffset , pvBuf,1496 rc = pImage->Backend->pfnWrite(pImage->pvBackendData, uOffsetCur, pcvBufCur, 1246 1497 cbThisWrite, &cbThisWrite, &cbPreRead, 1247 1498 &cbPostRead, fWrite); … … 1256 1507 * block if the data is in fact not changed. */ 1257 1508 rc = vdWriteHelperOptimized(pDisk, pImage, pImageParentOverride, 1258 uOffset , cbWrite,1509 uOffsetCur, cbWriteCur, 1259 1510 cbThisWrite, cbPreRead, cbPostRead, 1260 p vBuf, pvTmp);1511 pcvBufCur, pvTmp); 1261 1512 } 1262 1513 else … … 1267 1518 * block to be allocated. */ 1268 1519 rc = vdWriteHelperStandard(pDisk, pImage, pImageParentOverride, 1269 uOffset , cbWrite,1520 uOffsetCur, cbWriteCur, 1270 1521 cbThisWrite, cbPreRead, cbPostRead, 1271 p vBuf, pvTmp);1522 pcvBufCur, pvTmp); 1272 1523 } 1273 1524 RTMemTmpFree(pvTmp); … … 1276 1527 } 1277 1528 1278 cbWrite -= cbThisWrite; 1279 uOffset += cbThisWrite; 1280 pvBuf = (char *)pvBuf + cbThisWrite; 1281 } while (cbWrite != 0 && RT_SUCCESS(rc)); 1529 cbWriteCur -= cbThisWrite; 1530 uOffsetCur += cbThisWrite; 1531 pcvBufCur = (char *)pcvBufCur + cbThisWrite; 1532 } while (cbWriteCur != 0 && RT_SUCCESS(rc)); 1533 1534 /* Update the cache on success */ 1535 if ( RT_SUCCESS(rc) 1536 && pDisk->pCache 1537 && fUpdateCache) 1538 rc = vdCacheWriteHelper(pDisk->pCache, uOffset, pvBuf, cbWrite, NULL); 1282 1539 1283 1540 return rc; … … 1731 1988 /* To get all entries with VBoxHDD as prefix. */ 1732 1989 char *pszPluginFilter; 1733 rc = RTStrAPrintf(&pszPluginFilter, "%s/%s*", szPath, 1734 VBOX_HDDFORMAT_PLUGIN_PREFIX); 1990 rc = RTStrAPrintf(&pszPluginFilter, "%s/%s*", szPath, VBOX_HDDFORMAT_PLUGIN_PREFIX); 1735 1991 if (RT_FAILURE(rc)) 1736 1992 { … … 1809 2065 pBackend->hPlugin = hPlugin; 1810 2066 vdAddBackend(pBackend); 2067 } 2068 else 2069 LogFunc(("ignored plugin '%s': pBackend->cbSize=%d rc=%Rrc\n", pszPluginPath, pBackend->cbSize, rc)); 2070 } 2071 else 2072 LogFunc(("ignored plugin '%s': rc=%Rrc\n", pszPluginPath, rc)); 2073 2074 if (RT_FAILURE(rc)) 2075 RTLdrClose(hPlugin); 2076 } 2077 RTStrFree(pszPluginPath); 2078 } 2079 out: 2080 if (rc == VERR_NO_MORE_FILES) 2081 rc = VINF_SUCCESS; 2082 RTStrFree(pszPluginFilter); 2083 if (pPluginDirEntry) 2084 RTMemFree(pPluginDirEntry); 2085 if (pPluginDir) 2086 RTDirClose(pPluginDir); 2087 return rc; 2088 #else 2089 return VINF_SUCCESS; 2090 #endif 2091 } 2092 2093 /** 2094 * internal: scans plugin directory and loads the cache backends have been found. 2095 */ 2096 static int vdLoadDynamicCacheBackends() 2097 { 2098 #ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS 2099 int rc = VINF_SUCCESS; 2100 PRTDIR pPluginDir = NULL; 2101 2102 /* Enumerate plugin backends. */ 2103 char szPath[RTPATH_MAX]; 2104 rc = RTPathAppPrivateArch(szPath, sizeof(szPath)); 2105 if (RT_FAILURE(rc)) 2106 return rc; 2107 2108 /* To get all entries with VBoxHDD as prefix. */ 2109 char *pszPluginFilter; 2110 rc = RTStrAPrintf(&pszPluginFilter, "%s/%s*", szPath, VD_CACHEFORMAT_PLUGIN_PREFIX); 2111 if (RT_FAILURE(rc)) 2112 { 2113 rc = VERR_NO_MEMORY; 2114 return rc; 2115 } 2116 2117 PRTDIRENTRYEX pPluginDirEntry = NULL; 2118 size_t cbPluginDirEntry = sizeof(RTDIRENTRYEX); 2119 /* The plugins are in the same directory as the other shared libs. */ 2120 rc = RTDirOpenFiltered(&pPluginDir, pszPluginFilter, RTDIRFILTER_WINNT); 2121 if (RT_FAILURE(rc)) 2122 { 2123 /* On Windows the above immediately signals that there are no 2124 * files matching, while on other platforms enumerating the 2125 * files below fails. Either way: no plugins. */ 2126 goto out; 2127 } 2128 2129 pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(sizeof(RTDIRENTRYEX)); 2130 if (!pPluginDirEntry) 2131 { 2132 rc = VERR_NO_MEMORY; 2133 goto out; 2134 } 2135 2136 while ((rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK)) != VERR_NO_MORE_FILES) 2137 { 2138 RTLDRMOD hPlugin = NIL_RTLDRMOD; 2139 PFNVDCACHEFORMATLOAD pfnVDCacheLoad = NULL; 2140 PVDCACHEBACKEND pBackend = NULL; 2141 char *pszPluginPath = NULL; 2142 2143 if (rc == VERR_BUFFER_OVERFLOW) 2144 { 2145 /* allocate new buffer. */ 2146 RTMemFree(pPluginDirEntry); 2147 pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(cbPluginDirEntry); 2148 /* Retry. */ 2149 rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); 2150 if (RT_FAILURE(rc)) 2151 break; 2152 } 2153 else if (RT_FAILURE(rc)) 2154 break; 2155 2156 /* We got the new entry. */ 2157 if (!RTFS_IS_FILE(pPluginDirEntry->Info.Attr.fMode)) 2158 continue; 2159 2160 /* Prepend the path to the libraries. */ 2161 rc = RTStrAPrintf(&pszPluginPath, "%s/%s", szPath, pPluginDirEntry->szName); 2162 if (RT_FAILURE(rc)) 2163 { 2164 rc = VERR_NO_MEMORY; 2165 break; 2166 } 2167 2168 rc = SUPR3HardenedLdrLoad(pszPluginPath, &hPlugin); 2169 if (RT_SUCCESS(rc)) 2170 { 2171 rc = RTLdrGetSymbol(hPlugin, VD_CACHEFORMAT_LOAD_NAME, (void**)&pfnVDCacheLoad); 2172 if (RT_FAILURE(rc) || !pfnVDCacheLoad) 2173 { 2174 LogFunc(("error resolving the entry point %s in plugin %s, rc=%Rrc, pfnVDCacheLoad=%#p\n", 2175 VD_CACHEFORMAT_LOAD_NAME, pPluginDirEntry->szName, rc, pfnVDCacheLoad)); 2176 if (RT_SUCCESS(rc)) 2177 rc = VERR_SYMBOL_NOT_FOUND; 2178 } 2179 2180 if (RT_SUCCESS(rc)) 2181 { 2182 /* Get the function table. */ 2183 rc = pfnVDCacheLoad(&pBackend); 2184 if (RT_SUCCESS(rc) && pBackend->cbSize == sizeof(VDCACHEBACKEND)) 2185 { 2186 pBackend->hPlugin = hPlugin; 2187 vdAddCacheBackend(pBackend); 1811 2188 } 1812 2189 else … … 2522 2899 #ifdef RT_STRICT 2523 2900 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGetBestFit(pIoStorage->pTreeMetaXfers, uOffset, false /* fAbove */); 2524 AssertMsg(!pMetaXfer || (pMetaXfer->Core.Key + pMetaXfer->cbMeta <= (RTFOFF)uOffset),2901 AssertMsg(!pMetaXfer || (pMetaXfer->Core.Key + (RTFOFF)pMetaXfer->cbMeta <= (RTFOFF)uOffset), 2525 2902 ("Overlapping meta transfers!\n")); 2526 2903 #endif … … 2950 3327 int rc = vdAddBackends(aStaticBackends, RT_ELEMENTS(aStaticBackends)); 2951 3328 if (RT_SUCCESS(rc)) 2952 rc = vdLoadDynamicBackends(); 3329 { 3330 rc = vdAddCacheBackends(aStaticCacheBackends, RT_ELEMENTS(aStaticCacheBackends)); 3331 if (RT_SUCCESS(rc)) 3332 { 3333 rc = vdLoadDynamicBackends(); 3334 if (RT_SUCCESS(rc)) 3335 rc = vdLoadDynamicCacheBackends(); 3336 } 3337 } 2953 3338 LogRel(("VDInit finished\n")); 2954 3339 return rc; … … 2963 3348 { 2964 3349 PVBOXHDDBACKEND *pBackends = g_apBackends; 3350 PVDCACHEBACKEND *pCacheBackends = g_apCacheBackends; 2965 3351 unsigned cBackends = g_cBackends; 2966 3352 … … 2977 3363 #endif 2978 3364 3365 /* Clear the supported cache backends. */ 3366 cBackends = g_cCacheBackends; 3367 g_cCacheBackends = 0; 3368 g_apCacheBackends = NULL; 3369 3370 #ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS 3371 for (unsigned i = 0; i < cBackends; i++) 3372 if (pCacheBackends[i]->hPlugin != NIL_RTLDRMOD) 3373 RTLdrClose(pCacheBackends[i]->hPlugin); 3374 #endif 3375 3376 if (pCacheBackends) 3377 RTMemFree(pCacheBackends); 2979 3378 RTMemFree(pBackends); 2980 3379 return VINF_SUCCESS; … … 3315 3714 } 3316 3715 3716 /* Try the cache backends. */ 3717 if (rc == VERR_NOT_SUPPORTED) 3718 { 3719 for (unsigned i = 0; i < g_cCacheBackends; i++) 3720 { 3721 if (g_apCacheBackends[i]->pfnProbe) 3722 { 3723 rc = g_apCacheBackends[i]->pfnProbe(pszFilename, pVDIfsDisk); 3724 if ( RT_SUCCESS(rc) 3725 || (rc != VERR_VD_GEN_INVALID_HEADER)) 3726 { 3727 /* Copy the name into the new string. */ 3728 char *pszFormat = RTStrDup(g_apBackends[i]->pszBackendName); 3729 if (!pszFormat) 3730 { 3731 rc = VERR_NO_MEMORY; 3732 break; 3733 } 3734 *ppszFormat = pszFormat; 3735 rc = VINF_SUCCESS; 3736 break; 3737 } 3738 rc = VERR_NOT_SUPPORTED; 3739 } 3740 } 3741 } 3742 3317 3743 LogFlowFunc(("returns %Rrc *ppszFormat=\"%s\"\n", rc, *ppszFormat)); 3318 3744 return rc; … … 3559 3985 RTStrFree(pImage->pszFilename); 3560 3986 RTMemFree(pImage); 3987 } 3988 } 3989 3990 LogFlowFunc(("returns %Rrc\n", rc)); 3991 return rc; 3992 } 3993 3994 /** 3995 * Opens a cache image. 3996 * 3997 * @return VBox status code. 3998 * @param pDisk Pointer to the HDD container which should use the cache image. 3999 * @param pszBackend Name of the cache file backend to use (case insensitive). 4000 * @param pszFilename Name of the cache image to open. 4001 * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. 4002 * @param pVDIfsCache Pointer to the per-cache VD interface list. 4003 */ 4004 VBOXDDU_DECL(int) VDCacheOpen(PVBOXHDD pDisk, const char *pszBackend, 4005 const char *pszFilename, unsigned uOpenFlags, 4006 PVDINTERFACE pVDIfsCache) 4007 { 4008 int rc = VINF_SUCCESS; 4009 int rc2; 4010 bool fLockWrite = false; 4011 PVDCACHE pCache = NULL; 4012 4013 LogFlowFunc(("pDisk=%#p pszBackend=\"%s\" pszFilename=\"%s\" uOpenFlags=%#x, pVDIfsCache=%#p\n", 4014 pDisk, pszBackend, pszFilename, uOpenFlags, pVDIfsCache)); 4015 4016 do 4017 { 4018 /* sanity check */ 4019 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 4020 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 4021 4022 /* Check arguments. */ 4023 AssertMsgBreakStmt(VALID_PTR(pszBackend) && *pszBackend, 4024 ("pszBackend=%#p \"%s\"\n", pszBackend, pszBackend), 4025 rc = VERR_INVALID_PARAMETER); 4026 AssertMsgBreakStmt(VALID_PTR(pszFilename) && *pszFilename, 4027 ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename), 4028 rc = VERR_INVALID_PARAMETER); 4029 AssertMsgBreakStmt((uOpenFlags & ~VD_OPEN_FLAGS_MASK) == 0, 4030 ("uOpenFlags=%#x\n", uOpenFlags), 4031 rc = VERR_INVALID_PARAMETER); 4032 4033 /* Set up image descriptor. */ 4034 pCache = (PVDCACHE)RTMemAllocZ(sizeof(VDCACHE)); 4035 if (!pCache) 4036 { 4037 rc = VERR_NO_MEMORY; 4038 break; 4039 } 4040 pCache->pszFilename = RTStrDup(pszFilename); 4041 if (!pCache->pszFilename) 4042 { 4043 rc = VERR_NO_MEMORY; 4044 break; 4045 } 4046 4047 pCache->pDisk = pDisk; 4048 pCache->pVDIfsCache = pVDIfsCache; 4049 4050 rc = vdFindCacheBackend(pszBackend, &pCache->Backend); 4051 if (RT_FAILURE(rc)) 4052 break; 4053 if (!pCache->Backend) 4054 { 4055 rc = vdError(pDisk, VERR_INVALID_PARAMETER, RT_SRC_POS, 4056 N_("VD: unknown backend name '%s'"), pszBackend); 4057 break; 4058 } 4059 4060 /* Set up the I/O interface. */ 4061 rc = VDInterfaceAdd(&pCache->VDIIO, "VD_IO", VDINTERFACETYPE_IO, 4062 &pDisk->VDIIOCallbacks, pCache, &pCache->pVDIfsCache); 4063 AssertRC(rc); 4064 4065 pCache->uOpenFlags = uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME; 4066 rc = pCache->Backend->pfnOpen(pCache->pszFilename, 4067 uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME, 4068 pDisk->pVDIfsDisk, 4069 pCache->pVDIfsCache, 4070 &pCache->pvBackendData); 4071 /* If the open in read-write mode failed, retry in read-only mode. */ 4072 if (RT_FAILURE(rc)) 4073 { 4074 if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY) 4075 && ( rc == VERR_ACCESS_DENIED 4076 || rc == VERR_PERMISSION_DENIED 4077 || rc == VERR_WRITE_PROTECT 4078 || rc == VERR_SHARING_VIOLATION 4079 || rc == VERR_FILE_LOCK_FAILED)) 4080 rc = pCache->Backend->pfnOpen(pCache->pszFilename, 4081 (uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME) 4082 | VD_OPEN_FLAGS_READONLY, 4083 pDisk->pVDIfsDisk, 4084 pCache->pVDIfsCache, 4085 &pCache->pvBackendData); 4086 if (RT_FAILURE(rc)) 4087 { 4088 rc = vdError(pDisk, rc, RT_SRC_POS, 4089 N_("VD: error %Rrc opening image file '%s'"), rc, pszFilename); 4090 break; 4091 } 4092 } 4093 4094 /* Lock disk for writing, as we modify pDisk information below. */ 4095 rc2 = vdThreadStartWrite(pDisk); 4096 AssertRC(rc2); 4097 fLockWrite = true; 4098 4099 /* 4100 * Check that the modification UUID of the cache and last image 4101 * match. If not the image was modified inbetween without the cache. 4102 * The cache might contain stale data. 4103 */ 4104 RTUUID UuidImage, UuidCache; 4105 4106 rc = pCache->Backend->pfnGetModificationUuid(pCache->pvBackendData, 4107 &UuidCache); 4108 if (RT_SUCCESS(rc)) 4109 { 4110 rc = pDisk->pLast->Backend->pfnGetModificationUuid(pDisk->pLast->pvBackendData, 4111 &UuidImage); 4112 if (RT_SUCCESS(rc)) 4113 { 4114 if (RTUuidCompare(&UuidImage, &UuidCache)) 4115 rc = VERR_VD_CACHE_NOT_UP_TO_DATE; 4116 } 4117 } 4118 4119 /* 4120 * We assume that the user knows what he is doing if one of the images 4121 * doesn't support the modification uuid. 4122 */ 4123 if (rc == VERR_NOT_SUPPORTED) 4124 rc = VINF_SUCCESS; 4125 4126 if (RT_SUCCESS(rc)) 4127 { 4128 /* Cache successfully opened, make it the current one. */ 4129 if (!pDisk->pCache) 4130 pDisk->pCache = pCache; 4131 else 4132 rc = VERR_VD_CACHE_ALREADY_EXISTS; 4133 } 4134 4135 if (RT_FAILURE(rc)) 4136 { 4137 /* Error detected, but image opened. Close image. */ 4138 rc2 = pCache->Backend->pfnClose(pCache->pvBackendData, false); 4139 AssertRC(rc2); 4140 pCache->pvBackendData = NULL; 4141 } 4142 } while (0); 4143 4144 if (RT_UNLIKELY(fLockWrite)) 4145 { 4146 rc2 = vdThreadFinishWrite(pDisk); 4147 AssertRC(rc2); 4148 } 4149 4150 if (RT_FAILURE(rc)) 4151 { 4152 if (pCache) 4153 { 4154 if (pCache->pszFilename) 4155 RTStrFree(pCache->pszFilename); 4156 RTMemFree(pCache); 3561 4157 } 3562 4158 } … … 3856 4452 RTUUID uuid; 3857 4453 3858 LogFlowFunc(("pDisk=%#p pszBackend=\"%s\" pszFilename=\"%s\" uImageFlags=%#x pszComment=\"%s\" Uuid=%RTuuid ParentUuid=%RTuuid uOpenFlags=%#x pVDIfsImage=%#p pVDIfsOperation=%#p\n", 3859 pDisk, pszBackend, pszFilename, uImageFlags, pszComment, pUuid, pParentUuid, uOpenFlags, 3860 pVDIfsImage, pVDIfsOperation)); 4454 LogFlowFunc(("pDisk=%#p pszBackend=\"%s\" pszFilename=\"%s\" uImageFlags=%#x pszComment=\"%s\" Uuid=%RTuuid uOpenFlags=%#x pVDIfsImage=%#p pVDIfsOperation=%#p\n", 4455 pDisk, pszBackend, pszFilename, uImageFlags, pszComment, pUuid, uOpenFlags, pVDIfsImage, pVDIfsOperation)); 3861 4456 3862 4457 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation, … … 4068 4663 4069 4664 /** 4665 * Creates and opens new cache image file in HDD container. 4666 * 4667 * @return VBox status code. 4668 * @param pDisk Name of the cache file backend to use (case insensitive). 4669 * @param pszFilename Name of the differencing cache file to create. 4670 * @param cbSize Maximum size of the cache. 4671 * @param uImageFlags Flags specifying special cache features. 4672 * @param pszComment Pointer to image comment. NULL is ok. 4673 * @param pUuid New UUID of the image. If NULL, a new UUID is created. 4674 * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. 4675 * @param pVDIfsCache Pointer to the per-cache VD interface list. 4676 * @param pVDIfsOperation Pointer to the per-operation VD interface list. 4677 */ 4678 VBOXDDU_DECL(int) VDCreateCache(PVBOXHDD pDisk, const char *pszBackend, 4679 const char *pszFilename, uint64_t cbSize, 4680 unsigned uImageFlags, const char *pszComment, 4681 PCRTUUID pUuid, unsigned uOpenFlags, 4682 PVDINTERFACE pVDIfsCache, PVDINTERFACE pVDIfsOperation) 4683 { 4684 int rc = VINF_SUCCESS; 4685 int rc2; 4686 bool fLockWrite = false, fLockRead = false; 4687 PVDCACHE pCache = NULL; 4688 RTUUID uuid; 4689 4690 LogFlowFunc(("pDisk=%#p pszBackend=\"%s\" pszFilename=\"%s\" cbSIze=%llu uImageFlags=%#x pszComment=\"%s\" Uuid=%RTuuid uOpenFlags=%#x pVDIfsImage=%#p pVDIfsOperation=%#p\n", 4691 pDisk, pszBackend, pszFilename, cbSize, uImageFlags, pszComment, pUuid, uOpenFlags, pVDIfsCache, pVDIfsOperation)); 4692 4693 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation, 4694 VDINTERFACETYPE_PROGRESS); 4695 PVDINTERFACEPROGRESS pCbProgress = NULL; 4696 if (pIfProgress) 4697 pCbProgress = VDGetInterfaceProgress(pIfProgress); 4698 4699 do 4700 { 4701 /* sanity check */ 4702 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 4703 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 4704 4705 /* Check arguments. */ 4706 AssertMsgBreakStmt(VALID_PTR(pszBackend) && *pszBackend, 4707 ("pszBackend=%#p \"%s\"\n", pszBackend, pszBackend), 4708 rc = VERR_INVALID_PARAMETER); 4709 AssertMsgBreakStmt(VALID_PTR(pszFilename) && *pszFilename, 4710 ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename), 4711 rc = VERR_INVALID_PARAMETER); 4712 AssertMsgBreakStmt(cbSize, 4713 ("cbSize=%llu\n", cbSize), 4714 rc = VERR_INVALID_PARAMETER); 4715 AssertMsgBreakStmt((uImageFlags & ~VD_IMAGE_FLAGS_MASK) == 0, 4716 ("uImageFlags=%#x\n", uImageFlags), 4717 rc = VERR_INVALID_PARAMETER); 4718 /* The UUID may be NULL. */ 4719 AssertMsgBreakStmt(pUuid == NULL || VALID_PTR(pUuid), 4720 ("pUuid=%#p UUID=%RTuuid\n", pUuid, pUuid), 4721 rc = VERR_INVALID_PARAMETER); 4722 AssertMsgBreakStmt((uOpenFlags & ~VD_OPEN_FLAGS_MASK) == 0, 4723 ("uOpenFlags=%#x\n", uOpenFlags), 4724 rc = VERR_INVALID_PARAMETER); 4725 4726 /* Check state. Needs a temporary read lock. Holding the write lock 4727 * all the time would be blocking other activities for too long. */ 4728 rc2 = vdThreadStartRead(pDisk); 4729 AssertRC(rc2); 4730 fLockRead = true; 4731 AssertMsgBreakStmt(pDisk->cImages != 0, 4732 ("Create diff image cannot be done without other images open\n"), 4733 rc = VERR_VD_INVALID_STATE); 4734 AssertMsgBreakStmt(!pDisk->pCache, 4735 ("Create cache image cannot be done with a cache already attached\n"), 4736 rc = VERR_VD_CACHE_ALREADY_EXISTS); 4737 rc2 = vdThreadFinishRead(pDisk); 4738 AssertRC(rc2); 4739 fLockRead = false; 4740 4741 /* Set up image descriptor. */ 4742 pCache = (PVDCACHE)RTMemAllocZ(sizeof(VDCACHE)); 4743 if (!pCache) 4744 { 4745 rc = VERR_NO_MEMORY; 4746 break; 4747 } 4748 pCache->pszFilename = RTStrDup(pszFilename); 4749 if (!pCache->pszFilename) 4750 { 4751 rc = VERR_NO_MEMORY; 4752 break; 4753 } 4754 4755 rc = vdFindCacheBackend(pszBackend, &pCache->Backend); 4756 if (RT_FAILURE(rc)) 4757 break; 4758 if (!pCache->Backend) 4759 { 4760 rc = vdError(pDisk, VERR_INVALID_PARAMETER, RT_SRC_POS, 4761 N_("VD: unknown backend name '%s'"), pszBackend); 4762 break; 4763 } 4764 4765 pCache->pDisk = pDisk; 4766 pCache->pVDIfsCache = pVDIfsCache; 4767 4768 /* Set up the I/O interface. */ 4769 rc = VDInterfaceAdd(&pCache->VDIIO, "VD_IO", VDINTERFACETYPE_IO, 4770 &pDisk->VDIIOCallbacks, pCache, &pCache->pVDIfsCache); 4771 AssertRC(rc); 4772 4773 /* Create UUID if the caller didn't specify one. */ 4774 if (!pUuid) 4775 { 4776 rc = RTUuidCreate(&uuid); 4777 if (RT_FAILURE(rc)) 4778 { 4779 rc = vdError(pDisk, rc, RT_SRC_POS, 4780 N_("VD: cannot generate UUID for image '%s'"), 4781 pszFilename); 4782 break; 4783 } 4784 pUuid = &uuid; 4785 } 4786 4787 pCache->uOpenFlags = uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME; 4788 rc = pCache->Backend->pfnCreate(pCache->pszFilename, cbSize, 4789 uImageFlags, 4790 pszComment, pUuid, 4791 uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME, 4792 0, 99, 4793 pDisk->pVDIfsDisk, 4794 pCache->pVDIfsCache, 4795 pVDIfsOperation, 4796 &pCache->pvBackendData); 4797 4798 if (RT_SUCCESS(rc)) 4799 { 4800 /* Lock disk for writing, as we modify pDisk information below. */ 4801 rc2 = vdThreadStartWrite(pDisk); 4802 AssertRC(rc2); 4803 fLockWrite = true; 4804 4805 /* Re-check state, as the lock wasn't held and another image 4806 * creation call could have been done by another thread. */ 4807 AssertMsgStmt(!pDisk->pCache, 4808 ("Create cache image cannot be done with another cache open\n"), 4809 rc = VERR_VD_CACHE_ALREADY_EXISTS); 4810 } 4811 4812 if (RT_SUCCESS(rc)) 4813 { 4814 RTUUID UuidModification; 4815 4816 /* Set same modification Uuid as the last image. */ 4817 rc = pDisk->pLast->Backend->pfnGetModificationUuid(pDisk->pLast->pvBackendData, 4818 &UuidModification); 4819 if (RT_SUCCESS(rc)) 4820 { 4821 rc = pCache->Backend->pfnSetModificationUuid(pCache->pvBackendData, 4822 &UuidModification); 4823 } 4824 4825 if (rc == VERR_NOT_SUPPORTED) 4826 rc = VINF_SUCCESS; 4827 } 4828 4829 if (RT_SUCCESS(rc)) 4830 { 4831 /* Cache successfully created. */ 4832 pDisk->pCache = pCache; 4833 } 4834 else 4835 { 4836 /* Error detected, but image opened. Close and delete image. */ 4837 rc2 = pCache->Backend->pfnClose(pCache->pvBackendData, true); 4838 AssertRC(rc2); 4839 pCache->pvBackendData = NULL; 4840 } 4841 } while (0); 4842 4843 if (RT_UNLIKELY(fLockWrite)) 4844 { 4845 rc2 = vdThreadFinishWrite(pDisk); 4846 AssertRC(rc2); 4847 } 4848 else if (RT_UNLIKELY(fLockRead)) 4849 { 4850 rc2 = vdThreadFinishRead(pDisk); 4851 AssertRC(rc2); 4852 } 4853 4854 if (RT_FAILURE(rc)) 4855 { 4856 if (pCache) 4857 { 4858 if (pCache->pszFilename) 4859 RTStrFree(pCache->pszFilename); 4860 RTMemFree(pCache); 4861 } 4862 } 4863 4864 if (RT_SUCCESS(rc) && pCbProgress && pCbProgress->pfnProgress) 4865 pCbProgress->pfnProgress(pIfProgress->pvUser, 100); 4866 4867 LogFlowFunc(("returns %Rrc\n", rc)); 4868 return rc; 4869 } 4870 4871 /** 4070 4872 * Merges two images (not necessarily with direct parent/child relationship). 4071 4873 * As a side effect the source image and potentially the other images which … … 4183 4985 if (RT_FAILURE(rc)) 4184 4986 break; 4987 /* Updating the cache is required because this might be a live merge. */ 4185 4988 rc = vdWriteHelper(pDisk, pImageTo, pImageFrom->pPrev, 4186 uOffset, pvBuf, 4187 cbThisRead);4989 uOffset, pvBuf, cbThisRead, 4990 true /* fUpdateCache */); 4188 4991 if (RT_FAILURE(rc)) 4189 4992 break; … … 4273 5076 break; 4274 5077 rc = vdWriteHelper(pDisk, pImageTo, NULL, uOffset, pvBuf, 4275 cbThisRead );5078 cbThisRead, true /* fUpdateCache */); 4276 5079 if (RT_FAILURE(rc)) 4277 5080 break; … … 4670 5473 fLockReadFrom = true; 4671 5474 5475 /* 5476 * Updating the cache doesn't make any sense 5477 * as we are looping once through the image. 5478 */ 4672 5479 rc = vdReadHelper(pDiskFrom, pImageFrom, NULL, uOffset, pvBuf, 4673 cbThisRead, fRegularRead); 5480 cbThisRead, fRegularRead, 5481 false /* fUpdateCache */); 4674 5482 if (RT_FAILURE(rc) && rc != VERR_VD_BLOCK_FREE) 4675 5483 break; … … 4686 5494 4687 5495 rc = vdWriteHelper(pDiskTo, pImageTo, NULL, uOffset, pvBuf, 4688 cbThisRead );5496 cbThisRead, false /* fUpdateCache */); 4689 5497 if (RT_FAILURE(rc)) 4690 5498 break; … … 5148 5956 5149 5957 /** 5958 * Closes the currently opened cache image file in HDD container. 5959 * 5960 * @return VBox status code. 5961 * @return VERR_VD_NOT_OPENED if no cache is opened in HDD container. 5962 * @param pDisk Pointer to HDD container. 5963 * @param fDelete If true, delete the image from the host disk. 5964 */ 5965 VBOXDDU_DECL(int) VDCacheClose(PVBOXHDD pDisk, bool fDelete) 5966 { 5967 int rc = VINF_SUCCESS; 5968 int rc2; 5969 bool fLockWrite = false; 5970 PVDCACHE pCache = NULL; 5971 5972 LogFlowFunc(("pDisk=%#p fDelete=%d\n", pDisk, fDelete)); 5973 5974 do 5975 { 5976 /* sanity check */ 5977 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 5978 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 5979 5980 rc2 = vdThreadStartWrite(pDisk); 5981 AssertRC(rc2); 5982 fLockWrite = true; 5983 5984 AssertPtrBreakStmt(pDisk->pCache, rc = VERR_VD_CACHE_NOT_FOUND); 5985 5986 pCache = pDisk->pCache; 5987 pDisk->pCache = NULL; 5988 5989 pCache->Backend->pfnClose(pCache->pvBackendData, fDelete); 5990 if (pCache->pszFilename) 5991 RTStrFree(pCache->pszFilename); 5992 RTMemFree(pCache); 5993 } while (0); 5994 5995 if (RT_LIKELY(fLockWrite)) 5996 { 5997 rc2 = vdThreadFinishWrite(pDisk); 5998 AssertRC(rc2); 5999 } 6000 6001 LogFlowFunc(("returns %Rrc\n", rc)); 6002 return rc; 6003 } 6004 6005 /** 5150 6006 * Closes all opened image files in HDD container. 5151 6007 * … … 5170 6026 AssertRC(rc2); 5171 6027 fLockWrite = true; 6028 6029 PVDCACHE pCache = pDisk->pCache; 6030 if (pCache) 6031 { 6032 rc2 = pCache->Backend->pfnClose(pCache->pvBackendData, false); 6033 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 6034 rc = rc2; 6035 6036 if (pCache->pszFilename) 6037 RTStrFree(pCache->pszFilename); 6038 RTMemFree(pCache); 6039 } 5172 6040 5173 6041 PVDIMAGE pImage = pDisk->pLast; … … 5244 6112 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 5245 6113 5246 rc = vdReadHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbRead, true); 6114 rc = vdReadHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbRead, 6115 true /* fZeroFreeBlocks */, 6116 true /* fUpdateCache */); 5247 6117 } while (0); 5248 6118 … … 5304 6174 5305 6175 vdSetModifiedFlag(pDisk); 5306 rc = vdWriteHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite); 6176 rc = vdWriteHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite, 6177 true /* fUpdateCache */); 5307 6178 } while (0); 5308 6179 … … 5346 6217 vdResetModifiedFlag(pDisk); 5347 6218 rc = pImage->Backend->pfnFlush(pImage->pvBackendData); 6219 6220 if ( RT_SUCCESS(rc) 6221 && pDisk->pCache) 6222 rc = pDisk->pCache->Backend->pfnFlush(pDisk->pCache->pvBackendData); 5348 6223 } while (0); 5349 6224 … … 6888 7763 } 6889 7764 6890 #if 06891 /** @copydoc VBOXHDDBACKEND::pfnComposeLocation */6892 int genericFileComposeLocation(PVDINTERFACE pConfig, char **pszLocation)6893 {6894 return NULL;6895 }6896 6897 6898 /** @copydoc VBOXHDDBACKEND::pfnComposeName */6899 int genericFileComposeName(PVDINTERFACE pConfig, char **pszName)6900 {6901 return NULL;6902 }6903 #endif
Note:
See TracChangeset
for help on using the changeset viewer.