439 lines
13 KiB
C
439 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
strtstop.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the Start and Stop routines for the wrapper.
|
||
|
||
Author:
|
||
|
||
Balan Sethu Raman [SethuR] 27-Jan-1996
|
||
|
||
Revision History:
|
||
|
||
Notes:
|
||
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
#include <ntddnfs2.h>
|
||
#include <ntddmup.h>
|
||
#include "fsctlbuf.h"
|
||
#include "prefix.h"
|
||
#include "rxce.h"
|
||
|
||
//
|
||
// The local trace mask for this part of the module
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_DEVFCB)
|
||
|
||
//
|
||
// Forward declarations
|
||
//
|
||
|
||
|
||
VOID
|
||
RxDeregisterUNCProvider(
|
||
PRDBSS_DEVICE_OBJECT RxDeviceObject
|
||
);
|
||
|
||
VOID
|
||
RxUnstart(
|
||
PRX_CONTEXT RxContext,
|
||
PRDBSS_DEVICE_OBJECT RxDeviceObject
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, RxDeregisterUNCProvider)
|
||
#pragma alloc_text(PAGE, RxUnstart)
|
||
#pragma alloc_text(PAGE, RxSetDomainForMailslotBroadcast)
|
||
#endif
|
||
|
||
//
|
||
// There are three states associated with each minirdr w.r.t the Start/Stop sequence.
|
||
// These are
|
||
// RDBSS_STARTABLE
|
||
// - This is the initial state and also the one intowhich a minirdr transitions
|
||
// after a successful stop.
|
||
//
|
||
// RDBSS_STARTED
|
||
// - A transition to this state occurs after the startup sequence has been
|
||
// successfully completed. This is the state in which the minirdr is active.
|
||
//
|
||
// RDBSS_STOP_IN_PROGRESS
|
||
// - A transition to this state occurs when a shutdown sequence has been initiated.
|
||
//
|
||
//
|
||
// A minirdr can be started and stopped independent of the system by invoking
|
||
// the appropriate command through the workstation service. The
|
||
// Start/Stop functionality is different from the Load/UnLoad functionality, i.e., it
|
||
// is possible to stop a mini redirectors without unloading it.
|
||
//
|
||
// The data structures associated with the RDBSS can be classified into two categories
|
||
// 1) those maintained by the RDBSS and visible to all the mini redirectors or private
|
||
// and 2) those that are mainitained by the RDBSS and visible to the I/O subsystem.
|
||
// The NET_ROOT,VNET_ROOT, SRV_CALL etc. are examples of the first category while
|
||
// FCB's,FOBX's(File Object extensions ) are examples of the second category.
|
||
// None of these data structures can be unilaterally destroyed by the RDBSS -- those
|
||
// in category 1 must be destroyed in coordination with the mini redirectors while
|
||
// those in category 2 must be done in coordination with the I/O subsystem.
|
||
//
|
||
// The destruction of the data structures can be initiated by the RDBSS while those
|
||
// in the second category cannot be initiated by the RDBSS. Hence the shutdown
|
||
// sequence has to make provisions for handling them differently.
|
||
//
|
||
// A shutdown sequence can be successfully completed ( so that the driver can be
|
||
// unloaded ) if there are no residual instances in category 2, i.e., there are no
|
||
// open file handles or references to file objects from the other system components.
|
||
//
|
||
// If there are any residual references, the corresponding instances are marked as
|
||
// having been orphaned. The only permissible operations on orphaned instances are
|
||
// close and cleanup. The mini redirector close/cleanup operations must make special
|
||
// provisions for dealing with orphaned instances. All other operations are short
|
||
// circuited with an error status by the wrapper.
|
||
//
|
||
|
||
VOID
|
||
RxUnstart(
|
||
PRX_CONTEXT RxContext,
|
||
PRDBSS_DEVICE_OBJECT RxDeviceObject
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
|
||
ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP));
|
||
|
||
if (RxDeviceObject->MupHandle != (HANDLE)0) {
|
||
RxDbgTrace(0, Dbg, ("RxDeregisterUNCProvider derigistering from MUP %wZ\n", &RxDeviceObject->DeviceName));
|
||
FsRtlDeregisterUncProvider(RxDeviceObject->MupHandle);
|
||
RxDeviceObject->MupHandle = (HANDLE)0;
|
||
}
|
||
|
||
if (RxDeviceObject->RegisteredAsFileSystem) {
|
||
IoUnregisterFileSystem((PDEVICE_OBJECT)RxDeviceObject);
|
||
}
|
||
|
||
if (RxData.NumberOfMinirdrsStarted==1) {
|
||
|
||
RxForceNetTableFinalization(RxDeviceObject);
|
||
RxData.NumberOfMinirdrsStarted = 0;
|
||
|
||
// Get rid of buffers that have been allocated.
|
||
if (s_PrimaryDomainName.Buffer != NULL) {
|
||
RxFreePool(s_PrimaryDomainName.Buffer);
|
||
s_PrimaryDomainName.Length = 0;
|
||
s_PrimaryDomainName.Buffer = NULL;
|
||
}
|
||
|
||
} else {
|
||
InterlockedDecrement(&RxData.NumberOfMinirdrsStarted);
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
RxSetDomainForMailslotBroadcast (
|
||
IN PUNICODE_STRING DomainName
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (s_PrimaryDomainName.Buffer!=NULL) {
|
||
RxFreePool(s_PrimaryDomainName.Buffer);
|
||
}
|
||
|
||
RxLog(("DomainName=%wZ",DomainName));
|
||
RxWmiLog(LOG,
|
||
RxSetDomainForMailslotBroadcast_1,
|
||
LOGUSTR(*DomainName));
|
||
s_PrimaryDomainName.Length = (USHORT)DomainName->Length;
|
||
s_PrimaryDomainName.MaximumLength = s_PrimaryDomainName.Length;
|
||
|
||
if (s_PrimaryDomainName.Length > 0) {
|
||
s_PrimaryDomainName.Buffer = RxAllocatePoolWithTag(
|
||
PagedPool | POOL_COLD_ALLOCATION,
|
||
s_PrimaryDomainName.Length,
|
||
RX_MISC_POOLTAG);
|
||
|
||
if (s_PrimaryDomainName.Buffer == NULL) {
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
} else {
|
||
RtlCopyMemory(
|
||
s_PrimaryDomainName.Buffer,
|
||
DomainName->Buffer,
|
||
s_PrimaryDomainName.Length);
|
||
|
||
RxLog(("CapturedDomainName=%wZ",&s_PrimaryDomainName));
|
||
RxWmiLog(LOG,
|
||
RxSetDomainForMailslotBroadcast_2,
|
||
LOGUSTR(s_PrimaryDomainName));
|
||
}
|
||
} else {
|
||
s_PrimaryDomainName.Buffer = NULL;
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
NTSTATUS
|
||
RxStartMinirdr (
|
||
IN PRX_CONTEXT RxContext,
|
||
OUT PBOOLEAN PostToFsp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine starts up the calling minirdr by registering as an UNC
|
||
provider with the MUP.
|
||
|
||
Arguments:
|
||
|
||
RxContext - Describes the Context. the context is used to get the device object and to tell if we're in the fsp.
|
||
|
||
PostToFsp - set to TRUE if the request has to be posted
|
||
|
||
Return Value:
|
||
|
||
RxStatus(SUCCESS) -- the Startup sequence was successfully completed.
|
||
|
||
any other value indicates the appropriate error in the startup sequence.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
|
||
|
||
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
||
BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
|
||
|
||
BOOLEAN SuppressUnstart = FALSE;
|
||
|
||
RxDbgTrace(0, Dbg, ("RxStartMinirdr [Start] -> %08lx\n", 0));
|
||
|
||
// The startup sequence cannot be completed because there are certain aspects of
|
||
// security and transport initialization that require handles. Since handles are
|
||
// tied to a process the RDBSS needs to present an anchoring point to all the mini
|
||
// redirectors. So the initialization will be completed in the context of the
|
||
// FSP ( system process since RDBSS does not have its own FSP)
|
||
|
||
if (InFSD) {
|
||
SECURITY_SUBJECT_CONTEXT SubjectContext;
|
||
|
||
SeCaptureSubjectContext(&SubjectContext);
|
||
RxContext->FsdUid = RxGetUid( &SubjectContext );
|
||
SeReleaseSubjectContext(&SubjectContext);
|
||
|
||
*PostToFsp = TRUE;
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait)) {
|
||
*PostToFsp = TRUE;
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
if (!RxAcquirePrefixTableLockExclusive( RxContext->RxDeviceObject->pRxNetNameTable, Wait)) {
|
||
ASSERT(!"How can the wait fail?????");
|
||
ExReleaseResourceLite(&RxData.Resource);
|
||
*PostToFsp = TRUE;
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
try {
|
||
|
||
if (RxDeviceObject->MupHandle != NULL) {
|
||
RxDbgTrace(0, Dbg, ("RxStartMinirdr [Already] -> %08lx\n", 0));
|
||
SuppressUnstart = TRUE;
|
||
try_return(Status = STATUS_REDIRECTOR_STARTED);
|
||
}
|
||
|
||
if (RxDeviceObject->RegisterUncProvider) {
|
||
Status = FsRtlRegisterUncProvider(
|
||
&RxDeviceObject->MupHandle,
|
||
&RxDeviceObject->DeviceName,
|
||
RxDeviceObject->RegisterMailSlotProvider
|
||
);
|
||
|
||
if (Status!=STATUS_SUCCESS) {
|
||
RxDeviceObject->MupHandle = (HANDLE)0;
|
||
try_return(Status);
|
||
}
|
||
} else {
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
IoRegisterFileSystem((PDEVICE_OBJECT)RxDeviceObject);
|
||
|
||
RxDeviceObject->RegisteredAsFileSystem = TRUE;
|
||
|
||
MINIRDR_CALL(Status,
|
||
RxContext,
|
||
RxDeviceObject->Dispatch,
|
||
MRxStart,
|
||
(RxContext,RxDeviceObject));
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
RxDeviceObject->StartStopContext.Version++;
|
||
RxSetRdbssState(RxDeviceObject,RDBSS_STARTED);
|
||
InterlockedIncrement(&RxData.NumberOfMinirdrsStarted);
|
||
Status = RxInitializeMRxDispatcher(RxDeviceObject);
|
||
}
|
||
|
||
try_return(Status);
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
|
||
if (AbnormalTermination() || !NT_SUCCESS(Status)){
|
||
if (!SuppressUnstart) {
|
||
RxUnstart(RxContext,RxDeviceObject);
|
||
}
|
||
}
|
||
|
||
RxReleasePrefixTableLock( RxContext->RxDeviceObject->pRxNetNameTable );
|
||
ExReleaseResourceLite(&RxData.Resource);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
RxStopMinirdr (
|
||
IN PRX_CONTEXT RxContext,
|
||
OUT PBOOLEAN PostToFsp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine stops a minirdr....a stopped minirdr will no longer accept new commands.
|
||
|
||
Arguments:
|
||
|
||
RxContext - the context
|
||
|
||
PostToFsp - the flag when set delays processing to the FSP.
|
||
|
||
Return Value:
|
||
|
||
the Status of the STOP operaion ...
|
||
|
||
STATUS_PENDING -- processing delayed to FSP
|
||
|
||
STATUS_REDIRECTOR_HAS_OPEN_HANDLES -- cannot be stopped at this time
|
||
|
||
Notes:
|
||
|
||
When a STOP request is issued to RDBSS there are ongoing requests in the
|
||
RDBSS. Some of the requests can be cancelled while the remaining requests
|
||
need to be processed to completion.
|
||
|
||
There are a number of strategies that can be employed to close down the
|
||
RDBSS. Currently, the most conservative approach is employed. The
|
||
cancellation of those operations that can be cancelled and the STOP
|
||
operation is held back till the remaining requests run through to completion.
|
||
|
||
Subsequently, this will be revised so that the response times to STOP requests
|
||
are smaller.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
||
BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
|
||
|
||
PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
|
||
|
||
RxDbgTrace(0, Dbg, ("RxStopMinirdr [Stop] -> %08lx\n", 0));
|
||
|
||
if (InFSD) {
|
||
*PostToFsp = TRUE;
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
if (!ExAcquireResourceExclusiveLite(&RxData.Resource, Wait)) {
|
||
*PostToFsp = TRUE;
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
try {
|
||
|
||
KIRQL SavedIrql;
|
||
BOOLEAN fWait;
|
||
|
||
ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP));
|
||
|
||
|
||
if (RxDeviceObject->StartStopContext.State!=RDBSS_STARTED){
|
||
RxDbgTrace(0, Dbg, ("RxStopMinirdr [Notstarted] -> %08lx\n", 0));
|
||
try_return ( Status = STATUS_REDIRECTOR_NOT_STARTED );
|
||
}
|
||
// Wait for all the ongoing requests to be completed. When the RDBSS is
|
||
// transitioned to the STOPPED state the last context to be completed
|
||
// will complete the wait.
|
||
|
||
// Terminate all the scavenging operations.
|
||
RxTerminateScavenging(RxContext);
|
||
|
||
RxDbgPrint(("Waiting for all contexts to be flushed\n"));
|
||
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
||
RemoveEntryList(&RxContext->ContextListEntry);
|
||
RxDeviceObject->StartStopContext.State = RDBSS_STOP_IN_PROGRESS;
|
||
RxDeviceObject->StartStopContext.pStopContext = RxContext;
|
||
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
||
|
||
fWait = (InterlockedDecrement(&RxDeviceObject->NumberOfActiveContexts) != 0);
|
||
|
||
if (fWait) {
|
||
RxWaitSync(RxContext);
|
||
}
|
||
|
||
ASSERT(RxDeviceObject->NumberOfActiveContexts == 0);
|
||
|
||
RxUnstart(RxContext,RxDeviceObject);
|
||
|
||
RxSpinDownMRxDispatcher(RxDeviceObject);
|
||
|
||
MINIRDR_CALL(
|
||
Status,
|
||
RxContext,
|
||
RxDeviceObject->Dispatch,
|
||
MRxStop,
|
||
(RxContext,RxDeviceObject),
|
||
);
|
||
|
||
|
||
// If there are no residual FCB's the driver can be unloaded. If not the
|
||
// driver must remain loaded so that close/cleanup operations on ORPHANED
|
||
// FCB's can be completed.
|
||
if (RxDeviceObject->NumberOfActiveFcbs == 0) {
|
||
Status = STATUS_SUCCESS;
|
||
} else {
|
||
//ASSERT(!"OPENHANDLES!");
|
||
Status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
|
||
}
|
||
|
||
RxSpinDownMRxDispatcher(RxDeviceObject);
|
||
|
||
// All set to startup again.
|
||
RxSetRdbssState(RxDeviceObject,RDBSS_STARTABLE);
|
||
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
ExReleaseResourceLite( &RxData.Resource );
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|