VirtualBox

Changeset 32370 in vbox


Ignore:
Timestamp:
Sep 9, 2010 9:39:15 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
65720
Message:

VD: Beginnings of the L2 disk cache

Location:
trunk
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/VBoxHDD-Plugin.h

    r31776 r32370  
    2424 */
    2525
    26 #ifndef __VBoxHDD_Internal_h__
    27 
     26#ifndef __VBoxHDD_Plugin_h__
     27#define __VBoxHDD_Plugin_h__
    2828
    2929#include <VBox/pdm.h>
  • trunk/include/VBox/VBoxHDD.h

    r32277 r32370  
    19121912
    19131913/**
     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 */
     1923VBOXDDU_DECL(int) VDCacheOpen(PVBOXHDD pDisk, const char *pszBackend,
     1924                              const char *pszFilename, unsigned uOpenFlags,
     1925                              PVDINTERFACE pVDIfsCache);
     1926
     1927/**
    19141928 * Creates and opens a new base image file.
    19151929 *
     
    19591973                               PVDINTERFACE pVDIfsImage,
    19601974                               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 */
     1990VBOXDDU_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);
    19611995
    19621996/**
     
    20442078
    20452079/**
    2046  * Resizes the the given disk image to the given size.
     2080 * Resizes the given disk image to the given size.
    20472081 *
    20482082 * @return  VBox status
     
    20732107 */
    20742108VBOXDDU_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 */
     2118VBOXDDU_DECL(int) VDCacheClose(PVBOXHDD pDisk, bool fDelete);
    20752119
    20762120/**
  • trunk/include/VBox/err.h

    r31491 r32370  
    12551255/** Halt the current I/O context until further notification from the backend. */
    12561256#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)
    12571263/** @} */
    12581264
  • trunk/src/VBox/Devices/Makefile.kmk

    r32342 r32370  
    8686        Storage/RawHDDCore.cpp \
    8787        Storage/ParallelsHDDCore.cpp \
     88        Storage/VCICacheCore.cpp \
    8889        Storage/VSCSI/VSCSIDevice.cpp \
    8990        Storage/VSCSI/VSCSILun.cpp \
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r32021 r32370  
    4242
    4343#include <VBox/VBoxHDD-Plugin.h>
    44 
     44#include <VBox/VBoxHDD-CachePlugin.h>
    4545
    4646#define VBOXHDDDISK_SIGNATURE 0x6f0e2a7d
     
    103103
    104104/**
     105 * VBox HDD Cache image descriptor.
     106 */
     107typedef 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/**
    105130 * VBox HDD Container main structure, private part.
    106131 */
     
    170195    /** List of waiting requests. - Protected by the critical section. */
    171196    RTLISTNODE          ListWriteGrowing;
     197
     198    /** Pointer to the L2 disk cache if any. */
     199    PVDCACHE            pCache;
    172200};
    173201
     
    419447
    420448/**
     449 * Supported backends for the disk cache.
     450 */
     451extern VDCACHEBACKEND g_VciCacheBackend;
     452
     453static unsigned g_cCacheBackends = 0;
     454static PVDCACHEBACKEND *g_apCacheBackends = NULL;
     455static PVDCACHEBACKEND aStaticCacheBackends[] =
     456{
     457    &g_VciCacheBackend
     458};
     459
     460/**
    421461 * internal: add several backends.
    422462 */
     
    442482
    443483/**
     484 * internal: add several cache backends.
     485 */
     486static 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 */
     501DECLINLINE(int) vdAddCacheBackend(PVDCACHEBACKEND pBackend)
     502{
     503    return vdAddCacheBackends(&pBackend, 1);
     504}
     505
     506/**
    444507 * internal: issue error message.
    445508 */
     
    523586
    524587/**
     588 * internal: find cache format backend.
     589 */
     590static 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/**
    525611 * internal: add image structure to the end of images list.
    526612 */
     
    587673
    588674/**
     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 */
     692static 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 */
     720static 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 **/
     758static 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/**
    589795 * internal: read the specified amount of data in whatever blocks the backend
    590796 * will give us.
    591797 */
    592798static 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;
    596803    size_t cbThisRead;
    597804    bool fAllFree = true;
     
    606813        cbThisRead = cbRead;
    607814
    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)
    621822            {
    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                }
    625858            }
    626859        }
     
    631864            /* Fill the free space with 0 if we are told to do so
    632865             * or a previous read returned valid data. */
    633             if (fHandleFreeBlocks || !fAllFree)
     866            if (fZeroFreeBlocks || !fAllFree)
    634867                memset(pvBuf, '\0', cbThisRead);
    635868            else
     
    641874        {
    642875            /* First not free block, fill the space before with 0. */
    643             if (!fHandleFreeBlocks)
     876            if (!fZeroFreeBlocks)
    644877            {
    645878                memset((char *)pvBuf - cbBufClear, '\0', cbBufClear);
     
    654887    } while (cbRead != 0 && RT_SUCCESS(rc));
    655888
    656     return (!fHandleFreeBlocks && fAllFree) ? VERR_VD_BLOCK_FREE : rc;
     889    return (!fZeroFreeBlocks && fAllFree) ? VERR_VD_BLOCK_FREE : rc;
    657890}
    658891
     
    10191252    PVDPARENTSTATEDESC pParentState = (PVDPARENTSTATEDESC)pvUser;
    10201253    return vdReadHelper(pParentState->pDisk, pParentState->pImage, NULL, uOffset,
    1021                         pvBuf, cbRead, true);
     1254                        pvBuf, cbRead, true /* fZeroFreeBlocks */,
     1255                        false /* fUpdateCache */);
    10221256}
    10231257
     
    10371271            pDisk->pLast->Backend->pfnSetModificationUuid(pDisk->pLast->pvBackendData,
    10381272                                                          &Uuid);
     1273
     1274            if (pDisk->pCache)
     1275                pDisk->pCache->Backend->pfnSetModificationUuid(pDisk->pCache->pvBackendData,
     1276                                                               &Uuid);
    10391277        }
    10401278
     
    10561294        vdResetModifiedFlag(pDisk);
    10571295
    1058         if (!(pDisk->uModified | VD_IMAGE_MODIFIED_DISABLE_UUID_UPDATE))
     1296        if (!(pDisk->uModified & VD_IMAGE_MODIFIED_DISABLE_UUID_UPDATE))
    10591297            pDisk->pLast->Backend->pfnFlush(pDisk->pLast->pvBackendData);
    10601298    }
     
    10791317    if (cbPreRead)
    10801318    {
     1319        /*
     1320         * Updating the cache doesn't make sense here because
     1321         * this will be done after the complete block was written.
     1322         */
    10811323        rc = vdReadHelper(pDisk, pImage, pImageParentOverride,
    1082                           uOffset - cbPreRead, pvTmp, cbPreRead, true);
     1324                          uOffset - cbPreRead, pvTmp, cbPreRead,
     1325                          true /* fZeroFreeBlocks*/,
     1326                          false /* fUpdateCache */);
    10831327        if (RT_FAILURE(rc))
    10841328            return rc;
     
    11171361                              uOffset + cbThisWrite + cbWriteCopy,
    11181362                              (char *)pvTmp + cbPreRead + cbThisWrite + cbWriteCopy,
    1119                               cbReadImage, true);
     1363                              cbReadImage, true /* fZeroFreeBlocks */,
     1364                              false /* fUpdateCache */);
    11201365        if (RT_FAILURE(rc))
    11211366            return rc;
     
    11771422     * be modified by the write or not. */
    11781423    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 */);
    11801427    if (RT_FAILURE(rc))
    11811428        return rc;
     
    12241471 */
    12251472static 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)
    12271475{
    12281476    int rc;
     
    12301478    size_t cbThisWrite;
    12311479    size_t cbPreRead, cbPostRead;
     1480    uint64_t uOffsetCur = uOffset;
     1481    size_t cbWriteCur = cbWrite;
     1482    const void *pcvBufCur = pvBuf;
    12321483
    12331484    /* Loop until all written. */
     
    12401491         * to avoid unnecessarily allocating unchanged blocks. This prevents
    12411492         * unwanted expanding of images. VMDK is an example. */
    1242         cbThisWrite = cbWrite;
     1493        cbThisWrite = cbWriteCur;
    12431494        fWrite =   (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME)
    12441495                 ? 0 : VD_WRITE_NO_ALLOC;
    1245         rc = pImage->Backend->pfnWrite(pImage->pvBackendData, uOffset, pvBuf,
     1496        rc = pImage->Backend->pfnWrite(pImage->pvBackendData, uOffsetCur, pcvBufCur,
    12461497                                       cbThisWrite, &cbThisWrite, &cbPreRead,
    12471498                                       &cbPostRead, fWrite);
     
    12561507                 * block if the data is in fact not changed. */
    12571508                rc = vdWriteHelperOptimized(pDisk, pImage, pImageParentOverride,
    1258                                             uOffset, cbWrite,
     1509                                            uOffsetCur, cbWriteCur,
    12591510                                            cbThisWrite, cbPreRead, cbPostRead,
    1260                                             pvBuf, pvTmp);
     1511                                            pcvBufCur, pvTmp);
    12611512            }
    12621513            else
     
    12671518                 * block to be allocated. */
    12681519                rc = vdWriteHelperStandard(pDisk, pImage, pImageParentOverride,
    1269                                            uOffset, cbWrite,
     1520                                           uOffsetCur, cbWriteCur,
    12701521                                           cbThisWrite, cbPreRead, cbPostRead,
    1271                                            pvBuf, pvTmp);
     1522                                           pcvBufCur, pvTmp);
    12721523            }
    12731524            RTMemTmpFree(pvTmp);
     
    12761527        }
    12771528
    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);
    12821539
    12831540    return rc;
     
    17311988    /* To get all entries with VBoxHDD as prefix. */
    17321989    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);
    17351991    if (RT_FAILURE(rc))
    17361992    {
     
    18092065                    pBackend->hPlugin = hPlugin;
    18102066                    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    }
     2079out:
     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 */
     2096static 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);
    18112188                }
    18122189                else
     
    25222899#ifdef RT_STRICT
    25232900        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),
    25252902                  ("Overlapping meta transfers!\n"));
    25262903#endif
     
    29503327    int rc = vdAddBackends(aStaticBackends, RT_ELEMENTS(aStaticBackends));
    29513328    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    }
    29533338    LogRel(("VDInit finished\n"));
    29543339    return rc;
     
    29633348{
    29643349    PVBOXHDDBACKEND *pBackends = g_apBackends;
     3350    PVDCACHEBACKEND *pCacheBackends = g_apCacheBackends;
    29653351    unsigned cBackends = g_cBackends;
    29663352
     
    29773363#endif
    29783364
     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);
    29793378    RTMemFree(pBackends);
    29803379    return VINF_SUCCESS;
     
    33153714    }
    33163715
     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
    33173743    LogFlowFunc(("returns %Rrc *ppszFormat=\"%s\"\n", rc, *ppszFormat));
    33183744    return rc;
     
    35593985                RTStrFree(pImage->pszFilename);
    35603986            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 */
     4004VBOXDDU_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);
    35614157        }
    35624158    }
     
    38564452    RTUUID uuid;
    38574453
    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));
    38614456
    38624457    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     
    40684663
    40694664/**
     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 */
     4678VBOXDDU_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/**
    40704872 * Merges two images (not necessarily with direct parent/child relationship).
    40714873 * As a side effect the source image and potentially the other images which
     
    41834985                        if (RT_FAILURE(rc))
    41844986                            break;
     4987                        /* Updating the cache is required because this might be a live merge. */
    41854988                        rc = vdWriteHelper(pDisk, pImageTo, pImageFrom->pPrev,
    4186                                            uOffset, pvBuf,
    4187                                            cbThisRead);
     4989                                           uOffset, pvBuf, cbThisRead,
     4990                                           true /* fUpdateCache */);
    41884991                        if (RT_FAILURE(rc))
    41894992                            break;
     
    42735076                        break;
    42745077                    rc = vdWriteHelper(pDisk, pImageTo, NULL, uOffset, pvBuf,
    4275                                        cbThisRead);
     5078                                       cbThisRead, true /* fUpdateCache */);
    42765079                    if (RT_FAILURE(rc))
    42775080                        break;
     
    46705473            fLockReadFrom = true;
    46715474
     5475            /*
     5476             * Updating the cache doesn't make any sense
     5477             * as we are looping once through the image.
     5478             */
    46725479            rc = vdReadHelper(pDiskFrom, pImageFrom, NULL, uOffset, pvBuf,
    4673                               cbThisRead, fRegularRead);
     5480                              cbThisRead, fRegularRead,
     5481                              false /* fUpdateCache */);
    46745482            if (RT_FAILURE(rc) && rc != VERR_VD_BLOCK_FREE)
    46755483                break;
     
    46865494
    46875495                rc = vdWriteHelper(pDiskTo, pImageTo, NULL, uOffset, pvBuf,
    4688                                    cbThisRead);
     5496                                   cbThisRead, false /* fUpdateCache */);
    46895497                if (RT_FAILURE(rc))
    46905498                    break;
     
    51485956
    51495957/**
     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 */
     5965VBOXDDU_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/**
    51506006 * Closes all opened image files in HDD container.
    51516007 *
     
    51706026        AssertRC(rc2);
    51716027        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        }
    51726040
    51736041        PVDIMAGE pImage = pDisk->pLast;
     
    52446112        AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
    52456113
    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 */);
    52476117    } while (0);
    52486118
     
    53046174
    53056175        vdSetModifiedFlag(pDisk);
    5306         rc = vdWriteHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite);
     6176        rc = vdWriteHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite,
     6177                           true /* fUpdateCache */);
    53076178    } while (0);
    53086179
     
    53466217        vdResetModifiedFlag(pDisk);
    53476218        rc = pImage->Backend->pfnFlush(pImage->pvBackendData);
     6219
     6220        if (   RT_SUCCESS(rc)
     6221            && pDisk->pCache)
     6222            rc = pDisk->pCache->Backend->pfnFlush(pDisk->pCache->pvBackendData);
    53486223    } while (0);
    53496224
     
    68887763}
    68897764
    6890 #if 0
    6891 /** @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.

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