Beispiel #1
0
VOID
NTAPI
CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
                                      IN BOOLEAN LockHeldExclusively)
{
    CMTRACE(CM_REFERENCE_DEBUG,
            "%s - Dereferencing KCB: %p\n", __FUNCTION__, Kcb);

    /* Sanity check */
    ASSERT_KCB_VALID(Kcb);

    /* Check if this is the last reference */
    if ((InterlockedDecrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0)
    {
        /* Sanity check */
        ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
               (CmpTestRegistryLockExclusive() == TRUE));

        /* Check if we should do a direct delete */
        if (((CmpHoldLazyFlush) &&
                !(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) &&
                !(Kcb->Flags & KEY_SYM_LINK)) ||
                (Kcb->ExtFlags & CM_KCB_NO_DELAY_CLOSE) ||
                (Kcb->Delete))
        {
            /* Clean up the KCB*/
            CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively);
        }
        else
        {
            /* Otherwise, use delayed close */
            CmpAddToDelayedClose(Kcb, LockHeldExclusively);
        }
    }
}
Beispiel #2
0
ULONG
CmpSearchForOpenSubKeys(
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock,
    SUBKEY_SEARCH_TYPE      SearchType
    )
/*++
Routine Description:

    This routine searches the KCB tree for any open handles to keys that
    are subkeys of the given key.

    It is used by CmRestoreKey to verify that the tree being restored to
    has no open handles.

Arguments:

    KeyControlBlock - Supplies the key control block for the key for which
        open subkeys are to be found.

    SearchType - the type of the search
        SearchIfExist - exits at the first open subkey found ==> returns 1 if any subkey is open
        
        SearchAndDeref - Forces the keys underneath the Key referenced KeyControlBlock to 
                be marked as not referenced (see the REG_FORCE_RESTORE flag in CmRestoreKey) 
                returns 1 if at least one deref was made
        
        SearchAndCount - Counts all open subkeys - returns the number of them

Return Value:

    TRUE  - open handles to subkeys of the given key exist

    FALSE - open handles to subkeys of the given key do not exist.
--*/
{
    ULONG i;
    PCM_KEY_HASH *Current;
    PCM_KEY_CONTROL_BLOCK kcb;
    PCM_KEY_CONTROL_BLOCK Realkcb;
    PCM_KEY_CONTROL_BLOCK Parent;
    USHORT LevelDiff, l;
    ULONG   Count = 0;
    
    //
    // Registry lock should be held exclusively, so no need to KCB lock
    //
    ASSERT_CM_LOCK_OWNED_EXCLUSIVE();


    //
    // First, clean up all subkeys in the cache
    //
    for (i=0; i<CmpHashTableSize; i++) {
        Current = &CmpCacheTable[i];
        while (*Current) {
            kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash);
            if (kcb->RefCount == 0) {
                //
                // This kcb is in DelayClose case, remove it.
                //
                CmpRemoveFromDelayedClose(kcb);
                CmpCleanUpKcbCacheWithLock(kcb);

                //
                // The HashTable is changed, start over in this index again.
                //
                Current = &CmpCacheTable[i];
                continue;
            }
            Current = &kcb->NextHash;
        }
    }

    if (KeyControlBlock->RefCount == 1) {
        //
        // There is only one open handle, so there must be no open subkeys.
        //
        Count = 0;
    } else {
        //
        // Now search for an open subkey handle.
        //
        Count = 0;

     
#ifdef KCB_TO_KEYBODY_LINK
        //
        // dump the root first if we were asked to do so.
        //
        if(SearchType == SearchAndCount) {
            CmpDumpKeyBodyList(KeyControlBlock,&Count);
        }
#endif
        for (i=0; i<CmpHashTableSize; i++) {

StartDeref:
            Current = &CmpCacheTable[i];
            while (*Current) {
                kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash);
                if (kcb->TotalLevels > KeyControlBlock->TotalLevels) {
                    LevelDiff = kcb->TotalLevels - KeyControlBlock->TotalLevels;
                
                    Parent = kcb;
                    for (l=0; l<LevelDiff; l++) {
                        Parent = Parent->ParentKcb;
                    }
    
                    if (Parent == KeyControlBlock) {
                        //
                        // Found a match;
                        //
                        if( SearchType == SearchIfExist ) {
                            Count = 1;
                            break;
                        } else if(SearchType == SearchAndDeref) {
                            //
                            // Mark the key as deleted, remove it from cache, but don't add it
                            // to the Delay Close table (we want the key to be visible only to
                            // the one(s) that have open handles on it.
                            //

                            ASSERT_CM_LOCK_OWNED_EXCLUSIVE();

                            //
                            // flush any pending notifies as the kcb won't be around any longer
                            //
#ifdef KCB_TO_KEYBODY_LINK
                            CmpFlushNotifiesOnKeyBodyList(kcb);
#endif
                            
                            CmpCleanUpSubKeyInfo(kcb->ParentKcb);
                            kcb->Delete = TRUE;
                            CmpRemoveKeyControlBlock(kcb);
                            kcb->KeyCell = HCELL_NIL;
                            kcb->KeyNode = NULL;
                            Count++;
                         
                            //
                            // Restart the search 
                            // 
                            goto StartDeref;
                        
                        } else if(SearchType == SearchAndCount) {
                            //
                            // here do the dumping and count incrementing stuff
                            //
                        #ifdef KCB_TO_KEYBODY_LINK
                            CmpDumpKeyBodyList(kcb,&Count);
                        #else
                            Count++;
                        #endif
                        }
                    }   

                }
                Current = &kcb->NextHash;
            }
        }
    }
    
                           
    return Count;
}
Beispiel #3
0
VOID
CmpDereferenceKeyControlBlockWithLock(
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock
    )
{
    ULONG_PTR FreeIndex;
    PCM_KEY_CONTROL_BLOCK KcbToFree;



    ASSERT_KCB(KeyControlBlock);

    if (--KeyControlBlock->RefCount == 0) {
        //
        // Remove kcb from the tree
        //
        if (KeyControlBlock->ExtFlags & CM_KCB_NO_DELAY_CLOSE) {
            //
            // Free storage directly so we can clean up junk quickly.
            //
            //
            // Need to free all cached Index List, Index Leaf, Value, etc.
            //
            CmpCleanUpKcbCacheWithLock(KeyControlBlock);
        } else if (!KeyControlBlock->Delete) {

            //
            // Put this kcb on our delayed close list.
            //
            // First check the free list for a free slot.
            //
            FreeIndex = CmpDelayedFreeIndex;
            if (FreeIndex != -1) {
                ASSERT(FreeIndex < CmpDelayedCloseSize);
                CmpDelayedFreeIndex = (ULONG_PTR)CmpDelayedCloseTable[FreeIndex];
                KeyControlBlock->DelayedCloseIndex = (USHORT) FreeIndex;
                ASSERT((CmpDelayedFreeIndex == -1) ||
                       (CmpDelayedFreeIndex < CmpDelayedCloseSize));
                CmpDelayedCloseTable[FreeIndex] = KeyControlBlock;
            } else {

                //
                // Nothing is free, we have to get rid of something.
                //
                ASSERT(*CmpDelayedCloseCurrent != NULL);
                ASSERT(!(*CmpDelayedCloseCurrent)->Delete);
                //
                // Need to free all cached Index List, Index Leaf, Value, etc.
                // Change the code sequence for the recurrsive call to dereference the parent.
                //
                KcbToFree = *CmpDelayedCloseCurrent;
                *CmpDelayedCloseCurrent = KeyControlBlock;
                KeyControlBlock->DelayedCloseIndex = (USHORT)(CmpDelayedCloseCurrent - CmpDelayedCloseTable);
                ++CmpDelayedCloseCurrent;
                if ((ULONG)(CmpDelayedCloseCurrent - CmpDelayedCloseTable) == CmpDelayedCloseSize) {
                    CmpDelayedCloseCurrent = CmpDelayedCloseTable;
                }

                CmpCleanUpKcbCacheWithLock(KcbToFree);
            }
        } else {
            //
            // Free storage directly as there is no point in putting this on
            // our delayed close list.
            //
            //
            // Need to free all cached Index List, Index Leaf, Value, etc.
            //
            CmpCleanUpKcbCacheWithLock(KeyControlBlock);
        }
    }

    return;
}
Beispiel #4
0
VOID
CmpSearchKeyControlBlockTree(
    PKCB_WORKER_ROUTINE WorkerRoutine,
    PVOID               Context1,
    PVOID               Context2
    )
/*++

Routine Description:

    Traverse the kcb tree.  We will visit all nodes unless WorkerRoutine
    tells us to stop part way through.

    For each node, call WorkerRoutine(..., Context1, Contex2).  If it returns
    KCB_WORKER_DONE, we are done, simply return.  If it returns
    KCB_WORKER_CONTINUE, just continue the search. If it returns KCB_WORKER_DELETE,
    the specified KCB is marked as deleted.

    This routine has the side-effect of removing all delayed-close KCBs.

Arguments:

    WorkerRoutine - applied to nodes witch Match.

    Context1 - data we pass through

    Context2 - data we pass through


Return Value:

    NONE.

--*/
{
    PCM_KEY_CONTROL_BLOCK   Current;
    PCM_KEY_CONTROL_BLOCK   Next;
    PCM_KEY_HASH *Prev;
    ULONG                   WorkerResult;
    ULONG                   i;

    //
    // Walk the hash table
    //
    for (i=0; i<CmpHashTableSize; i++) {
        Prev = &CmpCacheTable[i];
        while (*Prev) {
            Current = CONTAINING_RECORD(*Prev,
                                        CM_KEY_CONTROL_BLOCK,
                                        KeyHash);
            ASSERT_KCB(Current);
            ASSERT(!Current->Delete);
            if (Current->RefCount == 0) {
                //
                // This kcb is in DelayClose case, remove it.
                //
                CmpRemoveFromDelayedClose(Current);
                CmpCleanUpKcbCacheWithLock(Current);

                //
                // The HashTable is changed, start over in this index again.
                //
                Prev = &CmpCacheTable[i];
                continue;
            }

            WorkerResult = (WorkerRoutine)(Current, Context1, Context2);
            if (WorkerResult == KCB_WORKER_DONE) {
                return;
            } else if (WorkerResult == KCB_WORKER_DELETE) {
                ASSERT(Current->Delete);
                *Prev = Current->NextHash;
                continue;
            } else {
                ASSERT(WorkerResult == KCB_WORKER_CONTINUE);
                Prev = &Current->NextHash;
            }
        }
    }
}
Beispiel #5
0
VOID
CmpAddToDelayedClose(
    IN PCM_KEY_CONTROL_BLOCK    kcb,
    IN BOOLEAN                  RegLockHeldEx
    )
/*++

Routine Description:

    Adds a kcb to the delayed close table

Arguments:

    kcb - the kcb in question

Note: 
    
    kcb lock/resource should be acquired exclusively when this function is called

Return Value:

    NONE.

--*/
{
    PCM_DELAYED_CLOSE_ENTRY     DelayedEntry = NULL;

    CM_PAGED_CODE();

    ASSERT( (CmpIsKCBLockedExclusive(kcb) == TRUE) || // this kcb is owned exclusive
            (CmpTestRegistryLockExclusive() == TRUE) ); // or the entire registry is locked exclusive


    // Already on delayed close, don't try to put on again
    if (kcb->DelayedCloseIndex != CmpDelayedCloseSize) { // see if we really need this
        ASSERT( FALSE );
        return;
    }

    ASSERT(kcb->RefCount == 0);

    //
    // now materialize a new entry for this kcb
    //
    ASSERT_KEYBODY_LIST_EMPTY(kcb);
    DelayedEntry = CmpDelayCloseAllocNewEntry();
    if( !DelayedEntry ) {
        //
        // this is bad luck; we need to free the kcb in place
        //
        CmpCleanUpKcbCacheWithLock(kcb,RegLockHeldEx);
        return;
    }
#if DBG
    if( kcb->InDelayClose != 0 ) {
        ASSERT( FALSE );
    }
    {
        LONG                        OldRefCount;
        LONG                        NewRefCount;

        OldRefCount = *(PLONG)&kcb->InDelayClose; //get entire dword
        ASSERT( OldRefCount == 0 );
        NewRefCount = 1;
        if( InterlockedCompareExchange((PLONG)&kcb->InDelayClose,NewRefCount,OldRefCount)
                != OldRefCount ) {
    
            ASSERT( FALSE );
        }
    }
#endif //DBG
    //
    // populate the entry and insert it into the LRU list (at the top).
    //
    kcb->DelayedCloseIndex = 0; // see if we really need this
    kcb->DelayCloseEntry = (PVOID)DelayedEntry;    // need this for removing it back from here
    DelayedEntry->KeyControlBlock = kcb;
    InterlockedIncrement((PLONG)&CmpDelayedCloseElements);

    LOCK_DELAY_CLOSE();
    InsertHeadList(
        &CmpDelayedLRUListHead,
        &(DelayedEntry->DelayedLRUList)
        );
    //
    // check if limit hit and arm timer if not already armed
    //
    if( (CmpDelayedCloseElements > CmpDelayedCloseSize) && (!CmpDelayCloseWorkItemActive) ) {
        CmpArmDelayedCloseTimer();
    } 
    UNLOCK_DELAY_CLOSE();
    //
    // we're done here
    //

}
Beispiel #6
0
VOID
CmpDelayCloseWorker(
    IN PVOID Parameter
    )

/*++

Routine Description:
    
      The fun part. We need to walk the cache and look for kcbs with refcount == 0
      Get the oldest one and kick it out of cache.

Arguments:

    Parameter - not used.

Return Value:

    None.

--*/

{
    PCM_DELAYED_CLOSE_ENTRY     DelayedEntry;
    ULONG                       ConvKey;
    ULONG                       MaxIterations = MAX_DELAY_WORKER_ITERATIONS;

    CM_PAGED_CODE();

    UNREFERENCED_PARAMETER (Parameter);

    ASSERT(CmpDelayCloseWorkItemActive);

    BEGIN_LOCK_CHECKPOINT;
    CmpLockRegistry();
    
    //
    // process kick out every entry with RefCount == 0 && DelayCloseIndex == 0
    // ignore the others; we only do this while there is excess of delay - close kcbs
    //
    LOCK_DELAY_CLOSE();
    while( (CmpDelayedCloseElements > CmpDelayedCloseSize) && (MaxIterations--) ) {
        ASSERT( !CmpIsListEmpty(&CmpDelayedLRUListHead) );
        //
        // We first need to get the hash entry and attempt to lock it.
        //
        DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)(CmpDelayedLRUListHead.Blink);
        DelayedEntry = CONTAINING_RECORD(   DelayedEntry,
                                            CM_DELAYED_CLOSE_ENTRY,
                                            DelayedLRUList);
        ConvKey = DelayedEntry->KeyControlBlock->ConvKey;
        UNLOCK_DELAY_CLOSE();
        //
        // now lock the hash then recheck if the entry is still first on the list
        //
        CmpLockHashEntryExclusive(ConvKey);
        LOCK_DELAY_CLOSE();
        if( CmpDelayedCloseElements <= CmpDelayedCloseSize ) {
            //
            // just bail out; no need to kick them out
            //
            CmpUnlockHashEntry(ConvKey);
            break;
        }
        DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)(CmpDelayedLRUListHead.Blink);
        DelayedEntry = CONTAINING_RECORD(   DelayedEntry,
                                            CM_DELAYED_CLOSE_ENTRY,
                                            DelayedLRUList);
        if( ConvKey == DelayedEntry->KeyControlBlock->ConvKey ) {
            //
            // same hash entry; proceed
            // pull it out of the list
            //
            DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)RemoveTailList(&CmpDelayedLRUListHead);
    
            DelayedEntry = CONTAINING_RECORD(   DelayedEntry,
                                                CM_DELAYED_CLOSE_ENTRY,
                                                DelayedLRUList);
            CmpClearListEntry(&(DelayedEntry->DelayedLRUList));

            if( (DelayedEntry->KeyControlBlock->RefCount == 0) && (DelayedEntry->KeyControlBlock->DelayedCloseIndex == 0) ){
                //
                // free this kcb and the entry
                //
                UNLOCK_DELAY_CLOSE();
                DelayedEntry->KeyControlBlock->DelayCloseEntry = NULL;
                CmpCleanUpKcbCacheWithLock(DelayedEntry->KeyControlBlock,FALSE);
                CmpDelayCloseFreeEntry(DelayedEntry);
                InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
            } else {
                //
                // put it back at the top
                //
                InsertHeadList( &CmpDelayedLRUListHead,
                                &(DelayedEntry->DelayedLRUList)
                            );
                UNLOCK_DELAY_CLOSE();
            }
        } else {
            UNLOCK_DELAY_CLOSE();
        }
        CmpUnlockHashEntry(ConvKey);

        LOCK_DELAY_CLOSE();
    }
    if( CmpDelayedCloseElements > CmpDelayedCloseSize ) {
        //
        // iteration run was too short, there are more elements to process, queue ourselves for later
        //
        CmpArmDelayedCloseTimer();
    } else {
        //
        // signal that we have finished our work.
        //
        CmpDelayCloseWorkItemActive = FALSE;
    }
    UNLOCK_DELAY_CLOSE();


    CmpUnlockRegistry();
    END_LOCK_CHECKPOINT;
}