VOID PvfsReleaseFCB( PPVFS_FCB *ppFcb ) { NTSTATUS ntError = STATUS_SUCCESS; BOOLEAN bucketLocked = FALSE; BOOLEAN fcbLocked = FALSE; PPVFS_FCB pFcb = NULL; PPVFS_CB_TABLE_ENTRY pBucket = NULL; LONG refCount = 0; LWIO_ASSERT((ppFcb != NULL) && (*ppFcb != NULL)); pFcb = *ppFcb; // It is important to lock the ScbTable here so that there is no window // between the refcount check and the remove. Otherwise another open request // could search and locate the SCB in the tree and return free()'d memory. // However, if the SCB has no bucket pointer, it has already been removed // from the ScbTable so locking is unnecessary. */ LWIO_LOCK_MUTEX(fcbLocked, &pFcb->BaseControlBlock.Mutex); pBucket = pFcb->BaseControlBlock.pBucket; if (pBucket) { LWIO_LOCK_RWMUTEX_EXCLUSIVE(bucketLocked, &pBucket->rwLock); } refCount = InterlockedDecrement(&pFcb->BaseControlBlock.RefCount); LWIO_ASSERT(refCount >= 0); if (refCount == 0) { LWIO_ASSERT(PvfsListIsEmpty(pFcb->pScbList)); if (pBucket) { ntError = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)pFcb, pFcb->pszFilename); LWIO_ASSERT(ntError == STATUS_SUCCESS); LWIO_UNLOCK_RWMUTEX(bucketLocked, &pBucket->rwLock); } LWIO_UNLOCK_MUTEX(fcbLocked, &pFcb->BaseControlBlock.Mutex); PvfsFreeFCB(pFcb); } LWIO_UNLOCK_RWMUTEX(bucketLocked, &pBucket->rwLock); LWIO_UNLOCK_MUTEX(fcbLocked, &pFcb->BaseControlBlock.Mutex); *ppFcb = NULL; return; }
NTSTATUS PvfsListRemoveItem( PPVFS_LIST pList, PLW_LIST_LINKS pItem ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; BAIL_ON_INVALID_PTR(pList, ntError); BAIL_ON_INVALID_PTR(pItem, ntError); if (PvfsListIsEmpty(pList)) { ntError = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } LwListRemove(pItem); pList->CurrentSize--; ntError = STATUS_SUCCESS; cleanup: return ntError; error: goto cleanup; }
VOID PvfsListDestroy( PPVFS_LIST *ppList ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PPVFS_LIST pList = NULL; PLW_LIST_LINKS pData = NULL; if (ppList && *ppList) { pList = *ppList; while (!PvfsListIsEmpty(pList)) { pData = NULL; ntError = PvfsListRemoveHead(pList, &pData); /* Avoid an infinite loop in the case of an error. This means we may leak memory. */ BAIL_ON_NT_STATUS(ntError); if (pList->pfnFreeData) { pList->pfnFreeData((PVOID*)&pData); } else { PVFS_FREE(&pData); } } RTL_FREE(ppList); } cleanup: return; error: goto cleanup; }