Changeset 50991 in vbox for trunk/src/VBox/Storage/VD.cpp
- Timestamp:
- Apr 8, 2014 10:45:31 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VD.cpp
r50988 r50991 194 194 195 195 /** 196 * VD filter instance. 197 */ 198 typedef struct VDFILTER 199 { 200 /** Pointer to the previous filter. */ 201 struct VDFILTER *pPrev; 202 /** Pointer to the next filter. */ 203 struct VDFILTER *pNext; 204 /** Opaque VD filter backend instance data. */ 205 void *pvBackendData; 206 /** Pointer to the filter backend interface. */ 207 PCVDFILTERBACKEND pBackend; 208 } VDFILTER; 209 /** Pointer to a VD filter instance. */ 210 typedef VDFILTER *PVDFILTER; 211 212 /** 196 213 * VBox HDD Container main structure, private part. 197 214 */ … … 262 279 /** Pointer to the discard state if any. */ 263 280 PVDDISCARDSTATE pDiscard; 281 282 /** Pointer to the first filter in the chain. */ 283 PVDFILTER pFilterHead; 284 /** Pointer to the last filter in the chain. */ 285 PVDFILTER pFilterTail; 264 286 }; 265 287 … … 357 379 /** Override for the parent image to start reading from. */ 358 380 PVDIMAGE pImageParentOverride; 381 /** Original offset of the transfer - required for filtering read requests. */ 382 uint64_t uOffsetXferOrig; 383 /** Original size of the transfer - required for fitlering read requests. */ 384 size_t cbXferOrig; 359 385 } Io; 360 386 /** Discard requests. */ … … 598 624 }; 599 625 626 /** Number of supported filter backends. */ 627 static unsigned g_cFilterBackends = 0; 628 /** Array of pointers to the filters backends. */ 629 static PCVDFILTERBACKEND *g_apFilterBackends = NULL; 630 600 631 /** Forward declaration of the async discard helper. */ 601 632 static int vdDiscardHelperAsync(PVDIOCTX pIoCtx); … … 652 683 653 684 /** 685 * Add several filter bakends. 686 * 687 * @returns VBox status code. 688 * @param ppBackends Array of filter backends to add. 689 * @param cBackends Number of backends to add. 690 */ 691 static int vdAddFilterBackends(PCVDFILTERBACKEND *ppBackends, unsigned cBackends) 692 { 693 PCVDFILTERBACKEND *pTmp = (PCVDFILTERBACKEND *)RTMemRealloc(g_apFilterBackends, 694 (g_cFilterBackends + cBackends) * sizeof(PCVDFILTERBACKEND)); 695 if (RT_UNLIKELY(!pTmp)) 696 return VERR_NO_MEMORY; 697 g_apFilterBackends = pTmp; 698 memcpy(&g_apFilterBackends[g_cFilterBackends], ppBackends, cBackends * sizeof(PCVDFILTERBACKEND)); 699 g_cFilterBackends += cBackends; 700 return VINF_SUCCESS; 701 } 702 703 /** 704 * Add a single filter backend to the list of supported filters. 705 * 706 * @returns VBox status code. 707 * @param pBackend The backend to add. 708 */ 709 DECLINLINE(int) vdAddFilterBackend(PCVDFILTERBACKEND pBackend) 710 { 711 return vdAddFilterBackends(&pBackend, 1); 712 } 713 714 /** 654 715 * internal: issue error message. 655 716 */ … … 756 817 757 818 /** 819 * internal: find filter backend. 820 */ 821 static int vdFindFilterBackend(const char *pszFilter, PCVDFILTERBACKEND *ppBackend) 822 { 823 int rc = VINF_SUCCESS; 824 PCVDFILTERBACKEND pBackend = NULL; 825 826 for (unsigned i = 0; i < g_cFilterBackends; i++) 827 { 828 if (!RTStrICmp(pszFilter, g_apFilterBackends[i]->pszBackendName)) 829 { 830 pBackend = g_apFilterBackends[i]; 831 break; 832 } 833 } 834 *ppBackend = pBackend; 835 return rc; 836 } 837 838 839 /** 758 840 * internal: add image structure to the end of images list. 759 841 */ … … 804 886 805 887 /** 888 * internal: add filter structure to the end of filter list. 889 */ 890 static void vdAddFilterToList(PVBOXHDD pDisk, PVDFILTER pFilter) 891 { 892 pFilter->pPrev = NULL; 893 pFilter->pNext = NULL; 894 895 if (pDisk->pFilterHead) 896 { 897 pFilter->pPrev = pDisk->pFilterTail; 898 pDisk->pFilterTail->pNext = pFilter; 899 pDisk->pFilterTail = pFilter; 900 } 901 else 902 { 903 pDisk->pFilterHead = pFilter; 904 pDisk->pFilterTail = pFilter; 905 } 906 } 907 908 /** 909 * internal: Remove last filter structure from the filter list. 910 */ 911 static void vdRemoveFilterFromList(PVBOXHDD pDisk, PVDFILTER pFilter) 912 { 913 Assert(pDisk->pFilterHead != NULL && pDisk->pFilterTail != NULL); 914 915 if (pFilter->pPrev) 916 pFilter->pPrev->pNext = pFilter->pNext; 917 else 918 pDisk->pFilterHead = pFilter->pNext; 919 920 if (pFilter->pNext) 921 pFilter->pNext->pPrev = pFilter->pPrev; 922 else 923 pDisk->pFilterTail = pFilter->pPrev; 924 925 pFilter->pPrev = NULL; 926 pFilter->pNext = NULL; 927 } 928 929 /** 806 930 * internal: find image by index into the images list. 807 931 */ … … 817 941 } 818 942 return pImage; 943 } 944 945 /** 946 * Applies the filter chain to the given write request. 947 * 948 * @returns VBox status code. 949 * @param pDisk The HDD container. 950 * @param uOffset The start offset of the write. 951 * @param cbWrite Number of bytes to write. 952 * @param pIoCtx The I/O context associated with the request. 953 */ 954 static int vdFilterChainApplyWrite(PVBOXHDD pDisk, uint64_t uOffset, size_t cbWrite, 955 PVDIOCTX pIoCtx) 956 { 957 int rc = VINF_SUCCESS; 958 959 if (pDisk->pFilterHead) 960 { 961 PVDFILTER pFilterCurr = pDisk->pFilterHead; 962 963 do 964 { 965 rc = pFilterCurr->pBackend->pfnFilterWrite(pFilterCurr->pvBackendData, uOffset, cbWrite, pIoCtx); 966 /* Reset S/G buffer for the next filter. */ 967 RTSgBufReset(&pIoCtx->Req.Io.SgBuf); 968 969 pFilterCurr = pFilterCurr->pNext; 970 } while ( RT_SUCCESS(rc) 971 && pFilterCurr); 972 } 973 974 return rc; 975 } 976 977 /** 978 * Applies the filter chain to the given read request. 979 * 980 * @returns VBox status code. 981 * @param pDisk The HDD container. 982 * @param uOffset The start offset of the read. 983 * @param cbRead Number of bytes read. 984 * @param pIoCtx The I/O context associated with the request. 985 */ 986 static int vdFilterChainApplyRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 987 PVDIOCTX pIoCtx) 988 { 989 int rc = VINF_SUCCESS; 990 991 if (pDisk->pFilterHead) 992 { 993 PVDFILTER pFilterCurr = pDisk->pFilterHead; 994 995 do 996 { 997 rc = pFilterCurr->pBackend->pfnFilterRead(pFilterCurr->pvBackendData, uOffset, cbRead, pIoCtx); 998 /* Reset S/G buffer for the next filter. */ 999 RTSgBufReset(&pIoCtx->Req.Io.SgBuf); 1000 1001 pFilterCurr = pFilterCurr->pNext; 1002 } while ( RT_SUCCESS(rc) 1003 && pFilterCurr); 1004 } 1005 1006 return rc; 1007 } 1008 1009 DECLINLINE(void) vdIoCtxRootComplete(PVBOXHDD pDisk, PVDIOCTX pIoCtx) 1010 { 1011 if ( RT_SUCCESS(pIoCtx->rcReq) 1012 && pIoCtx->enmTxDir == VDIOCTXTXDIR_READ) 1013 pIoCtx->rcReq = vdFilterChainApplyRead(pDisk, pIoCtx->Req.Io.uOffsetXferOrig, 1014 pIoCtx->Req.Io.cbXferOrig, pIoCtx); 1015 1016 pIoCtx->Type.Root.pfnComplete(pIoCtx->Type.Root.pvUser1, 1017 pIoCtx->Type.Root.pvUser2, 1018 pIoCtx->rcReq); 819 1019 } 820 1020 … … 836 1036 pIoCtx->Req.Io.cbBufClear = 0; 837 1037 pIoCtx->Req.Io.pImageParentOverride = NULL; 1038 pIoCtx->Req.Io.uOffsetXferOrig = uOffset; 1039 pIoCtx->Req.Io.cbXferOrig = cbTransfer; 838 1040 pIoCtx->cDataTransfersPending = 0; 839 1041 pIoCtx->cMetaTransfersPending = 0; … … 1291 1493 DECLINLINE(void) vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask) 1292 1494 { 1293 //#ifdef DEBUG1495 #ifdef DEBUG 1294 1496 memset(pIoTask, 0xff, sizeof(VDIOTASK)); 1295 //#endif1497 #endif 1296 1498 RTMemCacheFree(pDisk->hMemCacheIoTask, pIoTask); 1297 1499 } … … 1537 1739 LogFlowFunc(("Waiting I/O context completed pTmp=%#p\n", pTmp)); 1538 1740 vdThreadFinishWrite(pDisk); 1539 pTmp->Type.Root.pfnComplete(pTmp->Type.Root.pvUser1, 1540 pTmp->Type.Root.pvUser2, 1541 pTmp->rcReq); 1741 vdIoCtxRootComplete(pDisk, pTmp); 1542 1742 vdIoCtxFree(pDisk, pTmp); 1543 1743 } … … 1594 1794 LogFlowFunc(("Waiting I/O context completed pTmp=%#p\n", pTmp)); 1595 1795 vdThreadFinishWrite(pDisk); 1596 pTmp->Type.Root.pfnComplete(pTmp->Type.Root.pvUser1, 1597 pTmp->Type.Root.pvUser2, 1598 pTmp->rcReq); 1796 vdIoCtxRootComplete(pDisk, pTmp); 1599 1797 vdIoCtxFree(pDisk, pTmp); 1600 1798 } … … 1982 2180 IoCtx.Type.Root.pvUser2 = hEventComplete; 1983 2181 rc = vdIoCtxProcessSync(&IoCtx, hEventComplete); 2182 if (RT_SUCCESS(rc)) 2183 rc = vdFilterChainApplyRead(pDisk, uOffset, cbRead, &IoCtx); 1984 2184 1985 2185 RTSemEventDestroy(hEventComplete); … … 2079 2279 IoCtx.Type.Root.pvUser1 = pDisk; 2080 2280 IoCtx.Type.Root.pvUser2 = hEventComplete; 2081 rc = vdIoCtxProcessSync(&IoCtx, hEventComplete); 2281 /* Apply write filter chain here. */ 2282 rc = vdFilterChainApplyWrite(pDisk, uOffset, cbWrite, &IoCtx); 2283 if (RT_SUCCESS(rc)) 2284 rc = vdIoCtxProcessSync(&IoCtx, hEventComplete); 2082 2285 2083 2286 RTSemEventDestroy(hEventComplete); … … 3230 3433 3231 3434 /** 3435 * @copydoc VDPLUGIN::pfnRegisterFilter 3436 */ 3437 static DECLCALLBACK(int) vdPluginRegisterFilter(void *pvUser, PCVDFILTERBACKEND pBackend) 3438 { 3439 int rc = VINF_SUCCESS; 3440 3441 if (pBackend->cbSize == sizeof(VDFILTERBACKEND)) 3442 vdAddFilterBackend(pBackend); 3443 else 3444 { 3445 LogFunc(("ignored plugin: pBackend->cbSize=%d rc=%Rrc\n", pBackend->cbSize)); 3446 rc = VERR_IGNORED; 3447 } 3448 3449 return rc; 3450 } 3451 3452 /** 3232 3453 * Adds a plugin to the list of loaded plugins. 3233 3454 * … … 3332 3553 PFNVDPLUGINLOAD pfnVDPluginLoad = NULL; 3333 3554 3334 BackendRegister.pfnRegisterImage = vdPluginRegisterImage;3335 BackendRegister.pfnRegisterCache = vdPluginRegisterCache;3336 /** @todo: Filter plugins. */3555 BackendRegister.pfnRegisterImage = vdPluginRegisterImage; 3556 BackendRegister.pfnRegisterCache = vdPluginRegisterCache; 3557 BackendRegister.pfnRegisterFilter = vdPluginRegisterFilter; 3337 3558 3338 3559 rc = RTLdrGetSymbol(hPlugin, VD_PLUGIN_LOAD_NAME, (void**)&pfnVDPluginLoad); … … 3580 3801 { 3581 3802 LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p rcReq=%Rrc\n", pIoCtxParent, pIoCtxParent->rcReq)); 3582 pIoCtxParent->Type.Root.pfnComplete(pIoCtxParent->Type.Root.pvUser1, 3583 pIoCtxParent->Type.Root.pvUser2, 3584 pIoCtxParent->rcReq); 3803 vdIoCtxRootComplete(pDisk, pIoCtxParent); 3585 3804 vdThreadFinishWrite(pDisk); 3586 3805 vdIoCtxFree(pDisk, pIoCtxParent); … … 3610 3829 3611 3830 LogFlowFunc(("I/O context completed pIoCtx=%#p rcReq=%Rrc\n", pIoCtx, pIoCtx->rcReq)); 3612 pIoCtx->Type.Root.pfnComplete(pIoCtx->Type.Root.pvUser1, 3613 pIoCtx->Type.Root.pvUser2, 3614 pIoCtx->rcReq); 3831 vdIoCtxRootComplete(pDisk, pIoCtx); 3615 3832 } 3616 3833 … … 5180 5397 pDisk->hMemCacheIoCtx = NIL_RTMEMCACHE; 5181 5398 pDisk->hMemCacheIoTask = NIL_RTMEMCACHE; 5399 pDisk->pFilterHead = NULL; 5400 pDisk->pFilterTail = NULL; 5182 5401 5183 5402 /* Create the I/O ctx cache */ … … 5237 5456 5238 5457 rc = VDCloseAll(pDisk); 5458 int rc2 = VDFilterRemoveAll(pDisk); 5459 if (RT_SUCCESS(rc)) 5460 rc = rc2; 5461 5239 5462 RTMemCacheDestroy(pDisk->hMemCacheIoCtx); 5240 5463 RTMemCacheDestroy(pDisk->hMemCacheIoTask); … … 5897 6120 RTMemFree(pCache); 5898 6121 } 6122 } 6123 6124 LogFlowFunc(("returns %Rrc\n", rc)); 6125 return rc; 6126 } 6127 6128 /** 6129 * Adds a filter to the disk. 6130 * 6131 * @returns VBox status code. 6132 * @param pDisk Pointer to the HDD container which should use the filter. 6133 * @param pszFilter Name of the filter backend to use (case insensitive). 6134 * @param pVDIfsFilter Pointer to the per-filter VD interface list. 6135 */ 6136 VBOXDDU_DECL(int) VDFilterAdd(PVBOXHDD pDisk, const char *pszFilter, 6137 PVDINTERFACE pVDIfsFilter) 6138 { 6139 int rc = VINF_SUCCESS; 6140 int rc2; 6141 bool fLockWrite = false; 6142 PVDFILTER pFilter = NULL; 6143 6144 LogFlowFunc(("pDisk=%#p pszFilter=\"%s\" pVDIfsFilter=%#p\n", 6145 pDisk, pszFilter, pVDIfsFilter)); 6146 6147 do 6148 { 6149 /* sanity check */ 6150 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 6151 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 6152 6153 /* Check arguments. */ 6154 AssertMsgBreakStmt(VALID_PTR(pszFilter) && *pszFilter, 6155 ("pszFilter=%#p \"%s\"\n", pszFilter, pszFilter), 6156 rc = VERR_INVALID_PARAMETER); 6157 6158 /* Set up image descriptor. */ 6159 pFilter = (PVDFILTER)RTMemAllocZ(sizeof(VDFILTER)); 6160 if (!pFilter) 6161 { 6162 rc = VERR_NO_MEMORY; 6163 break; 6164 } 6165 6166 rc = vdFindFilterBackend(pszFilter, &pFilter->pBackend); 6167 if (RT_FAILURE(rc)) 6168 break; 6169 if (!pFilter->pBackend) 6170 { 6171 rc = vdError(pDisk, VERR_INVALID_PARAMETER, RT_SRC_POS, 6172 N_("VD: unknown filter backend name '%s'"), pszFilter); 6173 break; 6174 } 6175 6176 rc = pFilter->pBackend->pfnCreate(pDisk->pVDIfsDisk, pVDIfsFilter, 6177 &pFilter->pvBackendData); 6178 6179 /* If the open in read-write mode failed, retry in read-only mode. */ 6180 if (RT_FAILURE(rc)) 6181 { 6182 rc = vdError(pDisk, rc, RT_SRC_POS, 6183 N_("VD: error %Rrc creating filter '%s'"), rc, pszFilter); 6184 break; 6185 } 6186 6187 /* Lock disk for writing, as we modify pDisk information below. */ 6188 rc2 = vdThreadStartWrite(pDisk); 6189 AssertRC(rc2); 6190 fLockWrite = true; 6191 6192 /* Add filter to chain. */ 6193 vdAddFilterToList(pDisk, pFilter); 6194 } while (0); 6195 6196 if (RT_UNLIKELY(fLockWrite)) 6197 { 6198 rc2 = vdThreadFinishWrite(pDisk); 6199 AssertRC(rc2); 6200 } 6201 6202 if (RT_FAILURE(rc)) 6203 { 6204 if (pFilter) 6205 RTMemFree(pFilter); 5899 6206 } 5900 6207 … … 7890 8197 7891 8198 /** 8199 * Removes the last added filter in the HDD container. 8200 * 8201 * @return VBox status code. 8202 * @retval VERR_VD_NOT_OPENED if no filter is present for the disk. 8203 * @param pDisk Pointer to HDD container. 8204 */ 8205 VBOXDDU_DECL(int) VDFilterRemove(PVBOXHDD pDisk) 8206 { 8207 int rc = VINF_SUCCESS; 8208 int rc2; 8209 bool fLockWrite = false; 8210 PVDFILTER pFilter = NULL; 8211 8212 LogFlowFunc(("pDisk=%#p\n", pDisk)); 8213 8214 do 8215 { 8216 /* sanity check */ 8217 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 8218 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 8219 8220 rc2 = vdThreadStartWrite(pDisk); 8221 AssertRC(rc2); 8222 fLockWrite = true; 8223 8224 AssertPtrBreakStmt(pDisk->pFilterHead, rc = VERR_VD_NOT_OPENED); 8225 8226 pFilter = pDisk->pFilterTail; 8227 vdRemoveFilterFromList(pDisk, pFilter); 8228 8229 pFilter->pBackend->pfnDestroy(pFilter->pvBackendData); 8230 RTMemFree(pFilter); 8231 } while (0); 8232 8233 if (RT_LIKELY(fLockWrite)) 8234 { 8235 rc2 = vdThreadFinishWrite(pDisk); 8236 AssertRC(rc2); 8237 } 8238 8239 LogFlowFunc(("returns %Rrc\n", rc)); 8240 return rc; 8241 } 8242 8243 /** 7892 8244 * Closes all opened image files in HDD container. 7893 8245 * … … 7941 8293 } 7942 8294 Assert(!VALID_PTR(pDisk->pLast)); 8295 } while (0); 8296 8297 if (RT_UNLIKELY(fLockWrite)) 8298 { 8299 rc2 = vdThreadFinishWrite(pDisk); 8300 AssertRC(rc2); 8301 } 8302 8303 LogFlowFunc(("returns %Rrc\n", rc)); 8304 return rc; 8305 } 8306 8307 /** 8308 * Removes all filters of the given HDD container. 8309 * 8310 * @return VBox status code. 8311 * @param pDisk Pointer to HDD container. 8312 */ 8313 VBOXDDU_DECL(int) VDFilterRemoveAll(PVBOXHDD pDisk) 8314 { 8315 int rc = VINF_SUCCESS; 8316 int rc2; 8317 bool fLockWrite = false; 8318 8319 LogFlowFunc(("pDisk=%#p\n", pDisk)); 8320 do 8321 { 8322 /* sanity check */ 8323 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 8324 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 8325 8326 /* Lock the entire operation. */ 8327 rc2 = vdThreadStartWrite(pDisk); 8328 AssertRC(rc2); 8329 fLockWrite = true; 8330 8331 PVDFILTER pFilter = pDisk->pFilterTail; 8332 while (VALID_PTR(pFilter)) 8333 { 8334 PVDFILTER pPrev = pFilter->pPrev; 8335 vdRemoveFilterFromList(pDisk, pFilter); 8336 8337 rc2 = pFilter->pBackend->pfnDestroy(pFilter->pvBackendData); 8338 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 8339 rc = rc2; 8340 /* Free remaining resources related to the image. */ 8341 RTMemFree(pFilter); 8342 pFilter = pPrev; 8343 } 8344 Assert(!VALID_PTR(pDisk->pFilterTail)); 7943 8345 } while (0); 7944 8346 … … 9635 10037 { 9636 10038 rc = VERR_NO_MEMORY; 10039 break; 10040 } 10041 10042 /* Apply write filter chain here. */ 10043 rc = vdFilterChainApplyWrite(pDisk, uOffset, cbWrite, pIoCtx); 10044 if (RT_FAILURE(rc)) 10045 { 10046 vdIoCtxFree(pDisk, pIoCtx); 9637 10047 break; 9638 10048 }
Note:
See TracChangeset
for help on using the changeset viewer.