907 lines
22 KiB
C
907 lines
22 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Scavengr.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the Netware Redirector scavenger thread.
|
||
|
||
Author:
|
||
|
||
Manny Weiser [MannyW] 15-Feb-1993
|
||
|
||
Revision History:
|
||
|
||
Tommy Evans (tommye) 04-27-2000 MS bug 33463 - added bShuttingDown flag
|
||
to CleanupSupplementalCredentials() to force cleanup
|
||
of cached credentials when we are unloaded.
|
||
--*/
|
||
|
||
#include "Procs.h"
|
||
|
||
//
|
||
// The debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_SCAVENGER)
|
||
|
||
extern BOOLEAN WorkerRunning; // From timer.c
|
||
|
||
#ifdef NWDBG
|
||
DWORD DumpIcbFlag = 0 ;
|
||
#endif
|
||
|
||
VOID
|
||
CleanupVcbs(
|
||
LARGE_INTEGER Now
|
||
);
|
||
|
||
VOID
|
||
CleanupObjectCache(
|
||
VOID
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
|
||
#ifndef QFE_BUILD
|
||
#pragma alloc_text( PAGE1, NwAllocateExtraIrpContext )
|
||
#pragma alloc_text( PAGE1, NwFreeExtraIrpContext )
|
||
#pragma alloc_text( PAGE1, CleanupScbs )
|
||
#pragma alloc_text( PAGE1, DisconnectTimedOutScbs )
|
||
#endif
|
||
|
||
#endif
|
||
|
||
//
|
||
// Not pageable:
|
||
//
|
||
// NwScavengerRoutine - Acquires a spin lock.
|
||
// CleanupVcbs - Acquires a spin lock.
|
||
//
|
||
|
||
VOID
|
||
NwScavengerRoutine(
|
||
IN PWORK_QUEUE_ITEM WorkItem
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the scavenger. The scavenger runs
|
||
periodically in the context of an executive worker thread to
|
||
do background cleanup operations on redirector data.
|
||
|
||
Arguments:
|
||
|
||
WorkItem - The work item for this routine.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LARGE_INTEGER Now;
|
||
PMDL LineChangeMdl;
|
||
PWORK_QUEUE_ITEM LineChangeWorkItem;
|
||
KIRQL OldIrql;
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
DebugTrace(+1, Dbg, "NwScavengerRoutine\n", 0);
|
||
|
||
KeQuerySystemTime( &Now );
|
||
|
||
#ifdef NWDBG
|
||
if (DumpIcbFlag != 0)
|
||
DumpIcbs();
|
||
#endif
|
||
|
||
//
|
||
// Try to free unused VCBs.
|
||
//
|
||
|
||
CleanupVcbs(Now);
|
||
|
||
//
|
||
// Try disconnect from SCBs that are timed out.
|
||
//
|
||
|
||
DisconnectTimedOutScbs(Now) ;
|
||
|
||
//
|
||
// Try to invalidate old object cache entries.
|
||
//
|
||
|
||
CleanupObjectCache();
|
||
|
||
//
|
||
// Try to free unused SCBs.
|
||
//
|
||
|
||
CleanupScbs(Now);
|
||
|
||
//
|
||
// Clean up supplemental credentials that are
|
||
// no longer being used.
|
||
//
|
||
|
||
CleanupSupplementalCredentials(Now, FALSE);
|
||
|
||
//
|
||
// Flag we're finished now to avoid deadlock in stop timer.
|
||
//
|
||
|
||
KeAcquireSpinLock( &NwScavengerSpinLock, &OldIrql );
|
||
|
||
if ( DelayedProcessLineChange ) {
|
||
|
||
DebugTrace( 0, Dbg, "Scavenger processing a delayed line change notification.\n", 0 );
|
||
|
||
LineChangeMdl = DelayedLineChangeIrp->MdlAddress;
|
||
LineChangeWorkItem = ALLOCATE_POOL( NonPagedPool, sizeof( WORK_QUEUE_ITEM ) );
|
||
|
||
if ( LineChangeWorkItem == NULL ) {
|
||
|
||
//
|
||
// If we couldn't get a work queue item, just blow
|
||
// it all off for now.
|
||
//
|
||
|
||
FREE_POOL( LineChangeMdl->MappedSystemVa );
|
||
FREE_MDL( LineChangeMdl );
|
||
FREE_IRP( DelayedLineChangeIrp );
|
||
|
||
DelayedLineChangeIrp = NULL;
|
||
DelayedProcessLineChange = FALSE;
|
||
WorkerRunning = FALSE;
|
||
|
||
KeReleaseSpinLock( &NwScavengerSpinLock, OldIrql );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Leave WorkRunning set to TRUE so that the scavenger can't run
|
||
// while the process line change is running, but clear the line
|
||
// change flag. The FspProcessLineChange function will clear the
|
||
// WorkerRunning flag.
|
||
//
|
||
|
||
DelayedProcessLineChange = FALSE;
|
||
KeReleaseSpinLock( &NwScavengerSpinLock, OldIrql );
|
||
|
||
//
|
||
// Use the user buffer field as a convenient place to remember where
|
||
// the address of the WorkQueueItem. We can get away with this since
|
||
// we don't let this IRP complete.
|
||
//
|
||
|
||
DelayedLineChangeIrp->UserBuffer = LineChangeWorkItem;
|
||
|
||
//
|
||
// Process the line change in the FSP.
|
||
//
|
||
|
||
ExInitializeWorkItem( LineChangeWorkItem, FspProcessLineChange, DelayedLineChangeIrp );
|
||
ExQueueWorkItem( LineChangeWorkItem, DelayedWorkQueue );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// No line change happened while the scavenger was running.
|
||
//
|
||
|
||
WorkerRunning = FALSE;
|
||
KeReleaseSpinLock( &NwScavengerSpinLock, OldIrql );
|
||
|
||
}
|
||
|
||
//
|
||
// Unlock discardable code, if we are inactive. Don't block
|
||
// if can't get resource.
|
||
//
|
||
|
||
NwUnlockCodeSections(FALSE);
|
||
|
||
|
||
DebugTrace(-1, Dbg, "NwScavengerRoutine\n", 0);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
CleanupScbs(
|
||
LARGE_INTEGER Now
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine tries to free unused VCB structures.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
PLIST_ENTRY ScbQueueEntry;
|
||
PNONPAGED_SCB pNpScb;
|
||
PLIST_ENTRY NextScbQueueEntry;
|
||
PSCB pScb;
|
||
LIST_ENTRY DyingScbs;
|
||
LARGE_INTEGER KillTime ;
|
||
|
||
DebugTrace(+1, Dbg, "CleanupScbs\n", 0);
|
||
|
||
//
|
||
// Calculate KillTime = Now - 2 minutes.
|
||
//
|
||
|
||
InitializeListHead( &DyingScbs );
|
||
|
||
KillTime.QuadPart = Now.QuadPart - ( NwOneSecond * DORMANT_SCB_KEEP_TIME );
|
||
|
||
//
|
||
// Scan through the SCBs holding the RCB.
|
||
//
|
||
|
||
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
||
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
||
|
||
//
|
||
// find all SCBs that are no longer usable and put them on the dying list.
|
||
// we will take a second pass thru to remove timed out ones, based on
|
||
// what is left.
|
||
//
|
||
|
||
for (ScbQueueEntry = ScbQueue.Flink ;
|
||
ScbQueueEntry != &ScbQueue ;
|
||
ScbQueueEntry = NextScbQueueEntry )
|
||
{
|
||
|
||
pNpScb = CONTAINING_RECORD( ScbQueueEntry, NONPAGED_SCB, ScbLinks );
|
||
NextScbQueueEntry = pNpScb->ScbLinks.Flink;
|
||
|
||
if ( ( pNpScb->Reference == 0 ) &&
|
||
( ( pNpScb->LastUsedTime.QuadPart < KillTime.QuadPart ) ||
|
||
( pNpScb->State == SCB_STATE_FLAG_SHUTDOWN ) ) )
|
||
{
|
||
DebugTrace( 0, Dbg,
|
||
"Moving SCB %08lx to dead list\n", pNpScb);
|
||
|
||
//
|
||
// The SCB has no references and is not logged in nor attached.
|
||
//
|
||
|
||
RemoveEntryList( &pNpScb->ScbLinks );
|
||
InsertHeadList( &DyingScbs, &pNpScb->ScbLinks );
|
||
}
|
||
|
||
#ifdef MSWDBG
|
||
//
|
||
// Look for blocked connections. If there's something
|
||
// queued for this server yet nothing was added or removed
|
||
// since the last time the scavenger ran then stop
|
||
//
|
||
|
||
if ((!IsListEmpty( &pNpScb->Requests ) ) &&
|
||
(pNpScb->RequestQueued == FALSE) &&
|
||
(pNpScb->RequestDequeued == FALSE )) {
|
||
|
||
DebugTrace( 0, Dbg, "Server %08lx seems to be locked up!\n", pNpScb );
|
||
ASSERT( FALSE );
|
||
|
||
} else {
|
||
|
||
pNpScb->RequestQueued = FALSE;
|
||
pNpScb->RequestDequeued = FALSE;
|
||
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// Now that the dying SCBs are off the ScbQueue we can release
|
||
// the SCB spin lock.
|
||
//
|
||
|
||
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
||
|
||
//
|
||
// Walk the list of Dying SCBs and kill them off. Note that we are
|
||
// still holding the RCB.
|
||
//
|
||
|
||
while ( !IsListEmpty( &DyingScbs ) ) {
|
||
|
||
pNpScb = CONTAINING_RECORD( DyingScbs.Flink, NONPAGED_SCB, ScbLinks );
|
||
pScb = pNpScb->pScb;
|
||
|
||
RemoveHeadList( &DyingScbs );
|
||
NwDeleteScb( pScb );
|
||
}
|
||
|
||
NwReleaseRcb( &NwRcb );
|
||
|
||
DebugTrace(-1, Dbg, "CleanupScbs\n", 0);
|
||
|
||
}
|
||
|
||
VOID
|
||
CleanupVcbs(
|
||
LARGE_INTEGER Now
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine tries to free unused VCB structures.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
PLIST_ENTRY ScbQueueEntry;
|
||
PLIST_ENTRY VcbQueueEntry;
|
||
PLIST_ENTRY NextVcbQueueEntry;
|
||
PNONPAGED_SCB pNpScb;
|
||
PSCB pScb;
|
||
PVCB pVcb;
|
||
LARGE_INTEGER KillTime;
|
||
|
||
NTSTATUS Status;
|
||
PIRP_CONTEXT IrpContext = NULL;
|
||
BOOLEAN VcbDeleted;
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace(+1, Dbg, "CleanupVcbs...\n", 0 );
|
||
|
||
//
|
||
// Calculate KillTime = Now - 5 minutes.
|
||
//
|
||
|
||
KillTime.QuadPart = Now.QuadPart - ( NwOneSecond * DORMANT_VCB_KEEP_TIME );
|
||
|
||
//
|
||
// Scan through the SCBs.
|
||
//
|
||
|
||
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
||
|
||
ScbQueueEntry = ScbQueue.Flink;
|
||
|
||
while ( ScbQueueEntry != &ScbQueue ) {
|
||
|
||
pNpScb = CONTAINING_RECORD( ScbQueueEntry, NONPAGED_SCB, ScbLinks );
|
||
|
||
//
|
||
// Reference the SCB so that it won't go away when we release
|
||
// the SCB spin lock.
|
||
//
|
||
|
||
NwReferenceScb( pNpScb );
|
||
|
||
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
||
|
||
pScb = pNpScb->pScb;
|
||
|
||
if ( pScb == NULL) {
|
||
|
||
//
|
||
// This must be the permanent SCB. Just skip it.
|
||
//
|
||
|
||
ASSERT( pNpScb == &NwPermanentNpScb );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Get an irp context and get to the head of the queue.
|
||
//
|
||
|
||
if ( NwAllocateExtraIrpContext( &IrpContext, pNpScb ) ) {
|
||
|
||
IrpContext->pNpScb = pNpScb;
|
||
IrpContext->pScb = pNpScb->pScb;
|
||
NwAppendToQueueAndWait( IrpContext );
|
||
|
||
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
||
|
||
VcbDeleted = TRUE;
|
||
|
||
//
|
||
// NwCleanupVcb releases the RCB, but we can't be guaranteed
|
||
// the state of the Vcb list when we release the RCB.
|
||
//
|
||
// If we need to cleanup a VCB, release the lock, and start
|
||
// processing the list again.
|
||
//
|
||
|
||
while ( VcbDeleted ) {
|
||
|
||
VcbDeleted = FALSE;
|
||
|
||
for ( VcbQueueEntry = pScb->ScbSpecificVcbQueue.Flink ;
|
||
VcbQueueEntry != &pScb->ScbSpecificVcbQueue;
|
||
VcbQueueEntry = NextVcbQueueEntry ) {
|
||
|
||
pVcb = CONTAINING_RECORD( VcbQueueEntry, VCB, VcbListEntry );
|
||
NextVcbQueueEntry = VcbQueueEntry->Flink;
|
||
|
||
//
|
||
// The VCB has no references, and hasn't been used for
|
||
// a long time. Kill it.
|
||
//
|
||
|
||
if ( pVcb->Reference == 0 ) {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
DebugTrace(0, Dbg, "Cleaning up VCB %08lx\n", pVcb );
|
||
DebugTrace(0, Dbg, "VCB name = %wZ\n", &pVcb->Name );
|
||
|
||
// Lock down so that we can send a packet.
|
||
NwReferenceUnlockableCodeSection();
|
||
|
||
NwCleanupVcb( pVcb, IrpContext );
|
||
|
||
NwDereferenceUnlockableCodeSection ();
|
||
|
||
//
|
||
// Get back to the head of the queue, re-acquire
|
||
// the VCB, and restart the processing of this list.
|
||
//
|
||
|
||
NwAppendToQueueAndWait( IrpContext );
|
||
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
||
VcbDeleted = TRUE;
|
||
|
||
break;
|
||
}
|
||
|
||
} // for
|
||
|
||
} // while
|
||
|
||
} else {
|
||
|
||
IrpContext = NULL;
|
||
DebugTrace( 0, Dbg, "Couldn't cleanup SCB: %08lx\n", pNpScb );
|
||
|
||
}
|
||
|
||
NwReleaseRcb( &NwRcb );
|
||
|
||
}
|
||
|
||
//
|
||
// Free the irp context allocated for this SCB.
|
||
//
|
||
|
||
if ( IrpContext != NULL ) {
|
||
NwDequeueIrpContext( IrpContext, FALSE );
|
||
NwFreeExtraIrpContext( IrpContext );
|
||
IrpContext = NULL;
|
||
}
|
||
|
||
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
||
ScbQueueEntry = pNpScb->ScbLinks.Flink;
|
||
NwDereferenceScb( pNpScb );
|
||
}
|
||
|
||
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
||
|
||
DebugTrace(-1, Dbg, "CleanupVcbs -> VOID\n", 0 );
|
||
}
|
||
|
||
|
||
VOID
|
||
DisconnectTimedOutScbs(
|
||
LARGE_INTEGER Now
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine disconnects any timed out SCBs before they get
|
||
nuked by CleanupScbs() which does not disconnect.
|
||
|
||
NOTE: The SCB's are destroyed on a timeout for a couple of
|
||
reasons. The first is because if we used a reference count then
|
||
normal use of UNCs would cause us to be continually reconnecting.
|
||
Another is in FindNearestServer where its useful to collect the
|
||
Near servers that are out of connections so we can avoid them when
|
||
we iterate through the 5 nearest servers and we escalate to General
|
||
SAP response.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
PLIST_ENTRY ScbQueueEntry;
|
||
PNONPAGED_SCB pNpScb;
|
||
LARGE_INTEGER KillTime ;
|
||
|
||
PIRP_CONTEXT IrpContext = NULL;
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace(+1, Dbg, "DisconnectTimedOutScbs...\n", 0 );
|
||
|
||
//
|
||
// Calculate KillTime = Now - 5 minutes.
|
||
//
|
||
|
||
KillTime.QuadPart = Now.QuadPart - ( NwOneSecond * DORMANT_SCB_KEEP_TIME );
|
||
|
||
//
|
||
// Scan through the SCBs.
|
||
//
|
||
|
||
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
||
|
||
ScbQueueEntry = ScbQueue.Flink;
|
||
|
||
while ( ScbQueueEntry != &ScbQueue )
|
||
{
|
||
|
||
pNpScb = CONTAINING_RECORD( ScbQueueEntry, NONPAGED_SCB, ScbLinks );
|
||
|
||
|
||
if ( (pNpScb != &NwPermanentNpScb) &&
|
||
(pNpScb->Reference == 0 ) &&
|
||
(pNpScb->LastUsedTime.QuadPart < KillTime.QuadPart) )
|
||
{
|
||
//
|
||
// Reference the SCB so that it won't go away when we release
|
||
// the SCB spin lock.
|
||
//
|
||
|
||
NwReferenceScb( pNpScb );
|
||
|
||
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
||
|
||
//
|
||
// Not the permanent SCB and the reference count is the one
|
||
// we just added, So this is really at zero & has not been used
|
||
// for a while. Note we only allocate the IrpContext once.
|
||
//
|
||
if ( IrpContext ||
|
||
NwAllocateExtraIrpContext( &IrpContext, pNpScb ) )
|
||
{
|
||
|
||
IrpContext->pNpScb = pNpScb;
|
||
|
||
// Lock down so that we can send a packet.
|
||
NwReferenceUnlockableCodeSection();
|
||
|
||
//
|
||
// get to front of queue and recheck to make sure we are
|
||
// still with a ref count of 1.
|
||
//
|
||
NwAppendToQueueAndWait( IrpContext );
|
||
|
||
if (pNpScb->Reference == 1)
|
||
{
|
||
//
|
||
// make sure we do not reconnect.
|
||
//
|
||
ClearFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
|
||
|
||
//
|
||
// This will result in a logoff and/or disconnect as
|
||
// need.
|
||
//
|
||
NwLogoffAndDisconnect(IrpContext, pNpScb) ;
|
||
}
|
||
|
||
NwDequeueIrpContext(IrpContext, FALSE) ;
|
||
|
||
NwDereferenceUnlockableCodeSection ();
|
||
|
||
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Could not allocate IrpContext. Oh well, we'll just leave
|
||
// this connection for the watch dog.
|
||
//
|
||
}
|
||
|
||
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
||
NwDereferenceScb( pNpScb );
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// not timed out or is permanent SCB. dont disconnect.
|
||
//
|
||
}
|
||
|
||
ScbQueueEntry = pNpScb->ScbLinks.Flink;
|
||
}
|
||
|
||
if ( IrpContext )
|
||
NwFreeExtraIrpContext( IrpContext );
|
||
|
||
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
||
|
||
DebugTrace(-1, Dbg, "DisconnectTimedOutScbs -> VOID\n", 0 );
|
||
}
|
||
|
||
BOOLEAN
|
||
NwAllocateExtraIrpContext(
|
||
OUT PIRP_CONTEXT *ppIrpContext,
|
||
IN PNONPAGED_SCB pNpScb
|
||
)
|
||
{
|
||
PIRP Irp;
|
||
BOOLEAN Success = TRUE;
|
||
|
||
try {
|
||
|
||
//
|
||
// Try to allocate an IRP
|
||
//
|
||
|
||
Irp = ALLOCATE_IRP( pNpScb->Server.pDeviceObject->StackSize, FALSE );
|
||
if ( Irp == NULL ) {
|
||
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
||
}
|
||
|
||
//
|
||
// Try to allocate an IRP Context. This will
|
||
// raise an excpetion if it fails.
|
||
//
|
||
|
||
*ppIrpContext = AllocateIrpContext( Irp );
|
||
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||
|
||
} except( NwExceptionFilter( Irp, GetExceptionInformation() )) {
|
||
Success = FALSE;
|
||
}
|
||
|
||
return( Success );
|
||
}
|
||
|
||
VOID
|
||
NwFreeExtraIrpContext(
|
||
IN PIRP_CONTEXT pIrpContext
|
||
)
|
||
{
|
||
FREE_IRP( pIrpContext->pOriginalIrp );
|
||
|
||
pIrpContext->pOriginalIrp = NULL; // Avoid FreeIrpContext modifying freed Irp.
|
||
|
||
FreeIrpContext( pIrpContext );
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
CleanupSupplementalCredentials(
|
||
LARGE_INTEGER Now,
|
||
BOOLEAN bShuttingDown
|
||
) {
|
||
|
||
PLIST_ENTRY pLogonList;
|
||
PLIST_ENTRY pCredList;
|
||
PLOGON pLogon;
|
||
PNDS_SECURITY_CONTEXT pCredential;
|
||
LARGE_INTEGER KillTime;
|
||
|
||
DebugTrace( 0, Dbg, "CleanupSupplementalCredentials...\n", 0 );
|
||
|
||
//
|
||
// Grab the RCB to protect the logon list.
|
||
//
|
||
|
||
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
||
|
||
pLogonList = LogonList.Flink;
|
||
|
||
//
|
||
// Walk the logon list.
|
||
//
|
||
|
||
while ( pLogonList != &LogonList ) {
|
||
|
||
pLogon = CONTAINING_RECORD( pLogonList, LOGON, Next );
|
||
|
||
//
|
||
// Grab the credential resource to protect the credential list.
|
||
// If we can't have exclusive access to the credential list,
|
||
// don't wait for it or we may deadlock.
|
||
//
|
||
|
||
if ( ExAcquireResourceExclusiveLite( &((pLogon)->CredentialListResource), FALSE ) ) {
|
||
|
||
pCredList = pLogon->NdsCredentialList.Flink;
|
||
|
||
while ( pCredList != &(pLogon->NdsCredentialList) ) {
|
||
BOOLEAN bRemove = FALSE;
|
||
|
||
pCredential = CONTAINING_RECORD( pCredList, NDS_SECURITY_CONTEXT, Next );
|
||
pCredList = pCredential->Next.Flink;
|
||
|
||
if (bShuttingDown) {
|
||
bRemove = TRUE;
|
||
}
|
||
else {
|
||
if ( ( IsCredentialName( &(pCredential->NdsTreeName) ) ) &&
|
||
( pCredential->SupplementalHandleCount == 0 ) ) {
|
||
|
||
//
|
||
// Calculate KillTime.
|
||
//
|
||
|
||
KillTime.QuadPart = Now.QuadPart - ( NwOneSecond * DORMANT_SCB_KEEP_TIME );
|
||
|
||
if ( pCredential->LastUsedTime.QuadPart < KillTime.QuadPart ) {
|
||
bRemove = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
/** If we are supposed to clean this guy up - do it **/
|
||
|
||
if (bRemove) {
|
||
DebugTrace( 0, Dbg, "Removing credentials for %wZ\n", &pCredential->NdsTreeName );
|
||
RemoveEntryList( &pCredential->Next );
|
||
FreeNdsContext( pCredential );
|
||
}
|
||
}
|
||
|
||
ExReleaseResourceLite( &((pLogon)->CredentialListResource) );
|
||
}
|
||
|
||
pLogonList = pLogon->Next.Flink;
|
||
}
|
||
|
||
NwReleaseRcb( &NwRcb );
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
CleanupObjectCache(
|
||
VOID
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
KIRQL OldIrql;
|
||
PLIST_ENTRY ScbEntry;
|
||
PLIST_ENTRY CacheEntry;
|
||
PNONPAGED_SCB NonpagedScb;
|
||
PSCB Scb;
|
||
PNDS_OBJECT_CACHE_ENTRY ObjectCache;
|
||
LARGE_INTEGER CurrentTick;
|
||
|
||
|
||
//
|
||
// Get the current tick count for checking timeouts.
|
||
//
|
||
|
||
KeQueryTickCount( &CurrentTick );
|
||
|
||
//
|
||
// Walk the SCB queue.
|
||
//
|
||
|
||
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
||
|
||
ScbEntry = ScbQueue.Flink;
|
||
|
||
while( ScbEntry != &ScbQueue ) {
|
||
|
||
NonpagedScb = CONTAINING_RECORD( ScbEntry, NONPAGED_SCB, ScbLinks );
|
||
|
||
//
|
||
// Make sure this isn't the permanent SCB.
|
||
//
|
||
|
||
if( NonpagedScb != &NwPermanentNpScb ) {
|
||
|
||
//
|
||
// Reference the SCB so it won't go away when we release the SCB lock.
|
||
//
|
||
|
||
NwReferenceScb( NonpagedScb );
|
||
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
||
|
||
Scb = NonpagedScb->pScb;
|
||
|
||
if( Scb->ObjectCacheBuffer != NULL ) {
|
||
|
||
//
|
||
// Acquire the cache lock so that the cache can be messed with.
|
||
// This wait should never fail, but if it does, act as if there
|
||
// is no cache for this SCB.
|
||
//
|
||
|
||
Status = KeWaitForSingleObject( &(Scb->ObjectCacheLock),
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL );
|
||
|
||
if( NT_SUCCESS(Status) ) {
|
||
|
||
//
|
||
// Walk the object cache and invalidate any timed-out entries.
|
||
//
|
||
|
||
CacheEntry = Scb->ObjectCacheList.Flink;
|
||
|
||
while( CacheEntry != &(Scb->ObjectCacheList) ) {
|
||
|
||
ObjectCache = CONTAINING_RECORD( CacheEntry, NDS_OBJECT_CACHE_ENTRY, Links );
|
||
|
||
//
|
||
// If this entry has timed out, invalidate it.
|
||
//
|
||
|
||
if( ObjectCache->Scb != NULL && CurrentTick.QuadPart < ObjectCache->Timeout.QuadPart ) {
|
||
|
||
NwDereferenceScb( ObjectCache->Scb->pNpScb );
|
||
ObjectCache->Scb = NULL;
|
||
}
|
||
|
||
//
|
||
// Move to the next entry.
|
||
//
|
||
|
||
CacheEntry = CacheEntry->Flink;
|
||
}
|
||
|
||
KeReleaseSemaphore( &(Scb->ObjectCacheLock),
|
||
0,
|
||
1,
|
||
FALSE );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Reacquire the SCB lock and dereference the current SCB.
|
||
//
|
||
|
||
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
||
NwDereferenceScb( NonpagedScb );
|
||
}
|
||
|
||
ScbEntry = ScbEntry->Flink;
|
||
}
|
||
|
||
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
||
return;
|
||
}
|