windows-nt/Source/XPSP1/NT/base/fs/rdr2/rdbss/smb.mrx/vnrcntxt.c

874 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
smbcedb.c
Abstract:
This module implements all functions related to accessing the SMB connection engine
database
Revision History:
Balan Sethu Raman [SethuR] 6-March-1995
Notes:
The mapping between MRX_V_NET_ROOT and a mini rdr data structure is a many to
one relationship, i.e., more than one MRX_V_NET_ROOT instance can be associated with the
same mini rdr data structure.
--*/
#include "precomp.h"
#pragma hdrstop
#include "exsessup.h"
#include "secext.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, SmbCeCompleteVNetRootContextInitialization)
#pragma alloc_text(PAGE, SmbCeDestroyAssociatedVNetRootContext)
#pragma alloc_text(PAGE, SmbCeTearDownVNetRootContext)
#endif
RXDT_Extern(SMBCEDB);
#define Dbg (DEBUG_TRACE_SMBCEDB)
extern BOOLEAN Win9xSessionRestriction;
PSMBCE_V_NET_ROOT_CONTEXT
SmbCeFindVNetRootContext(
PSMBCE_V_NET_ROOT_CONTEXTS pVNetRootContexts,
PSMBCEDB_SERVER_ENTRY pServerEntry,
PSMBCEDB_SESSION_ENTRY pSessionEntry,
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
BOOLEAN fCscAgentOpen)
/*++
Routine Description:
This routine finds a SMBCE_V_NET_ROOT_CONTEXT instance
Arguments:
pVNetRootContexts - list of VNetRootContexts for searching
PServerEntry - the ServerEntry should be the same as the one on found VNetRootContext
PSessionEntry - the SessionEntry should be the same as the one on found VNetRootContext
pNetRootEntry - the NetRootEntry should be the same as the one on found VNetRootContext
fCscAgentOpen - this V_NET_ROOT_CONTEXT instance is being created for the CSC
agent
Return Value:
VNetRootContext if found
Notes:
--*/
{
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
pVNetRootContext = SmbCeGetFirstVNetRootContext(
pVNetRootContexts);
while (pVNetRootContext != NULL) {
if ((pVNetRootContext->pServerEntry == pServerEntry) &&
(pVNetRootContext->pSessionEntry == pSessionEntry) &&
(pVNetRootContext->pNetRootEntry == pNetRootEntry) &&
(BooleanFlagOn(pVNetRootContext->Flags,
SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE) == fCscAgentOpen)) {
SmbCeRemoveVNetRootContext(
pVNetRootContexts,
pVNetRootContext);
SmbCeAddVNetRootContext(
&pServerEntry->VNetRootContexts,
pVNetRootContext);
InterlockedDecrement(&pServerEntry->Server.NumberOfVNetRootContextsForScavenging);
SmbCeLog(("CachedVNRContext(S) %lx\n",pVNetRootContext));
SmbLog(LOG,
SmbCeFindVNetRootContext,
LOGPTR(pVNetRootContext));
break;
} else {
pVNetRootContext = SmbCeGetNextVNetRootContext(
pVNetRootContexts,
pVNetRootContext);
}
}
return pVNetRootContext;
}
NTSTATUS
SmbCeFindOrConstructVNetRootContext(
PMRX_V_NET_ROOT pVNetRoot,
BOOLEAN fDeferNetworkInitialization,
BOOLEAN fCscAgentOpen)
/*++
Routine Description:
This routine finds or constructs a SMBCE_V_NET_ROOT_CONTEXT instance
Arguments:
pVNetRoot - the MRX_V_NET_ROOT instance
fDeferNetworkInitialization - a directive to delay network initialization for new
instances.
fCscAgentOpen - this V_NET_ROOT_CONTEXT instance is being created for the CSC
agent
Return Value:
STATUS_SUCCESS if the MRX_V_NET_ROOT instance was successfully initialized
Notes:
The algorithm that has been implemented tries to delay the construction of a
new instance as much as possible. It does this be either reusing a context
that has already been active or a context instance that has been marked for
scavenging but has not been scavenged.
--*/
{
NTSTATUS Status;
PMRX_SRV_CALL pSrvCall;
PMRX_NET_ROOT pNetRoot;
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL;
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
BOOLEAN fInitializeNetRoot;
BOOLEAN fDereferenceSessionEntry = FALSE;
BOOLEAN fDereferenceNetRootEntry = FALSE;
pNetRoot = pVNetRoot->pNetRoot;
pSrvCall = pNetRoot->pSrvCall;
SmbCeAcquireResource();
pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
// The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as
// follows
// 1) the V_NET_ROOT and the associated NET_ROOT are being newly created.
// 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created.
//
// These two cases can be distinguished by checking if the context associated with
// NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized
// by the wrapper this is a safe check.
// ( The wrapper cannot have more then one thread tryingto initialize the same
// NET_ROOT).
pNetRootEntry = (PSMBCEDB_NET_ROOT_ENTRY)pNetRoot->Context;
fInitializeNetRoot = (pNetRootEntry == NULL);
pVNetRoot->Context = NULL;
// Find or construct the session entry that will be associated with the context. The
// one error that deserves special consideration is STATUS_NETWORK_CREDENTIAL_CONFLICT.
// This error signifies that the credentials presented with the MRX_V_NET_ROOT instance
// conflicted with an existing session. This conflict could be either becuase there
// exists an active session or because a previously active session is awaiting
// scavenging. In the former case the error needs to be propagated back but in the
// later case the contexts must be selectively scavenged.
//
// The scavenging should be limited only to those contexts to the appropriate server.
Status = SmbCeFindOrConstructSessionEntry(
pVNetRoot,
&pSessionEntry);
if (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT) {
NTSTATUS ScavengingStatus;
SmbCeReleaseResource();
ScavengingStatus = SmbCeScavengeRelatedContexts(pServerEntry);
if (ScavengingStatus == STATUS_SUCCESS) {
SmbCeAcquireResource();
Status = SmbCeFindOrConstructSessionEntry(
pVNetRoot,
&pSessionEntry);
} else {
return Status;
}
}
fDereferenceSessionEntry = (Status == STATUS_SUCCESS);
if (Status == STATUS_SUCCESS) {
if (fInitializeNetRoot) {
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
// Initialize the device type and state for a new MRX_NET_ROOT instance
switch (pNetRoot->Type) {
case NET_ROOT_DISK:
{
pNetRoot->DeviceType = RxDeviceType(DISK);
RxInitializeNetRootThrottlingParameters(
&pNetRoot->DiskParameters.LockThrottlingParameters,
MRxSmbConfiguration.LockIncrement,
MRxSmbConfiguration.MaximumLock
);
}
break;
case NET_ROOT_PIPE:
{
pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
RxInitializeNetRootThrottlingParameters(
&pNetRoot->NamedPipeParameters.PipeReadThrottlingParameters,
MRxSmbConfiguration.PipeIncrement,
MRxSmbConfiguration.PipeMaximum
);
}
break;
case NET_ROOT_COMM:
pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
break;
case NET_ROOT_PRINT:
pNetRoot->DeviceType = RxDeviceType(PRINTER);
break;
case NET_ROOT_MAILSLOT:
pNetRoot->DeviceType = RxDeviceType(MAILSLOT);
break;
case NET_ROOT_WILD:
break;
default:
ASSERT(!"Valid Net Root Type");
}
Status = SmbCeFindOrConstructNetRootEntry(
pNetRoot,
&pNetRootEntry);
RxDbgTrace( 0, Dbg, ("SmbCeOpenNetRoot %lx\n",Status));
} else {
SmbCeLog(("ReuseNREntry %lx\n",pNetRootEntry));
SmbLog(LOG,
SmbCeFindOrConstructVNetRootContext_1,
LOGPTR(pNetRootEntry));
SmbCeReferenceNetRootEntry(pNetRootEntry);
}
fDereferenceNetRootEntry = (Status == STATUS_SUCCESS);
}
if (Status == STATUS_SUCCESS) {
pVNetRootContext = SmbCeFindVNetRootContext(
&pServerEntry->VNetRootContexts,
pServerEntry,
pSessionEntry,
pNetRootEntry,
fCscAgentOpen);
if (pVNetRootContext == NULL) {
pVNetRootContext = SmbCeFindVNetRootContext(
&MRxSmbScavengerServiceContext.VNetRootContexts,
pServerEntry,
pSessionEntry,
pNetRootEntry,
fCscAgentOpen);
}
if (pVNetRootContext != NULL) {
// An existing instance can be reused. No more work to be done
SmbCeReferenceVNetRootContext(pVNetRootContext);
} else {
// None of the existing instances can be reused. A new instance needs to be
// constructed.
pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)
RxAllocatePoolWithTag(
NonPagedPool,
sizeof(SMBCE_V_NET_ROOT_CONTEXT),
MRXSMB_VNETROOT_POOLTAG);
if (pVNetRootContext != NULL) {
// Initialize the new instance
RtlZeroMemory(
pVNetRootContext,
sizeof(SMBCE_V_NET_ROOT_CONTEXT));
// Transfer the references made during the construction of the session and
// the net root entries to the new context. Disable the dereferencing at
// the end of this routine.
fDereferenceSessionEntry = FALSE;
fDereferenceNetRootEntry = FALSE;
SmbCeReferenceServerEntry(pServerEntry);
pVNetRootContext->Header.NodeType = SMB_CONNECTION_ENGINE_NTC(
SMBCEDB_OT_VNETROOTCONTEXT);
if (pNetRootEntry->NetRoot.NetRootType == NET_ROOT_MAILSLOT) {
pVNetRootContext->Header.State = SMBCEDB_ACTIVE;
} else {
pVNetRootContext->Header.State = SMBCEDB_INVALID;
}
pVNetRootContext->Flags = 0;
if (fCscAgentOpen) {
pVNetRootContext->Flags |= SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE;
}
InitializeListHead(&pVNetRootContext->Requests.ListHead);
pVNetRootContext->pServerEntry = pServerEntry;
pVNetRootContext->pSessionEntry = pSessionEntry;
pVNetRootContext->pNetRootEntry = pNetRootEntry;
SmbCeReferenceVNetRootContext(pVNetRootContext);
// Add it to the list of active contexts
SmbCeAddVNetRootContext(
&pServerEntry->VNetRootContexts,
pVNetRootContext);
SmbCeLog(("NewVNetRootContext %lx\n",pVNetRootContext));
SmbLog(LOG,
SmbCeFindOrConstructVNetRootContext_2,
LOGPTR(pVNetRootContext));
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
if (Status == STATUS_SUCCESS) {
// If everything was successful set up the MRX_V_NET_ROOT and MRX_NET_ROOT
// instances
pVNetRoot->Context = pVNetRootContext;
pVNetRootContext->pRdbssVNetRoot = pVNetRoot;
if (fInitializeNetRoot) {
ASSERT(pNetRootEntry->pRdbssNetRoot == NULL);
InterlockedExchangePointer(
&pNetRootEntry->pRdbssNetRoot,
pNetRoot);
SmbCeUpdateNetRoot(pNetRootEntry,pNetRoot);
SmbCeReferenceNetRootEntry(pNetRootEntry);
pNetRoot->Context = pNetRootEntry;
} else {
if (FlagOn(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED)) {
ClearFlag(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED);
SmbCeReferenceNetRootEntry(pNetRootEntry);
}
}
InterlockedIncrement(&pSessionEntry->Session.NumberOfActiveVNetRoot);
} else {
pVNetRoot->Context = NULL;
if (fInitializeNetRoot) {
pNetRoot->Context = NULL;
}
}
SmbCeReleaseResource();
if (fDereferenceSessionEntry) {
SmbCeDereferenceSessionEntry(pSessionEntry);
}
if (fDereferenceNetRootEntry) {
SmbCeDereferenceNetRootEntry(pNetRootEntry);
}
if (!fDeferNetworkInitialization &&
(Status == STATUS_SUCCESS)) {
Status = STATUS_MORE_PROCESSING_REQUIRED;
}
if (SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER) {
ASSERT((Status != STATUS_SUCCESS) || (pVNetRoot->Context != NULL));
}
return Status;
}
VOID
SmbCeCompleteVNetRootContextInitialization(
PVOID pContext)
/*++
Routine Description:
This routine is invoked in the context of a worker thread to finalize the
construction of a SMBCE_V_NET_ROOT_CONTEXT instance
Arguments:
pContext - the SMBCE_V_NET_ROOT_CONTEXT instance
Notes:
PRE_CONDITION: The VNetRootContext must have been referenced to ensure that
even it has been finalized it will not be deleted.
--*/
{
NTSTATUS Status;
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
PSMBCEDB_REQUEST_ENTRY pRequestEntry;
SMBCEDB_REQUESTS Requests;
PAGED_CODE();
RxDbgTrace( 0, Dbg, ("Net Root Entry Finalization\n"));
pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)pContext;
ASSERT(pVNetRootContext->Header.ObjectType == SMBCEDB_OT_VNETROOTCONTEXT);
SmbCeAcquireResource();
pVNetRootContext->pExchange = NULL;
SmbCeTransferRequests(&Requests,&pVNetRootContext->Requests);
if (pVNetRootContext->Header.State == SMBCEDB_ACTIVE) {
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INVALID_CONNECTION;
SmbCeUpdateVNetRootContextState(
pVNetRootContext,
SMBCEDB_INVALID);
}
SmbCeReleaseResource();
// Iterate over the list of pending requests and resume all of them
SmbCeResumeOutstandingRequests(&Requests,Status);
SmbCeDereferenceVNetRootContext(pVNetRootContext);
}
VOID
SmbCepDereferenceVNetRootContext(
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext)
/*++
Routine Description:
This routine dereferences a SMBCE_V_NET_ROOT_CONTEXT instance
Arguments:
pVNetRootContext - the SMBCE_V_NET_ROOT_CONTEXT instance
Notes:
There are two intersting points to note. A mini redirector can avoid potential
network traffic by delaying the scavenging of the SMBCE_V_NET_ROOT_CONTEXT
instance since it contains all the relevant network setup to satisfy requests.
This is a policy that is implemented in the mini redirector and is different from
the wrapper policies.
Once the decision to delay scavenging has been made, there are two options. The
successful and unsuccessful instances can be delayed or only the successful
instances. The current algorithm is to delay the scavenging of the successful
SMBCE_V_NET_ROOT_CONTEXT instances only.
Also there are three components to a VNetRootContext that can be scavenged
independently. If the server exists and a session setup to the server fails
because of wrong credentials there is no point in throwing away the server
entry eagerly. This routine selectively gathers the failed fields for eager
scavenging and retains the VNetRootContext skeleton alongwith the other
structures that can be deferred.
--*/
{
if (pVNetRootContext != NULL) {
LONG FinalRefCount;
FinalRefCount = InterlockedDecrement(
&pVNetRootContext->Header.SwizzleCount);
if (FinalRefCount == 0) {
LARGE_INTEGER CurrentTime;
BOOLEAN TearDownVNetRootContext = FALSE;
PSMBCE_SERVER pServer = &pVNetRootContext->pServerEntry->Server;
PSMBCE_SESSION pSession = &pVNetRootContext->pSessionEntry->Session;
SmbCeAcquireResource();
if (pVNetRootContext->Header.SwizzleCount == 0) {
// Remove the instance from the active list of contexts to the server.
SmbCeRemoveVNetRootContext(
&pVNetRootContext->pSessionEntry->pServerEntry->VNetRootContexts,
pVNetRootContext);
// if it was a successful instance mark it for scavenging, otherwise
// tear it down immediately
if ((pVNetRootContext->pSessionEntry != NULL) &&
(pVNetRootContext->pSessionEntry->Header.State != SMBCEDB_ACTIVE ||
pSession->pUserName != NULL ||
pSession->pPassword != NULL ||
pSession->pUserDomainName != NULL)) {
TearDownVNetRootContext = TRUE;
}
if ((pVNetRootContext->pNetRootEntry != NULL) &&
(pVNetRootContext->pNetRootEntry->Header.State != SMBCEDB_ACTIVE ||
TearDownVNetRootContext)) {
TearDownVNetRootContext = TRUE;
}
if (Win9xSessionRestriction &&
(pVNetRootContext->pServerEntry != NULL) &&
FlagOn(pVNetRootContext->pServerEntry->Server.DialectFlags,DF_W95)) {
TearDownVNetRootContext = TRUE;
}
InterlockedIncrement(&pServer->NumberOfVNetRootContextsForScavenging);
if (!TearDownVNetRootContext &&
(pVNetRootContext->pNetRootEntry != NULL) &&
(pVNetRootContext->pSessionEntry != NULL) &&
pServer->NumberOfVNetRootContextsForScavenging < MaximumNumberOfVNetRootContextsForScavenging) {
ClearFlag(pVNetRootContext->Flags, SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE);
KeQueryTickCount( &CurrentTime );
pVNetRootContext->ExpireTime.QuadPart = CurrentTime.QuadPart +
(LONGLONG) ((MRXSMB_V_NETROOT_CONTEXT_SCAVENGER_INTERVAL * 10 * 1000 * 1000) / KeQueryTimeIncrement());
SmbCeAddVNetRootContext(
&MRxSmbScavengerServiceContext.VNetRootContexts,
pVNetRootContext);
MRxSmbActivateRecurrentService(
(PRECURRENT_SERVICE_CONTEXT)&MRxSmbScavengerServiceContext);
SmbCeLog(("ScavngVNetRootCntxt %lx\n",pVNetRootContext));
SmbLog(LOG,
SmbCepDereferenceVNetRootContext,
LOGPTR(pVNetRootContext));
} else {
TearDownVNetRootContext = TRUE;
}
}
SmbCeReleaseResource();
if (TearDownVNetRootContext) {
pVNetRootContext->Header.State = SMBCEDB_MARKED_FOR_DELETION;
SmbCeTearDownVNetRootContext(pVNetRootContext);
}
}
}
}
NTSTATUS
SmbCeDestroyAssociatedVNetRootContext(
PMRX_V_NET_ROOT pVNetRoot)
/*++
Routine Description:
This routine derferences a SMBCE_V_NET_ROOT_CONTEXT instance
Arguments:
pVNetRootContext - the SMBCE_V_NET_ROOT_CONTEXT instance to be dereferenced
--*/
{
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
PAGED_CODE();
pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)pVNetRoot->Context;
if (pVNetRootContext != NULL) {
pVNetRootContext->pRdbssVNetRoot = NULL;
SmbCeDecrementNumberOfActiveVNetRootOnSession(pVNetRootContext);
SmbCeDereferenceVNetRootContext(pVNetRootContext);
}
pVNetRoot->Context = NULL;
return STATUS_SUCCESS;
}
VOID
SmbCeTearDownVNetRootContext(
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext)
/*++
Routine Description:
This routine tears down a SMBCE_V_NET_ROOT_CONTEXT instance
Arguments:
pVNetRootContext - the SMBCE_V_NET_ROOT_CONTEXT instance to be torn down
--*/
{
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
PAGED_CODE();
SmbCeLog(("TearVNetRootContext %lx\n",pVNetRootContext));
SmbLog(LOG,
SmbCeTearDownVNetRootContext,
LOGPTR(pVNetRootContext));
pNetRootEntry = pVNetRootContext->pNetRootEntry;
if ((pNetRootEntry != NULL) &&
BooleanFlagOn(pVNetRootContext->Flags,SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID) &&
(SmbCeGetServerType(pVNetRootContext->pServerEntry) == SMBCEDB_FILE_SERVER)) {
SmbCeDisconnect(pVNetRootContext);
}
if (pNetRootEntry != NULL) {
pVNetRootContext->pNetRootEntry = NULL;
SmbCeDereferenceNetRootEntry(pNetRootEntry);
}
if (pVNetRootContext->pSessionEntry != NULL) {
SmbCeDereferenceSessionEntry(pVNetRootContext->pSessionEntry);
}
InterlockedDecrement(&pVNetRootContext->pServerEntry->Server.NumberOfVNetRootContextsForScavenging);
SmbCeDereferenceServerEntry(pVNetRootContext->pServerEntry);
RxFreePool(pVNetRootContext);
}
NTSTATUS
SmbCeScavenger(
PVOID pContext)
/*++
Routine Description:
This routine scavenges SMBCE_V_NET_ROOT_CONTEXT instances
Arguments:
pContext - the scavenger service context
Notes:
Since the contexts for scavenging are threaded together in an entry that
is managed in a FIFO fashion, if the first entry fails the time interval
test ( expiry time has not elapsed ) all the other entries in the list
are guaranteed to fail the test. This is an important property that eases
the implementation of scavenging.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PMRXSMB_SCAVENGER_SERVICE_CONTEXT pScavengerServiceContext;
LARGE_INTEGER CurrentTime;
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
BOOLEAN fTerminateScavenging = FALSE;
pScavengerServiceContext = (PMRXSMB_SCAVENGER_SERVICE_CONTEXT)pContext;
do {
SmbCeAcquireResource();
KeQueryTickCount( &CurrentTime );
pVNetRootContext = SmbCeGetFirstVNetRootContext(
&pScavengerServiceContext->VNetRootContexts);
fTerminateScavenging = (pVNetRootContext == NULL);
if (!fTerminateScavenging) {
if ((CurrentTime.QuadPart >= pVNetRootContext->ExpireTime.QuadPart) ||
(pScavengerServiceContext->RecurrentServiceContext.State == RECURRENT_SERVICE_SHUTDOWN)) {
SmbCeRemoveVNetRootContext(
&pScavengerServiceContext->VNetRootContexts,
pVNetRootContext);
} else {
fTerminateScavenging = TRUE;
}
}
SmbCeReleaseResource();
if (!fTerminateScavenging &&
(pVNetRootContext != NULL)) {
SmbCeTearDownVNetRootContext(pVNetRootContext);
}
} while (!fTerminateScavenging);
return Status;
}
NTSTATUS
SmbCeScavengeRelatedContexts(
PSMBCEDB_SERVER_ENTRY pServerEntry)
/*++
Routine Description:
This routine scavenges SMBCE_V_NET_ROOT_CONTEXT instances for a given
server entry
Arguments:
pServerEntry - the server entry
Notes:
--*/
{
NTSTATUS Status;
SMBCE_V_NET_ROOT_CONTEXTS VNetRootContexts;
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
InitializeListHead(&VNetRootContexts.ListHead);
SmbCeAcquireResource();
pVNetRootContext = SmbCeGetFirstVNetRootContext(
&MRxSmbScavengerServiceContext.VNetRootContexts);
while (pVNetRootContext != NULL) {
PSMBCE_V_NET_ROOT_CONTEXT pNextVNetRootContext;
pNextVNetRootContext = SmbCeGetNextVNetRootContext(
&MRxSmbScavengerServiceContext.VNetRootContexts,
pVNetRootContext);
if (pVNetRootContext->pServerEntry == pServerEntry) {
SmbCeRemoveVNetRootContext(
&MRxScavengerServiceContext.VNetRootContexts,
pVNetRootContext);
SmbCeAddVNetRootContext(
&VNetRootContexts,
pVNetRootContext);
}
pVNetRootContext = pNextVNetRootContext;
}
SmbCeReleaseResource();
pVNetRootContext = SmbCeGetFirstVNetRootContext(
&VNetRootContexts);
if (pVNetRootContext != NULL) {
do {
SmbCeRemoveVNetRootContext(
&VNetRootContexts,
pVNetRootContext);
SmbCeTearDownVNetRootContext(pVNetRootContext);
pVNetRootContext = SmbCeGetFirstVNetRootContext(
&VNetRootContexts);
} while ( pVNetRootContext != NULL );
Status = STATUS_SUCCESS;
} else {
Status = STATUS_UNSUCCESSFUL;
}
SmbCeLog(("Scavctxts Srv %lx Status %lx\n",pServerEntry,Status));
SmbLog(LOG,
SmbCeScavengeRelatedContexts,
LOGULONG(Status)
LOGPTR(pServerEntry)
LOGUSTR(pServerEntry->Name));
return Status;
}
VOID
SmbCeDecrementNumberOfActiveVNetRootOnSession(
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext
)
{
ULONG NumberOfVNetRoot;
BOOLEAN fLogOffRequired = FALSE;
PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL;
SmbCeAcquireResource();
NumberOfVNetRoot = InterlockedDecrement(&pVNetRootContext->pSessionEntry->Session.NumberOfActiveVNetRoot);
if (NumberOfVNetRoot == 0) {
pSessionEntry = pVNetRootContext->pSessionEntry;
pServerEntry = pVNetRootContext->pServerEntry;
if (!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) {
SmbCeRemoveSessionEntry(pServerEntry,pSessionEntry);
SmbCeRemoveDefaultSessionEntry(pSessionEntry);
}
if ((pSessionEntry->Session.UserId != (SMB_USER_ID)(SMBCE_SHARE_LEVEL_SERVER_USERID)) &&
(pSessionEntry->Session.UserId != 0) &&
(pSessionEntry->Header.State == SMBCEDB_ACTIVE) &&
!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) {
SmbCeReferenceServerEntry(pServerEntry);
SmbCeReferenceSessionEntry(pSessionEntry);
fLogOffRequired = TRUE;
}
// all the consequent requests on this session should fail
pSessionEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_LOGGED_OFF;
pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION;
}
SmbCeReleaseResource();
if (fLogOffRequired) {
SmbCeLogOff(pServerEntry,pSessionEntry);
SmbCeDereferenceServerEntry(pServerEntry);
}
}