874 lines
27 KiB
C
874 lines
27 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
|
||
|