/*++ Copyright (c) 1999 Microsoft Corporation Module Name: cmdelay.c Abstract: This module implements the new algorithm (LRU style) for the Delayed Close KCB table. Functions in this module are thread safe protected by the kcb lock. When kcb lock is converted to a resource, we should assert (enforce) exclusivity of that resource here !!! Note: We might want to convert these functions to macros after enough testing provides that they work well Author: Dragos C. Sambotin (dragoss) 09-Aug-1999 Revision History: --*/ #include "cmp.h" ULONG CmpDelayedCloseSize = 2048; // !!!! Cannot be bigger that 4094 !!!!! CM_DELAYED_CLOSE_ENTRY *CmpDelayedCloseTable; LIST_ENTRY CmpDelayedLRUListHead; // head of the LRU list of Delayed Close Table entries ULONG CmpGetDelayedCloseIndex( ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,CmpInitializeDelayedCloseTable) #pragma alloc_text(PAGE,CmpRemoveFromDelayedClose) #pragma alloc_text(PAGE,CmpGetDelayedCloseIndex) #pragma alloc_text(PAGE,CmpAddToDelayedClose) #endif VOID CmpInitializeDelayedCloseTable() /*++ Routine Description: Initialize delayed close table; allocation + LRU list initialization. Arguments: Return Value: NONE. --*/ { ULONG i; PAGED_CODE(); // // allocate the table from paged pool; it is important that the table // is contiguous in memory as we compute the index based on this assumption // CmpDelayedCloseTable = ExAllocatePoolWithTag(PagedPool, CmpDelayedCloseSize * sizeof(CM_DELAYED_CLOSE_ENTRY), CM_DELAYCLOSE_TAG); if (CmpDelayedCloseTable == NULL) { CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_DELAYED_CLOSE_TABLE,1,0,0); return; } // // Init LRUlist head. // InitializeListHead(&CmpDelayedLRUListHead); for (i=0; iDelayedCloseIndex; // If not on delayed close, don't try to remove if (i == CmpDelayedCloseSize) { return; } CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"[CmpRemoveFromDelayedClose] : Removing kcb = %p from DelayedCloseTable; index = %lu\n",kcb,(ULONG)i)); // // at this index should be the this kcb and the index should not be bigger // than the size of the table // ASSERT(CmpDelayedCloseTable[i].KeyControlBlock == kcb); ASSERT( i < CmpDelayedCloseSize ); // // nobody should hold references on this particular kcb // ASSERT_KCB_LOCK_OWNED_EXCLUSIVE(); // // mark the entry as available and add it to the end of the LRU list // CmpDelayedCloseTable[i].KeyControlBlock = NULL; CmpRemoveEntryList(&(CmpDelayedCloseTable[i].DelayedLRUList)); InsertTailList( &CmpDelayedLRUListHead, &(CmpDelayedCloseTable[i].DelayedLRUList) ); kcb->DelayedCloseIndex = CmpDelayedCloseSize; } ULONG CmpGetDelayedCloseIndex( ) /*++ Routine Description: Finds a free entry in the delayed close table and returns it. If the table is full, the kcb in the last entry (LRU-wise) is kicked out of the table and its entry is reused. Arguments: Note: kcb lock/resource should be aquired exclusively when this function is called Return Value: NONE. --*/ { ULONG DelayedIndex; PCM_DELAYED_CLOSE_ENTRY DelayedEntry; PAGED_CODE(); // // get the last entry in the Delayed LRU list // DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)CmpDelayedLRUListHead.Blink; Retry: DelayedEntry = CONTAINING_RECORD( DelayedEntry, CM_DELAYED_CLOSE_ENTRY, DelayedLRUList); if( DelayedEntry->KeyControlBlock != NULL ) { // // entry is not available; kick the kcb out of cache // ASSERT_KCB(DelayedEntry->KeyControlBlock); //ASSERT( DelayedEntry->KeyControlBlock->RefCount == 0 ); // // lock should be held here !!! // if(DelayedEntry->KeyControlBlock->RefCount == 0) { CmpCleanUpKcbCacheWithLock(DelayedEntry->KeyControlBlock); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"[CmpGetDelayedCloseIndex] : no index free; kicking kcb = %p index = %lu out of DelayedCloseTable\n", DelayedEntry->KeyControlBlock,(ULONG)(((PUCHAR)DelayedEntry - (PUCHAR)CmpDelayedCloseTable) / sizeof( CM_DELAYED_CLOSE_ENTRY )))); } else { // // somebody else is partying on this kcb; go to the next entry (in reverse order). // if( DelayedEntry->DelayedLRUList.Blink == CmpDelayedLRUListHead.Flink ) { // // we cannot go up anymore; we need to yank this one. // DelayedEntry->KeyControlBlock->DelayedCloseIndex = CmpDelayedCloseSize; } else { // // go back one spot and retry // DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)(DelayedEntry->DelayedLRUList.Blink); goto Retry; } } DelayedEntry->KeyControlBlock = NULL; } DelayedIndex = (ULONG) (((PUCHAR)DelayedEntry - (PUCHAR)CmpDelayedCloseTable) / sizeof( CM_DELAYED_CLOSE_ENTRY )); // // sanity check // ASSERT( DelayedIndex < CmpDelayedCloseSize ); #if defined(_WIN64) // // somehow DelayedIndex is ok here but it gets corupted upon return from this api // if( DelayedIndex >= CmpDelayedCloseSize ) { DbgPrint("CmpGetDelayedCloseIndex: Bogus index %lx; DelayedEntry = %p; sizeof( CM_DELAYED_CLOSE_ENTRY ) = %lx\n", DelayedIndex,DelayedEntry,sizeof( CM_DELAYED_CLOSE_ENTRY ) ); DbgBreakPoint(); } #endif return DelayedIndex; } VOID CmpAddToDelayedClose( IN PCM_KEY_CONTROL_BLOCK kcb ) /*++ Routine Description: Adds a kcb to the delayed close table Arguments: kcb - the kcb in question Note: kcb lock/resource should be aquired exclusively when this function is called Return Value: NONE. --*/ { ULONG DelayedIndex; PCM_DELAYED_CLOSE_ENTRY DelayedEntry; PAGED_CODE(); ASSERT_KCB( kcb); ASSERT( kcb->RefCount == 0 ); ASSERT_KCB_LOCK_OWNED_EXCLUSIVE(); // Already on delayed close, don't try to put on again if (kcb->DelayedCloseIndex != CmpDelayedCloseSize) { return; } // // get the delayed entry and attach the kcb to it // DelayedIndex = CmpGetDelayedCloseIndex(); #if defined(_WIN64) // // somehow DelayedIndex is corupted here, but it was ok prior to return from CmpGetDeleyedCloseIndex // if( DelayedIndex >= CmpDelayedCloseSize ) { DbgPrint("CmpAddToDelayedClose: Bogus index %lx; sizeof( CM_DELAYED_CLOSE_ENTRY ) = %lx\n", DelayedIndex,sizeof( CM_DELAYED_CLOSE_ENTRY ) ); DbgBreakPoint(); } #endif DelayedEntry = &(CmpDelayedCloseTable[DelayedIndex]); ASSERT( DelayedEntry->KeyControlBlock == NULL ); DelayedEntry->KeyControlBlock = kcb; kcb->DelayedCloseIndex = DelayedIndex; CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"[CmpAddToDelayedClose] : Adding kcb = %p to DelayedCloseTable; index = %lu\n", kcb,DelayedIndex)); // // move the entry on top of the LRU list // CmpRemoveEntryList(&(DelayedEntry->DelayedLRUList)); InsertHeadList( &CmpDelayedLRUListHead, &(DelayedEntry->DelayedLRUList) ); }