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

449 lines
12 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
recursvc.c
Abstract:
This module implements the recurrent services in the mini rdr. These are services that
are not triggered as a response to some request from the wrapper, they are autonomous
services that aid in the functioning of the mini redirector.
Scavenging -- The construction of the SMB mini redirector counterparts to SRV_CALL,
NET_ROOT and V_NET_ROOT involve network traffic. Therefore the SMB mini redirector
introduces a hystersis between the deletion of the data structures by the wrapper and
effecting those changes in the mini redirector data structures and the remote server.
This is done by transitioning the deleted data structures to a dormant state and
scavenging them after a suitable interval( approximately 45 sec).
Probing Servers -- Sometimes the server response to a client request is delayed. The
mini redirector has a probing mechanism which enables it to cope with overloaded
servers. When a response is not forthcoming from a server it sends it an ECHO SMB.
Since the server can respond to an ECHO SMB without having to commit many resources,
a reply to the ECHO SMB is interpreted as a sign that the server is indeed alive and
well.
Author:
Balan Sethu Raman [SethuR] 7-March-1995
Revision History:
Notes:
A recurrent service can be either periodic or aperiodic. The periodic services are
triggered at regular time intervals. These services then perform some tasks if
required. The advantage of having periodic recurrent services is the guarantee that
work will get done and the disadvantage is that it consumes system resources when
there is no work to be done. Also if the handling time happens to straddle the
service time period multiple threads wil
An aperiodic recurrent service is a one shot mechanism. The service once invoked gets
to decide when the next invocation will be. The advantage of such services is that
it provides an inbuilt throttling mechanism.
--*/
#include "precomp.h"
#pragma hdrstop
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, MRxSmbInitializeRecurrentService)
#pragma alloc_text(PAGE, MRxSmbCancelRecurrentService)
#pragma alloc_text(PAGE, MRxSmbActivateRecurrentService)
#pragma alloc_text(PAGE, MRxSmbInitializeRecurrentServices)
#pragma alloc_text(PAGE, MRxSmbTearDownRecurrentServices)
#pragma alloc_text(PAGE, MRxSmbInitializeScavengerService)
#pragma alloc_text(PAGE, MRxSmbTearDownScavengerService)
#endif
MRXSMB_ECHO_PROBE_SERVICE_CONTEXT MRxSmbEchoProbeServiceContext;
MRXSMB_SCAVENGER_SERVICE_CONTEXT MRxSmbScavengerServiceContext;
extern VOID
MRxSmbRecurrentServiceDispatcher(
PVOID pContext);
VOID
MRxSmbInitializeRecurrentService(
PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext,
PRECURRENT_SERVICE_ROUTINE pServiceRoutine,
PVOID pServiceRoutineParameter,
PLARGE_INTEGER pTimeInterval)
/*++
Routine Description:
This routine initializes a recurrent service
Arguments:
pRecurrentServiceContext - the recurrent service to be initialized
pServiceRoutine - the recurrent service routine
pServiceRoutineParameter - the recurrent service routine parameter
pTimeInterval - the time interval which controls the frequency of the recurrent
service
--*/
{
NTSTATUS Status;
PAGED_CODE();
pRecurrentServiceContext->State = RECURRENT_SERVICE_DORMANT;
pRecurrentServiceContext->pServiceRoutine = pServiceRoutine;
pRecurrentServiceContext->pServiceRoutineParameter = pServiceRoutineParameter;
pRecurrentServiceContext->Interval.QuadPart = pTimeInterval->QuadPart;
// Initialize the cancel completion event associated with the service
KeInitializeEvent(
&pRecurrentServiceContext->CancelCompletionEvent,
NotificationEvent,
FALSE);
}
VOID
MRxSmbCancelRecurrentService(
PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext)
/*++
Routine Description:
This routine cancels a recurrent service
Arguments:
pRecurrentServiceContext - the recurrent service to be initialized
Notes:
When the cancel request is handled the recurrent service can be in one
of two states -- either active or on the timer queue awaiting dispatch.
The service state is changed and an attempt is made to cancel the service
in the timer queue and if it fails this request is suspended till the
active invocation of the service is completed
--*/
{
NTSTATUS Status;
LONG State;
PAGED_CODE();
State = InterlockedCompareExchange(
&pRecurrentServiceContext->State,
RECURRENT_SERVICE_CANCELLED,
RECURRENT_SERVICE_ACTIVE);
if (State == RECURRENT_SERVICE_ACTIVE) {
// Cancel the echo processing timer request.
Status = RxCancelTimerRequest(
MRxSmbDeviceObject,
MRxSmbRecurrentServiceDispatcher,
pRecurrentServiceContext);
if (Status != STATUS_SUCCESS) {
// The request is currently active. Wait for it to be completed.
KeWaitForSingleObject(
&pRecurrentServiceContext->CancelCompletionEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
}
}
VOID
MRxSmbRecurrentServiceDispatcher(
PVOID pContext)
/*++
Routine Description:
This routine dispatches the recurrent service
Arguments:
pRecurrentServiceContext - the recurrent service to be initialized
Notes:
The dispatcher provides a centralized location for monitoring the state
of the recurrent service prior to and after invocation. Based on the
state a decision as to whether a subsequent request must be posted
is made.
--*/
{
NTSTATUS Status;
PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext;
LONG State;
pRecurrentServiceContext = (PRECURRENT_SERVICE_CONTEXT)pContext;
State = InterlockedCompareExchange(
&pRecurrentServiceContext->State,
RECURRENT_SERVICE_ACTIVE,
RECURRENT_SERVICE_ACTIVE);
// If the state of the service is active invoke the handler
if (State == RECURRENT_SERVICE_ACTIVE) {
Status = (pRecurrentServiceContext->pServiceRoutine)(
pRecurrentServiceContext->pServiceRoutineParameter);
State = InterlockedCompareExchange(
&pRecurrentServiceContext->State,
RECURRENT_SERVICE_ACTIVE,
RECURRENT_SERVICE_ACTIVE);
if (State == RECURRENT_SERVICE_ACTIVE) {
// If the service is still active and further continuation
// was desired by the handler post another timer request
if (Status == STATUS_SUCCESS) {
Status = RxPostOneShotTimerRequest(
MRxSmbDeviceObject,
&pRecurrentServiceContext->WorkItem,
MRxSmbRecurrentServiceDispatcher,
pRecurrentServiceContext,
pRecurrentServiceContext->Interval);
} else {
do {
State = InterlockedCompareExchange(
&pRecurrentServiceContext->State,
RECURRENT_SERVICE_DORMANT,
State);
} while (State != RECURRENT_SERVICE_DORMANT);
}
}
}
if (State == RECURRENT_SERVICE_CANCELLED) {
// if the recurrent service was cancelled resume the cancel request
KeSetEvent(
&pRecurrentServiceContext->CancelCompletionEvent,
0,
FALSE );
}
}
NTSTATUS
MRxSmbActivateRecurrentService(
PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext)
/*++
Routine Description:
This routine activates a recurrent service
Arguments:
pRecurrentServiceContext - the recurrent service to be initialized
Notes:
--*/
{
NTSTATUS Status;
LONG State;
PAGED_CODE();
State = InterlockedCompareExchange(
&pRecurrentServiceContext->State,
RECURRENT_SERVICE_ACTIVE,
RECURRENT_SERVICE_DORMANT);
if (State == RECURRENT_SERVICE_DORMANT) {
Status = RxPostOneShotTimerRequest(
MRxSmbDeviceObject,
&pRecurrentServiceContext->WorkItem,
MRxSmbRecurrentServiceDispatcher,
pRecurrentServiceContext,
pRecurrentServiceContext->Interval);
} else if (State == RECURRENT_SERVICE_ACTIVE) {
Status = STATUS_SUCCESS;
} else if (State == RECURRENT_SERVICE_CANCELLED) {
Status = STATUS_CANCELLED;
}
else if (State == RECURRENT_SERVICE_SHUTDOWN) {
Status = STATUS_UNSUCCESSFUL;
} else {
ASSERT(!"Valid State for Recurrent Service");
Status = STATUS_UNSUCCESSFUL;
}
return Status;
}
NTSTATUS
MRxSmbInitializeRecurrentServices()
/*++
Routine Description:
This routine initializes all the recurrent services associated with the SMB
mini redirector
Notes:
--*/
{
NTSTATUS Status;
LARGE_INTEGER RecurrentServiceInterval;
BOOLEAN fEchoProbeServiceInitialized = FALSE;
BOOLEAN fScavengerServiceInitialized = FALSE;
PAGED_CODE();
try {
RecurrentServiceInterval.QuadPart = 30 * 1000 * 10000; // 30 seconds in 100 ns intervals
MRxSmbInitializeRecurrentService(
&MRxSmbEchoProbeServiceContext.RecurrentServiceContext,
SmbCeProbeServers,
&MRxSmbEchoProbeServiceContext,
&RecurrentServiceInterval);
Status = MRxSmbInitializeEchoProbeService(
&MRxSmbEchoProbeServiceContext);
if (Status == STATUS_SUCCESS) {
fEchoProbeServiceInitialized = TRUE;
Status = MRxSmbActivateRecurrentService(
&MRxSmbEchoProbeServiceContext.RecurrentServiceContext);
}
if (Status != STATUS_SUCCESS) {
try_return(Status);
}
MRxSmbInitializeRecurrentService(
&MRxSmbScavengerServiceContext.RecurrentServiceContext,
SmbCeScavenger,
&MRxSmbScavengerServiceContext,
&RecurrentServiceInterval);
Status = MRxSmbInitializeScavengerService(
&MRxSmbScavengerServiceContext);
if (Status == STATUS_SUCCESS) {
fScavengerServiceInitialized = TRUE;
}
try_exit: NOTHING;
} finally {
if (Status != STATUS_SUCCESS) {
if (fEchoProbeServiceInitialized) {
SmbCeLog(("Tearing down Echo Probe Service\n"));
SmbLogError(Status,
LOG,
MRxSmbInitializeRecurrentServices,
LOGULONG(Status));
MRxSmbTearDownEchoProbeService(
&MRxSmbEchoProbeServiceContext);
}
}
};
return Status;
}
VOID
MRxSmbTearDownRecurrentServices()
/*++
Routine Description:
This routine tears down the recurrent services associated with the
SMB mini redirector
Notes:
--*/
{
PAGED_CODE();
MRxSmbCancelRecurrentService(
&MRxSmbEchoProbeServiceContext.RecurrentServiceContext);
MRxSmbEchoProbeServiceContext.RecurrentServiceContext.State = RECURRENT_SERVICE_SHUTDOWN;
MRxSmbTearDownEchoProbeService(
&MRxSmbEchoProbeServiceContext);
MRxSmbCancelRecurrentService(
&MRxSmbScavengerServiceContext.RecurrentServiceContext);
MRxSmbScavengerServiceContext.RecurrentServiceContext.State = RECURRENT_SERVICE_SHUTDOWN;
MRxSmbTearDownScavengerService(
&MRxSmbScavengerServiceContext);
}
NTSTATUS
MRxSmbInitializeScavengerService(
PMRXSMB_SCAVENGER_SERVICE_CONTEXT pScavengerServiceContext)
/*++
Routine Description:
This routine initializes the scavenger recurrent service
Arguments:
pScavengerServiceContext - the recurrent service to be initialized
Notes:
--*/
{
PAGED_CODE();
InitializeListHead(
&pScavengerServiceContext->VNetRootContexts.ListHead);
return STATUS_SUCCESS;
}
VOID
MRxSmbTearDownScavengerService(
PMRXSMB_SCAVENGER_SERVICE_CONTEXT pScavengerServiceContext)
/*++
Routine Description:
This routine tears down the scavenger recurrent service
Arguments:
pScavengerServiceContext - the recurrent service to be initialized
Notes:
--*/
{
PAGED_CODE();
SmbCeScavenger(pScavengerServiceContext);
}