VirtualBox

Changeset 54340 in vbox


Ignore:
Timestamp:
Feb 20, 2015 6:51:07 PM (10 years ago)
Author:
vboxsync
Message:

Storage/VD: Allow different filter chains for reads and writes (required by disk image encryption to encrypt images afterwards)

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vd.h

    r52830 r54340  
    242242/** @}*/
    243243
     244/** @name VBox HDD container filter flags
     245 * @{
     246 */
     247/** The filter is applied during writes. */
     248#define VD_FILTER_FLAGS_WRITE RT_BIT(0)
     249/** The filter is applied during reads. */
     250#define VD_FILTER_FLAGS_READ  RT_BIT(1)
     251/** Default set of filter flags. */
     252#define VD_FILTER_FLAGS_DEFAULT (VD_FILTER_FLAGS_WRITE | VD_FILTER_FLAGS_READ)
     253/** Mask of valid flags. */
     254#define VD_FILTER_FLAGS_MASK    (VD_FILTER_FLAGS_WRITE | VD_FILTER_FLAGS_READ)
     255/** @} */
     256
    244257/**
    245258 * Helper functions to handle open flags.
     
    641654 * @param   pDisk           Pointer to the HDD container which should use the filter.
    642655 * @param   pszFilter       Name of the filter backend to use (case insensitive).
     656 * @param   fFlags          Flags which apply to the filter, combination of VD_FILTER_FLAGS_*
     657 *                          defines.
    643658 * @param   pVDIfsFilter    Pointer to the per-filter VD interface list.
    644659 */
    645 VBOXDDU_DECL(int) VDFilterAdd(PVBOXHDD pDisk, const char *pszFilter,
     660VBOXDDU_DECL(int) VDFilterAdd(PVBOXHDD pDisk, const char *pszFilter, uint32_t fFlags,
    646661                              PVDINTERFACE pVDIfsFilter);
    647662
     
    907922
    908923/**
    909  * Removes the last added filter in the HDD container.
     924 * Removes the last added filter in the HDD container from the specified chain.
    910925 *
    911926 * @return  VBox status code.
    912927 * @retval  VERR_VD_NOT_OPENED if no filter is present for the disk.
    913928 * @param   pDisk           Pointer to HDD container.
    914  */
    915 VBOXDDU_DECL(int) VDFilterRemove(PVBOXHDD pDisk);
     929 * @param   fFlags          Combination of VD_FILTER_FLAGS_* defines.
     930 */
     931VBOXDDU_DECL(int) VDFilterRemove(PVBOXHDD pDisk, uint32_t fFlags);
    916932
    917933/**
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r53539 r54340  
    17671767        {
    17681768            /* Unload the crypto filter first to make sure it doesn't access the keys anymore. */
    1769             rc = VDFilterRemove(pThis->pDisk);
     1769            rc = VDFilterRemove(pThis->pDisk, VD_FILTER_FLAGS_DEFAULT);
    17701770            AssertRC(rc);
    17711771
     
    17871787
    17881788            /* Load the crypt filter plugin. */
    1789             rc = VDFilterAdd(pThis->pDisk, "CRYPT", pVDIfFilter);
     1789            rc = VDFilterAdd(pThis->pDisk, "CRYPT", VD_FILTER_FLAGS_DEFAULT, pVDIfFilter);
    17901790            if (RT_FAILURE(rc))
    17911791                pThis->pIfSecKey = NULL;
     
    22352235            AssertRC(rc);
    22362236
    2237             rc = VDFilterAdd(pThis->pDisk, pszFilterName, pVDIfsFilter);
     2237            rc = VDFilterAdd(pThis->pDisk, pszFilterName, VD_FILTER_FLAGS_DEFAULT, pVDIfsFilter);
    22382238
    22392239            MMR3HeapFree(pszFilterName);
  • trunk/src/VBox/Storage/VD.cpp

    r54117 r54340  
    198198typedef struct VDFILTER
    199199{
    200     /** Pointer to the previous filter. */
    201     struct VDFILTER   *pPrev;
    202     /** Pointer to the next filter. */
    203     struct VDFILTER   *pNext;
     200    /** List node for the read filter chain. */
     201    RTLISTNODE         ListNodeChainRead;
     202    /** List node for the write filter chain. */
     203    RTLISTNODE         ListNodeChainWrite;
     204    /** Number of references to this filter. */
     205    uint32_t           cRefs;
    204206    /** Opaque VD filter backend instance data. */
    205207    void              *pvBackendData;
     
    290292    PVDDISCARDSTATE        pDiscard;
    291293
    292     /** Pointer to the first filter in the chain. */
    293     PVDFILTER              pFilterHead;
    294     /** Pointer to the last filter in the chain. */
    295     PVDFILTER              pFilterTail;
     294    /** Read filter chain - PVDFILTER. */
     295    RTLISTANCHOR           ListFilterChainRead;
     296    /** Write filter chain - PVDFILTER. */
     297    RTLISTANCHOR           ListFilterChainWrite;
    296298};
    297299
     
    938940
    939941/**
    940  * internal: add filter structure to the end of filter list.
    941  */
    942 static void vdAddFilterToList(PVBOXHDD pDisk, PVDFILTER pFilter)
    943 {
    944     pFilter->pPrev = NULL;
    945     pFilter->pNext = NULL;
    946 
    947     if (pDisk->pFilterHead)
    948     {
    949         pFilter->pPrev = pDisk->pFilterTail;
    950         pDisk->pFilterTail->pNext = pFilter;
    951         pDisk->pFilterTail = pFilter;
    952     }
    953     else
    954     {
    955         pDisk->pFilterHead = pFilter;
    956         pDisk->pFilterTail = pFilter;
    957     }
    958 }
    959 
    960 /**
    961  * internal: Remove last filter structure from the filter list.
    962  */
    963 static void vdRemoveFilterFromList(PVBOXHDD pDisk, PVDFILTER pFilter)
    964 {
    965     Assert(pDisk->pFilterHead != NULL && pDisk->pFilterTail != NULL);
    966 
    967     if (pFilter->pPrev)
    968         pFilter->pPrev->pNext = pFilter->pNext;
    969     else
    970         pDisk->pFilterHead = pFilter->pNext;
    971 
    972     if (pFilter->pNext)
    973         pFilter->pNext->pPrev = pFilter->pPrev;
    974     else
    975         pDisk->pFilterTail = pFilter->pPrev;
    976 
    977     pFilter->pPrev = NULL;
    978     pFilter->pNext = NULL;
     942 * Release a referene to the filter decrementing the counter and destroying the filter
     943 * when the counter reaches zero.
     944 *
     945 * @returns The new reference count.
     946 * @param   pFilter    The filter to release.
     947 */
     948static uint32_t vdFilterRelease(PVDFILTER pFilter)
     949{
     950    uint32_t cRefs = ASMAtomicDecU32(&pFilter->cRefs);
     951    if (!cRefs)
     952    {
     953        pFilter->pBackend->pfnDestroy(pFilter->pvBackendData);
     954        RTMemFree(pFilter);
     955    }
     956
     957    return cRefs;
     958}
     959
     960/**
     961 * Increments the reference counter of the given filter.
     962 *
     963 * @return The new reference count.
     964 * @param  pFilter    The filter.
     965 */
     966static uint32_t vdFilterRetain(PVDFILTER pFilter)
     967{
     968    return ASMAtomicIncU32(&pFilter->cRefs);
    979969}
    980970
     
    10111001    VD_IS_LOCKED(pDisk);
    10121002
    1013     if (pDisk->pFilterHead)
    1014     {
    1015         PVDFILTER pFilterCurr = pDisk->pFilterHead;
    1016 
    1017         do
    1018         {
    1019             rc = pFilterCurr->pBackend->pfnFilterWrite(pFilterCurr->pvBackendData, uOffset, cbWrite, pIoCtx);
    1020             /* Reset S/G buffer for the next filter. */
    1021             RTSgBufReset(&pIoCtx->Req.Io.SgBuf);
    1022 
    1023             pFilterCurr = pFilterCurr->pNext;
    1024         } while (   RT_SUCCESS(rc)
    1025                  && pFilterCurr);
     1003    PVDFILTER pFilter;
     1004    RTListForEach(&pDisk->ListFilterChainWrite, pFilter, VDFILTER, ListNodeChainWrite)
     1005    {
     1006        rc = pFilter->pBackend->pfnFilterWrite(pFilter->pvBackendData, uOffset, cbWrite, pIoCtx);
     1007        if (RT_FAILURE(rc))
     1008            break;
     1009        /* Reset S/G buffer for the next filter. */
     1010        RTSgBufReset(&pIoCtx->Req.Io.SgBuf);
    10261011    }
    10271012
     
    10451030    VD_IS_LOCKED(pDisk);
    10461031
    1047     if (pDisk->pFilterHead)
    1048     {
    1049         PVDFILTER pFilterCurr = pDisk->pFilterHead;
    1050 
    1051         /* Reset buffer before starting. */
     1032    /* Reset buffer before starting. */
     1033    RTSgBufReset(&pIoCtx->Req.Io.SgBuf);
     1034
     1035    PVDFILTER pFilter;
     1036    RTListForEach(&pDisk->ListFilterChainRead, pFilter, VDFILTER, ListNodeChainRead)
     1037    {
     1038        rc = pFilter->pBackend->pfnFilterRead(pFilter->pvBackendData, uOffset, cbRead, pIoCtx);
     1039        if (RT_FAILURE(rc))
     1040            break;
     1041        /* Reset S/G buffer for the next filter. */
    10521042        RTSgBufReset(&pIoCtx->Req.Io.SgBuf);
    1053 
    1054         do
    1055         {
    1056             rc = pFilterCurr->pBackend->pfnFilterRead(pFilterCurr->pvBackendData, uOffset, cbRead, pIoCtx);
    1057             /* Reset S/G buffer for the next filter. */
    1058             RTSgBufReset(&pIoCtx->Req.Io.SgBuf);
    1059 
    1060             pFilterCurr = pFilterCurr->pNext;
    1061         } while (   RT_SUCCESS(rc)
    1062                  && pFilterCurr);
    10631043    }
    10641044
     
    23972377    bool fLockReadFrom = false;
    23982378    bool fLockWriteTo = false;
    2399     bool fBlockwiseCopy = fSuppressRedundantIo || (cImagesFromRead > 0);
     2379    bool fBlockwiseCopy = false;
    24002380    unsigned uProgressOld = 0;
    24012381
    24022382    LogFlowFunc(("pDiskFrom=%#p pImageFrom=%#p pDiskTo=%#p cbSize=%llu cImagesFromRead=%u cImagesToRead=%u fSuppressRedundantIo=%RTbool pIfProgress=%#p pDstIfProgress=%#p\n",
    24032383                 pDiskFrom, pImageFrom, pDiskTo, cbSize, cImagesFromRead, cImagesToRead, fSuppressRedundantIo, pDstIfProgress, pDstIfProgress));
     2384
     2385    if (   (fSuppressRedundantIo || (cImagesFromRead > 0))
     2386        && RTListIsEmpty(&pDiskFrom->ListFilterChainRead))
     2387        fBlockwiseCopy = true;
    24042388
    24052389    /* Allocate tmp buffer. */
     
    60115995            pDisk->hMemCacheIoCtx          = NIL_RTMEMCACHE;
    60125996            pDisk->hMemCacheIoTask         = NIL_RTMEMCACHE;
    6013             pDisk->pFilterHead             = NULL;
    6014             pDisk->pFilterTail             = NULL;
     5997            RTListInit(&pDisk->ListFilterChainWrite);
     5998            RTListInit(&pDisk->ListFilterChainRead);
    60155999
    60166000            /* Create the I/O ctx cache */
     
    67406724}
    67416725
    6742 /**
    6743  * Adds a filter to the disk.
    6744  *
    6745  * @returns VBox status code.
    6746  * @param   pDisk           Pointer to the HDD container which should use the filter.
    6747  * @param   pszFilter       Name of the filter backend to use (case insensitive).
    6748  * @param   pVDIfsFilter    Pointer to the per-filter VD interface list.
    6749  */
    6750 VBOXDDU_DECL(int) VDFilterAdd(PVBOXHDD pDisk, const char *pszFilter,
     6726VBOXDDU_DECL(int) VDFilterAdd(PVBOXHDD pDisk, const char *pszFilter, uint32_t fFlags,
    67516727                              PVDINTERFACE pVDIfsFilter)
    67526728{
     
    67686744        AssertMsgBreakStmt(VALID_PTR(pszFilter) && *pszFilter,
    67696745                           ("pszFilter=%#p \"%s\"\n", pszFilter, pszFilter),
     6746                           rc = VERR_INVALID_PARAMETER);
     6747
     6748        AssertMsgBreakStmt(!(fFlags & ~VD_FILTER_FLAGS_MASK),
     6749                           ("Invalid flags set (fFlags=%#x)\n", fFlags),
    67706750                           rc = VERR_INVALID_PARAMETER);
    67716751
     
    68146794        fLockWrite = true;
    68156795
    6816         /* Add filter to chain. */
    6817         vdAddFilterToList(pDisk, pFilter);
     6796        /* Add filter to chains. */
     6797        if (fFlags & VD_FILTER_FLAGS_WRITE)
     6798        {
     6799            RTListAppend(&pDisk->ListFilterChainWrite, &pFilter->ListNodeChainWrite);
     6800            vdFilterRetain(pFilter);
     6801        }
     6802
     6803        if (fFlags & VD_FILTER_FLAGS_READ)
     6804        {
     6805            RTListAppend(&pDisk->ListFilterChainRead, &pFilter->ListNodeChainRead);
     6806            vdFilterRetain(pFilter);
     6807        }
    68186808    } while (0);
    68196809
     
    88208810}
    88218811
    8822 /**
    8823  * Removes the last added filter in the HDD container.
    8824  *
    8825  * @return  VBox status code.
    8826  * @retval  VERR_VD_NOT_OPENED if no filter is present for the disk.
    8827  * @param   pDisk           Pointer to HDD container.
    8828  */
    8829 VBOXDDU_DECL(int) VDFilterRemove(PVBOXHDD pDisk)
     8812VBOXDDU_DECL(int) VDFilterRemove(PVBOXHDD pDisk, uint32_t fFlags)
    88308813{
    88318814    int rc = VINF_SUCCESS;
     
    88428825        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    88438826
     8827        AssertMsgBreakStmt(!(fFlags & VD_FILTER_FLAGS_MASK),
     8828                           ("Invalid flags set (fFlags=%#x)\n", fFlags),
     8829                           rc = VERR_INVALID_PARAMETER);
     8830
    88448831        rc2 = vdThreadStartWrite(pDisk);
    88458832        AssertRC(rc2);
    88468833        fLockWrite = true;
    88478834
    8848         AssertPtrBreakStmt(pDisk->pFilterHead, rc = VERR_VD_NOT_OPENED);
    8849 
    8850         pFilter = pDisk->pFilterTail;
    8851         vdRemoveFilterFromList(pDisk, pFilter);
    8852 
    8853         pFilter->pBackend->pfnDestroy(pFilter->pvBackendData);
    8854         RTMemFree(pFilter);
     8835        if (fFlags & VD_FILTER_FLAGS_WRITE)
     8836        {
     8837            AssertBreakStmt(!RTListIsEmpty(&pDisk->ListFilterChainWrite), rc = VERR_VD_NOT_OPENED);
     8838            pFilter = RTListGetLast(&pDisk->ListFilterChainWrite, VDFILTER, ListNodeChainWrite);
     8839            AssertPtr(pFilter);
     8840            RTListNodeRemove(&pFilter->ListNodeChainWrite);
     8841            vdFilterRelease(pFilter);
     8842        }
     8843
     8844        if (fFlags & VD_FILTER_FLAGS_READ)
     8845        {
     8846            AssertPtrBreakStmt(!RTListIsEmpty(&pDisk->ListFilterChainRead), rc = VERR_VD_NOT_OPENED);
     8847            pFilter = RTListGetLast(&pDisk->ListFilterChainRead, VDFILTER, ListNodeChainRead);
     8848            AssertPtr(pFilter);
     8849            RTListNodeRemove(&pFilter->ListNodeChainRead);
     8850            vdFilterRelease(pFilter);
     8851        }
    88558852    } while (0);
    88568853
     
    89538950        fLockWrite = true;
    89548951
    8955         PVDFILTER pFilter = pDisk->pFilterTail;
    8956         while (VALID_PTR(pFilter))
    8957         {
    8958             PVDFILTER pPrev = pFilter->pPrev;
    8959             vdRemoveFilterFromList(pDisk, pFilter);
    8960 
    8961             rc2 = pFilter->pBackend->pfnDestroy(pFilter->pvBackendData);
    8962             if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    8963                 rc = rc2;
    8964             /* Free remaining resources related to the image. */
    8965             RTMemFree(pFilter);
    8966             pFilter = pPrev;
    8967         }
    8968         Assert(!VALID_PTR(pDisk->pFilterTail));
     8952        PVDFILTER pFilter, pFilterNext;
     8953        RTListForEachSafe(&pDisk->ListFilterChainWrite, pFilter, pFilterNext, VDFILTER, ListNodeChainWrite)
     8954        {
     8955            RTListNodeRemove(&pFilter->ListNodeChainWrite);
     8956            vdFilterRelease(pFilter);
     8957        }
     8958
     8959        RTListForEachSafe(&pDisk->ListFilterChainRead, pFilter, pFilterNext, VDFILTER, ListNodeChainRead)
     8960        {
     8961            RTListNodeRemove(&pFilter->ListNodeChainRead);
     8962            vdFilterRelease(pFilter);
     8963        }
     8964        Assert(RTListIsEmpty(&pDisk->ListFilterChainRead));
     8965        Assert(RTListIsEmpty(&pDisk->ListFilterChainWrite));
    89698966    } while (0);
    89708967
Note: See TracChangeset for help on using the changeset viewer.

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