Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1230 lines
36 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
RxContx.c
Abstract:
This module implements routine to allocate/initialize and to delete an Irp
Context. These structures are very important because they link Irps with the
RDBSS. They encapsulate all the context required to process an IRP.
Author:
Joe Linn [JoeLinn] 21-aug-1994
Revision History:
Balan Sethu Raman [SethuR] 07-June-1995 Included support for cancelling
requests
--*/
#include "precomp.h"
#pragma hdrstop
#include <dfsfsctl.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxInitializeContext)
#pragma alloc_text(PAGE, RxReinitializeContext)
#pragma alloc_text(PAGE, RxPrepareContextForReuse)
#pragma alloc_text(PAGE, RxCompleteRequest)
#pragma alloc_text(PAGE, __RxSynchronizeBlockingOperations)
#pragma alloc_text(PAGE, RxResumeBlockedOperations_Serially)
#pragma alloc_text(PAGE, RxResumeBlockedOperations_ALL)
#pragma alloc_text(PAGE, RxCancelBlockingOperation)
#pragma alloc_text(PAGE, RxRemoveOperationFromBlockingQueue)
#endif
BOOLEAN RxSmallContextLogEntry = FALSE;
FAST_MUTEX RxContextPerFileSerializationMutex;
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_RXCONTX)
ULONG RxContextSerialNumberCounter = 0;
#ifdef RDBSSLOG
//
// this stuff must be in nonpaged memory
//
//// 1 2 3 4 5 6 7 8 9
char RxInitContext_SurrogateFormat[] = "%S%S%N%N%N%N%N%N%N";
//// 2 3 4 5 6 7 8 9
char RxInitContext_ActualFormat[] = "Irp++ %s/%lx %08lx irp %lx thrd %lx %lx:%lx #%lx";
#endif // ifdef RDBSSLOG
VOID
ValidateBlockingIoQ (
PLIST_ENTRY BlockingIoQ
);
VOID
RxInitializeContext (
IN PIRP Irp,
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
IN ULONG InitialContextFlags,
IN OUT PRX_CONTEXT RxContext
)
{
PDEVICE_OBJECT TopLevelDeviceObject;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("RxInitializeContext\n"));
//
// some asserts that we need. This ensures that the two values that are
// packaged together as an IoStatusBlock can be manipulated independently
// as well as together.
//
ASSERT( FIELD_OFFSET( RX_CONTEXT, StoredStatus ) == FIELD_OFFSET( RX_CONTEXT, IoStatusBlock.Status ) );
ASSERT( FIELD_OFFSET( RX_CONTEXT, InformationToReturn ) == FIELD_OFFSET( RX_CONTEXT, IoStatusBlock.Information ) );
//
// Set the proper node type code, node byte size and the flags
//
RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
RxContext->NodeByteSize = sizeof( RX_CONTEXT );
RxContext->ReferenceCount = 1;
RxContext->SerialNumber = InterlockedIncrement( &RxContextSerialNumberCounter );
RxContext->RxDeviceObject = RxDeviceObject;
//
// Initialize the Sync Event.
//
KeInitializeEvent( &RxContext->SyncEvent, SynchronizationEvent, FALSE );
//
// Initialize the associated scavenger entry
//
RxInitializeScavengerEntry( &RxContext->ScavengerEntry );
//
// Initialize the list entry of blocked operations
//
InitializeListHead( &RxContext->BlockedOperations );
RxContext->MRxCancelRoutine = NULL;
RxContext->ResumeRoutine = NULL;
SetFlag( RxContext->Flags, InitialContextFlags );
//
// Set the Irp fields....for cacheing and hiding
//
RxContext->CurrentIrp = Irp;
RxContext->OriginalThread = RxContext->LastExecutionThread = PsGetCurrentThread();
if (Irp != NULL) {
PIO_STACK_LOCATION IrpSp;
IrpSp = IoGetCurrentIrpStackLocation( Irp ); // ok4ioget
//
// There are certain operations that are open ended in the redirector.
// The change notification mechanism is one of them. On a synchronous
// operation if the wait is in the redirector then we will not be able
// to cancel because FsRtlEnterFileSystem disables APC's. Therefore
// we convert the synchronous operation into an asynchronous one and
// let the I/O system do the waiting.
//
if (IrpSp->FileObject != NULL) {
if (!IoIsOperationSynchronous( Irp )) {
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
} else {
PFCB Fcb;
Fcb = (PFCB)IrpSp->FileObject->FsContext;
if ((Fcb != NULL) && NodeTypeIsFcb( Fcb )) {
if (((IrpSp->MajorFunction == IRP_MJ_READ) ||
(IrpSp->MajorFunction == IRP_MJ_WRITE) ||
(IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)) &&
(Fcb->NetRoot != NULL) &&
(Fcb->NetRoot->Type == NET_ROOT_PIPE)) {
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
}
}
}
}
if ((IrpSp->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
(IrpSp->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)) {
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
}
//
// JOYC: make all device io control async
//
if (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
}
//
// Set the recursive file system call parameter. We set it true if
// the TopLevelIrp field in the thread local storage is not the current
// irp, otherwise we leave it as FALSE.
//
if (!RxIsThisTheTopLevelIrp( Irp )) {
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL );
}
if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject) {
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL );
}
//
// Major/Minor Function codes
//
RxContext->MajorFunction = IrpSp->MajorFunction;
RxContext->MinorFunction = IrpSp->MinorFunction;
ASSERT( RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION );
RxContext->CurrentIrpSp = IrpSp;
if (IrpSp->FileObject) {
PFOBX Fobx;
PFCB Fcb;
Fcb = (PFCB)IrpSp->FileObject->FsContext;
Fobx = (PFOBX)IrpSp->FileObject->FsContext2;
RxContext->pFcb = (PMRX_FCB)Fcb;
if (Fcb && NodeTypeIsFcb( Fcb )) {
RxContext->NonPagedFcb = Fcb->NonPaged;
}
if (Fobx &&
(Fobx != (PFOBX)UIntToPtr( DFS_OPEN_CONTEXT )) &&
(Fobx != (PFOBX)UIntToPtr( DFS_DOWNLEVEL_OPEN_CONTEXT ))) {
RxContext->pFobx = (PMRX_FOBX)Fobx;
RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
if (NodeType( Fobx ) == RDBSS_NTC_FOBX) {
RxContext->FobxSerialNumber = InterlockedIncrement( &Fobx->FobxSerialNumber );
}
} else {
RxContext->pFobx = NULL;
}
//
// Copy IRP specific parameters.
//
if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
(RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)) {
if (Fobx != NULL) {
if (NodeType( Fobx ) == RDBSS_NTC_FOBX) {
RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)Fcb->VNetRoot;
} else if (NodeType( Fobx ) == RDBSS_NTC_V_NETROOT) {
RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)Fobx;
}
}
}
//
// Copy RealDevice for workque algorithms,
//
RxContext->RealDevice = IrpSp->FileObject->DeviceObject;
if (FlagOn( IrpSp->FileObject->Flags,FO_WRITE_THROUGH )) {
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH );
}
}
} else {
RxContext->CurrentIrpSp = NULL;
//
// Major/Minor Function codes
//
RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
RxContext->MinorFunction = 0;
}
if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
PETHREAD Thread = PsGetCurrentThread();
UCHAR Pad = 0;
RxLog(( RxInitContext_SurrogateFormat,
RxInitContext_ActualFormat,
RXCONTX_OPERATION_NAME( RxContext->MajorFunction, BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT )),
RxContext->MinorFunction,
RxContext,
Irp,
Thread,
RxContext->pFcb,
RxContext->pFobx,
RxContext->SerialNumber ));
RxWmiLog( LOG,
RxInitializeContext,
LOGPTR( RxContext )
LOGPTR( Irp )
LOGPTR( Thread )
LOGPTR( RxContext->pFcb )
LOGPTR( RxContext->pFobx )
LOGULONG( RxContext->SerialNumber )
LOGUCHAR( RxContext->MinorFunction )
LOGARSTR( RXCONTX_OPERATION_NAME( RxContext->MajorFunction, BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT ) )) );
}
RxDbgTrace( -1, Dbg, ("RxInitializeContext -> %08lx %08lx %08lx\n", RxContext, RxContext->pFcb, RxContext->pFobx ));
}
PRX_CONTEXT
RxCreateRxContext (
IN PIRP Irp,
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
IN ULONG InitialContextFlags
)
/*++
Routine Description:
This routine creates a new RX_CONTEXT record
Arguments:
Irp - Supplies the originating Irp.
RxDeviceObject - the deviceobject that applies
InitialContextFlags - Supplies the wait value to store in the context;
also, the must_succeed value
Return Value:
PRX_CONTEXT - returns a pointer to the newly allocate RX_CONTEXT Record
--*/
{
KIRQL SavedIrql;
PRX_CONTEXT RxContext = NULL;
ULONG RxContextFlags = 0;
UCHAR MustSucceedDescriptorNumber = 0;
#if DBG
InterlockedIncrement( &RxFsdEntryCount );
#endif
ASSERT( RxDeviceObject != NULL );
InterlockedIncrement( &RxDeviceObject->NumberOfActiveContexts );
if (RxContext == NULL) {
RxContext = ExAllocateFromNPagedLookasideList( &RxContextLookasideList );
if (RxContext != NULL) {
SetFlag( RxContextFlags, RX_CONTEXT_FLAG_FROM_POOL );
}
}
if (RxContext == NULL) {
return NULL;
}
RtlZeroMemory( RxContext, sizeof( RX_CONTEXT ) );
RxContext->Flags = RxContextFlags;
RxContext->MustSucceedDescriptorNumber = MustSucceedDescriptorNumber;
RxInitializeContext( Irp, RxDeviceObject, InitialContextFlags, RxContext );
ASSERT( (RxContext->MajorFunction!=IRP_MJ_CREATE) ||
!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED ) );
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
InsertTailList(&RxActiveContexts,&RxContext->ContextListEntry);
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
return RxContext;
}
VOID
RxReinitializeContext(
IN OUT PRX_CONTEXT RxContext
)
{
PIRP Irp = RxContext->CurrentIrp;
PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
ULONG PreservedContextFlags = FlagOn( RxContext->Flags, RX_CONTEXT_PRESERVED_FLAGS );
ULONG InitialContextFlags = FlagOn( RxContext->Flags, RX_CONTEXT_INITIALIZATION_FLAGS );
PAGED_CODE();
RxPrepareContextForReuse( RxContext );
RtlZeroMemory( (PCHAR)(&RxContext->ContextListEntry + 1), sizeof( RX_CONTEXT ) - FIELD_OFFSET( RX_CONTEXT, MajorFunction ) );
RxContext->Flags = PreservedContextFlags;
RxInitializeContext( Irp, RxDeviceObject, InitialContextFlags, RxContext );
}
VOID
RxPrepareContextForReuse (
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine prepares a context for reuse by resetting all operation specific
allocations/acquistions that have been made. The parameters that have been
obtained from the IRP are not modified.
Arguments:
RxContext - Supplies the RX_CONTEXT to remove
Return Value:
None
--*/
{
PAGED_CODE();
//
// Clean up the operation specific stuff
//
switch (RxContext->MajorFunction) {
case IRP_MJ_CREATE:
ASSERT( RxContext->Create.CanonicalNameBuffer == NULL );
break;
case IRP_MJ_READ :
case IRP_MJ_WRITE :
ASSERT( RxContext->RxContextSerializationQLinks.Flink == NULL );
ASSERT( RxContext->RxContextSerializationQLinks.Blink == NULL );
break;
default:
NOTHING;
}
RxContext->ReferenceCount = 0;
}
VOID
RxDereferenceAndDeleteRxContext_Real (
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine dereferences an RxContexts and if the refcount goes to zero
then it deallocates and removes the specified RX_CONTEXT record from the
Rx in-memory data structures. IT is called by routines other than
RxCompleteRequest async requests touch the RxContext "last" in either the
initiating thread or in some other thread. Thus, we refcount the structure
and finalize on the last dereference.
Arguments:
RxContext - Supplies the RX_CONTEXT to remove
Return Value:
None
--*/
{
KIRQL SavedIrql;
BOOLEAN RxContextIsFromPool;
PRDBSS_DEVICE_OBJECT RxDeviceObject;
PRX_CONTEXT StopContext = NULL;
LONG FinalRefCount;
RxDbgTraceLV( +1, Dbg, 1500, ("RxDereferenceAndDeleteRxContext, RxContext = %08lx (%lu)\n", RxContext,RxContext->SerialNumber) );
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
ASSERT( RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT );
FinalRefCount = InterlockedDecrement( &RxContext->ReferenceCount );
if (FinalRefCount == 0) {
RxDeviceObject = RxContext->RxDeviceObject;
RxContextIsFromPool = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL );
if (RxContext == RxDeviceObject->StartStopContext.pStopContext) {
RxDeviceObject->StartStopContext.pStopContext = NULL;
} else {
ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
(RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
RemoveEntryList( &RxContext->ContextListEntry );
if ((InterlockedDecrement( &RxDeviceObject->NumberOfActiveContexts) == 0) &&
(RxDeviceObject->StartStopContext.pStopContext != NULL)) {
StopContext = RxDeviceObject->StartStopContext.pStopContext;
}
}
}
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
if (FinalRefCount > 0) {
RxDbgTraceLV( -1, Dbg, 1500, ("RxDereferenceAndDeleteRxContext, RxContext not final!!! = %08lx (%lu)\n", RxContext,RxContext->SerialNumber) );
return;
}
ASSERT( RxContext->ReferenceCount == 0 );
//
// Clean up the operation specific stuff
//
RxPrepareContextForReuse( RxContext );
ASSERT( RxContext->AcquireReleaseFcbTrackerX == 0 );
if (StopContext != NULL) {
//
// Signal the event.
//
RxSignalSynchronousWaiter( StopContext );
}
#if DBG
if (RxContext->ShadowCritOwner) {
DbgPrint( "RxDereferenceAndDeleteRxContext:shdowcrit still owned by %x\n", RxContext->ShadowCritOwner );
ASSERT( FALSE );
}
#endif
if (RxContextIsFromPool) {
ExFreeToNPagedLookasideList( &RxContextLookasideList, RxContext );
}
RxDbgTraceLV( -1, Dbg, 1500, ("RxDereferenceAndDeleteRxContext -> VOID\n", 0) );
return;
}
ULONG RxStopOnLoudCompletion = TRUE;
NTSTATUS
RxCompleteRequest (
IN PRX_CONTEXT RxContext,
IN NTSTATUS Status
)
/*++
Routine Description:
This routine complete the request associated with the RX_CONTEXT
Arguments:
RxContext - Contains an irp to be completed
Status - Status to complete request with
Return Value:
--*/
{
PIRP Irp = RxContext->CurrentIrp;
PAGED_CODE();
ASSERT( RxContext );
ASSERT( RxContext->CurrentIrp );
if ((RxContext->LoudCompletionString)) {
DbgPrint( "LoudCompletion %08lx/%08lx on %wZ\n", Status, Irp->IoStatus.Information, RxContext->LoudCompletionString );
if ((Status != STATUS_SUCCESS) && RxStopOnLoudCompletion) {
DbgPrint( "FAILURE!!!!! %08lx/%08lx on %wZ\n", Status, Irp->IoStatus.Information, RxContext->LoudCompletionString );
// DbgBreakPoint();
}
}
RxCompleteRequest_Real( RxContext, Irp, Status );
return Status;
}
#ifdef RDBSSLOG
//this stuff must be in nonpaged memory
//// 1 2 3 4 5 6 7 8 9
char RxCompleteContext_SurrogateFormat[] = "%S%S%S%N%N%N%N%N%N";
//// 2 3 4 5 6 7 8 9
char RxCompleteContext_ActualFormat[] = "Irp-- %s%s/%lx %lx irp %lx iosb %lx,%lx #%lx";
#endif //ifdef RDBSSLOG
VOID
RxCompleteRequest_Real (
IN OPTIONAL PRX_CONTEXT RxContext,
IN PIRP Irp OPTIONAL,
IN NTSTATUS Status
)
/*++
Routine Description:
This routine completes a Irp
Arguments:
Irp - Supplies the Irp being processed
Status - Supplies the status to complete the Irp with
--*/
{
//
// If we have an Irp then complete the irp.
//
if (Irp != NULL) {
CCHAR PriorityBoost;
PIO_STACK_LOCATION IrpSp;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
RxSetCancelRoutine( Irp, NULL );
//
// For an error, zero out the information field before
// completing the request if this was an input operation.
// Otherwise IopCompleteRequest will try to copy to the user's buffer.
// Also, no boost for an error.
//
if (NT_ERROR( Status ) &&
FlagOn( Irp->Flags, IRP_INPUT_OPERATION )) {
Irp->IoStatus.Information = 0;
PriorityBoost = IO_NO_INCREMENT;
} else {
PriorityBoost = IO_DISK_INCREMENT;
}
Irp->IoStatus.Status = Status;
RxDbgTrace( 0, (DEBUG_TRACE_DISPATCH),
("RxCompleteRequest_real ---------- Irp(code) = %08lx(%02lx) %08lx %08lx\n",
Irp, IoGetCurrentIrpStackLocation( Irp )->MajorFunction,
Status, Irp->IoStatus.Information));
if (RxContext != NULL) {
ASSERT( RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION );
if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
RxLog(( RxCompleteContext_SurrogateFormat,
RxCompleteContext_ActualFormat,
(RxContext->OriginalThread == PsGetCurrentThread())?"":"*",
RXCONTX_OPERATION_NAME( RxContext->MajorFunction ,TRUE) ,
RxContext->MinorFunction,
RxContext,
Irp,
Status,
Irp->IoStatus.Information,
RxContext->SerialNumber ));
RxWmiLog( LOG,
RxCompleteRequest,
LOGPTR( RxContext )
LOGPTR( Irp )
LOGULONG( Status )
LOGPTR( Irp->IoStatus.Information )
LOGULONG( RxContext->SerialNumber )
LOGUCHAR( RxContext->MinorFunction )
LOGARSTR( RXCONTX_OPERATION_NAME( RxContext->MajorFunction, TRUE )) );
}
}
if ((IrpSp->MajorFunction == IRP_MJ_CREATE) &&
(Status != STATUS_PENDING) &&
(RxContext != NULL)) {
if (FlagOn( RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH )) {
IrpSp->FileObject->FileName.Length += sizeof( WCHAR );
}
RxpPrepareCreateContextForReuse( RxContext );
ASSERT ( RxContext->Create.CanonicalNameBuffer == NULL );
}
//
// Check information returned on successfull writes is no more than requested
//
ASSERT( (IrpSp->MajorFunction != IRP_MJ_WRITE) ||
(Irp->IoStatus.Status != STATUS_SUCCESS) ||
(Irp->IoStatus.Information <= IrpSp->Parameters.Write.Length) );
//
// Check that pending returned is in sync with the irp itself
//
ASSERT( (RxContext == NULL) ||
(!RxContext->PendingReturned) ||
FlagOn( IrpSp->Control, SL_PENDING_RETURNED ) );
if( RxContext != NULL ) RxContext->CurrentIrp = NULL;
IoCompleteRequest( Irp, PriorityBoost );
} else {
//
// a call with a null irp..........
//
RxLog(( "Irp00 %lx\n", RxContext ));
RxWmiLog( LOG,
RxCompleteRequest_NI,
LOGPTR( RxContext ) );
}
//
// Delete the Irp context.
//
if (RxContext != NULL) {
RxDereferenceAndDeleteRxContext( RxContext );
}
return;
}
NTSTATUS
__RxSynchronizeBlockingOperations (
IN OUT PRX_CONTEXT RxContext,
IN PFCB Fcb,
IN OUT PLIST_ENTRY BlockingIoQ,
IN BOOLEAN DropFcbLock
)
/*++
Routine Description:
This routine is used to synchronize among blocking IOs to the same Q.
Currently, the routine is only used to synchronize block pipe operations and
the Q is the one in the file object extension (Fobx). What happens is that
the operation joins the queue. If it is now the front of the queue, the
operation continues; otherwise it waits on the sync event in the RxContext
or just returns pending (if async).
We may have been cancelled while we slept, check for that and
return an error if it happens.
The event must have been reset before the call. The fcb lock must be held;
it is dropped after we get on the Q.
Arguments:
RxContext The context of the operation being synchronized
BlockingIoQ The queue to get on.
--*/
{
NTSTATUS Status;
PIRP Irp = RxContext->CurrentIrp;
BOOLEAN FcbLockDropped = FALSE;
BOOLEAN SerializationMutexReleased = FALSE;
PRX_CONTEXT FrontRxContext;
PAGED_CODE();
RxDbgTrace( +1, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock, rxc=%08lx, fobx=%08lx\n", RxContext, RxContext->pFobx) );
//
// do this early since a cleanup could come through and change it
//
RxContext->StoredStatus = STATUS_SUCCESS;
ExAcquireFastMutex( &RxContextPerFileSerializationMutex );
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED )) {
SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
InsertTailList( BlockingIoQ, &RxContext->RxContextSerializationQLinks );
FrontRxContext = CONTAINING_RECORD( BlockingIoQ->Flink, RX_CONTEXT, RxContextSerializationQLinks );
if (RxContext != FrontRxContext) {
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION )) {
if (!SerializationMutexReleased) {
SerializationMutexReleased = TRUE;
ExReleaseFastMutex( &RxContextPerFileSerializationMutex );
}
if (DropFcbLock && !FcbLockDropped) {
RxContext->FcbResourceAcquired = FALSE;
FcbLockDropped = TRUE;
RxReleaseFcb( RxContext, Fcb );
}
RxDbgTrace( 0, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock waiting, rxc=%08lx\n", RxContext) );
RxWaitSync( RxContext );
RxDbgTrace( 0, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock ubblocked, rxc=%08lx\n", RxContext) );
} else {
RxContext->StoredStatus = STATUS_PENDING;
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME );
try {
RxPrePostIrp( RxContext, Irp );
} finally {
if (AbnormalTermination()) {
RxLog(( "!!!!! RxContext %lx Status %lx\n", RxContext, RxContext->StoredStatus ));
RxWmiLog( LOG,
RxSynchronizeBlockingOperationsMaybeDroppingFcbLock,
LOGPTR( RxContext )
LOGULONG( Status ));
RemoveEntryList(&RxContext->RxContextSerializationQLinks);
RxContext->RxContextSerializationQLinks.Flink = NULL;
RxContext->RxContextSerializationQLinks.Blink = NULL;
ClearFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
if (!SerializationMutexReleased) {
SerializationMutexReleased = TRUE;
ExReleaseFastMutex( &RxContextPerFileSerializationMutex );
}
} else {
InterlockedIncrement( &RxContext->ReferenceCount );
}
}
RxDbgTrace( -1, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock asyncreturn, rxc=%08lx\n", RxContext) );
}
}
if (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED)) {
Status = STATUS_CANCELLED;
} else {
Status = RxContext->StoredStatus;
}
} else {
Status = STATUS_CANCELLED;
}
if (!SerializationMutexReleased) {
SerializationMutexReleased = TRUE;
ExReleaseFastMutex( &RxContextPerFileSerializationMutex );
}
if (DropFcbLock && !FcbLockDropped) {
RxContext->FcbResourceAcquired = FALSE;
FcbLockDropped = TRUE;
RxReleaseFcb( RxContext, Fcb );
}
RxDbgTrace( -1, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock returning, rxc=%08lx, status=%08lx\n", RxContext, Status) );
return Status;
}
VOID
RxRemoveOperationFromBlockingQueue (
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine removes the context from the blocking queue if it is on it
Arguments:
RxContext The context of the operation being synchronized
--*/
{
PAGED_CODE();
ExAcquireFastMutex( &RxContextPerFileSerializationMutex );
if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION )) {
ClearFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
RemoveEntryList( &RxContext->RxContextSerializationQLinks );
RxContext->RxContextSerializationQLinks.Flink = NULL;
RxContext->RxContextSerializationQLinks.Blink = NULL;
}
ExReleaseFastMutex( &RxContextPerFileSerializationMutex );
RxDbgTrace( -1, Dbg, ("RxRemoveOperationFromBlockingQueue, rxc=%08lx\n", RxContext ));
return;
}
VOID
RxCancelBlockingOperation (
IN OUT PRX_CONTEXT RxContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine cancels the operation in the blocking queue
Arguments:
RxContext - The context of the operation being synchronized
Return:
None
--*/
{
PIO_STACK_LOCATION IrpSp;
PFCB Fcb;
PFOBX Fobx;
BOOLEAN CompleteRequest = FALSE;
PAGED_CODE();
ExAcquireFastMutex( &RxContextPerFileSerializationMutex );
if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION ) &&
(RxContext->RxContextSerializationQLinks.Flink != NULL)) {
//
// Now its safe to get the fobx - since we know the irp is still active
// we will cancel the request if it isn't on the front of the list
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
RxDecodeFileObject( IrpSp->FileObject, &Fcb, &Fobx );
if ((RxContext != CONTAINING_RECORD( Fobx->Specific.NamedPipe.ReadSerializationQueue.Flink, RX_CONTEXT, RxContextSerializationQLinks) ) &&
(RxContext != CONTAINING_RECORD( Fobx->Specific.NamedPipe.WriteSerializationQueue.Flink, RX_CONTEXT, RxContextSerializationQLinks) )) {
ClearFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
RemoveEntryList( &RxContext->RxContextSerializationQLinks );
RxContext->RxContextSerializationQLinks.Flink = NULL;
RxContext->RxContextSerializationQLinks.Blink = NULL;
RxContext->StoredStatus = STATUS_CANCELLED;
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION )) {
RxSignalSynchronousWaiter( RxContext );
} else {
CompleteRequest = TRUE;
}
}
}
ExReleaseFastMutex( &RxContextPerFileSerializationMutex );
if (CompleteRequest) {
RxFsdPostRequest( RxContext );
}
RxDbgTrace( -1, Dbg, ("RxCancelBlockedOperations, rxc=%08lx\n", RxContext ));
return;
}
VOID
RxResumeBlockedOperations_Serially (
IN OUT PRX_CONTEXT RxContext,
IN OUT PLIST_ENTRY BlockingIoQ
)
/*++
Routine Description:
This routine wakes up the next guy, if any, on the serialized blockingioQ. We know that the fcb must still be valid because
of the reference that is being held by the IO system on the file object thereby preventing a close.
Arguments:
RxContext The context of the operation being synchronized
BlockingIoQ The queue to get on.
--*/
{
PLIST_ENTRY ListEntry;
BOOLEAN FcbLockHeld = FALSE;
PRX_CONTEXT FrontRxContext = NULL;
PAGED_CODE();
RxDbgTrace( +1, Dbg, ("RxResumeBlockedOperations_Serially, rxc=%08lx, fobx=%08lx\n", RxContext, RxContext->pFobx ));
//
// remove myself from the queue and check for someone else
//
ExAcquireFastMutex( &RxContextPerFileSerializationMutex );
if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION )) {
ClearFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
// ValidateBlockingIoQ(BlockingIoQ);
RemoveEntryList( &RxContext->RxContextSerializationQLinks );
// ValidateBlockingIoQ(BlockingIoQ);
RxContext->RxContextSerializationQLinks.Flink = NULL;
RxContext->RxContextSerializationQLinks.Blink = NULL;
ListEntry = BlockingIoQ->Flink;
if (BlockingIoQ != ListEntry) {
FrontRxContext = CONTAINING_RECORD( ListEntry, RX_CONTEXT, RxContextSerializationQLinks );
RxDbgTrace( -1, Dbg, ("RxResumeBlockedOperations unwaiting the next guy and returning, rxc=%08lx\n", RxContext ));
} else {
FrontRxContext = NULL;
}
if (FrontRxContext != NULL) {
if (!FlagOn( FrontRxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION )) {
RxSignalSynchronousWaiter( FrontRxContext );
} else {
//
// The reference taken in the synchronization routine is derefernced
// by the post completion routine,
//
RxFsdPostRequest( FrontRxContext );
}
}
}
ExReleaseFastMutex( &RxContextPerFileSerializationMutex );
RxDbgTrace( -1, Dbg, ("RxResumeBlockedOperations_Serially returning, rxc=%08lx\n", RxContext ) );
return;
}
VOID
RxResumeBlockedOperations_ALL (
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine wakes up all of the guys on the blocked operations queue. The controlling mutex is also
stored in the RxContext block. the current implementation is that all of the guys must be waiting
on the sync events.
Arguments:
RxContext The context of the operation being synchronized
--*/
{
LIST_ENTRY CopyOfQueue;
PLIST_ENTRY ListEntry;
PAGED_CODE();
RxDbgTrace( +1, Dbg, ("RxResumeBlockedOperations_ALL, rxc=%08lx\n", RxContext) );
RxTransferListWithMutex( &CopyOfQueue, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex );
for (ListEntry = CopyOfQueue.Flink; ListEntry != &CopyOfQueue;) {
PRX_CONTEXT FrontRxContext = CONTAINING_RECORD( ListEntry, RX_CONTEXT, RxContextSerializationQLinks );
RxSignalSynchronousWaiter( FrontRxContext );
IF_DEBUG {
PLIST_ENTRY PrevListEntry = ListEntry;
ListEntry = ListEntry->Flink;
PrevListEntry->Flink = PrevListEntry->Blink = NULL;
} else {
ListEntry = ListEntry->Flink;
}
}
RxDbgTrace( -1, Dbg, ("RxResumeBlockedOperations_ALL returning, rxc=%08lx\n", RxContext) );
return;
}
VOID
__RxItsTheSameContext (
PRX_CONTEXT RxContext,
ULONG CapturedRxContextSerialNumber,
ULONG Line,
PSZ File
)
{
if ((NodeType( RxContext ) != RDBSS_NTC_RX_CONTEXT) ||
(RxContext->SerialNumber != CapturedRxContextSerialNumber)) {
RxLog(( "NotSame!!!! %lx", RxContext ));
RxWmiLog( LOG,
RxItsTheSameContext,
LOGPTR( RxContext ) );
DbgPrint( "NOT THE SAME CONTEXT %08lx at Line %d in %s\n", RxContext, Line, File );
}
}
#if 0
VOID
ValidateBlockingIoQ(
PLIST_ENTRY BlockingIoQ
)
{
PLIST_ENTRY ListEntry;
ULONG cntFlink, cntBlink;
cntFlink = cntBlink = 0;
ListEntry = BlockingIoQ->Flink;
while (ListEntry != BlockingIoQ) {
PRX_CONTEXT RxContext;
RxContext = (PRX_CONTEXT)CONTAINING_RECORD( ListEntry, RX_CONTEXT, RxContextSerializationQLinks );
if (!RxContext || (NodeType( RxContext ) != RDBSS_NTC_RX_CONTEXT)) {
DbgPrint("ValidateBlockingIO:Invalid RxContext %x on Q %x\n", RxContext, BlockingIoQ );
//DbgBreakPoint();
}
cntFlink += 1;
ListEntry = ListEntry->Flink;
}
//
// check backward list validity
//
ListEntry = BlockingIoQ->Blink;
while (ListEntry != BlockingIoQ) {
PRX_CONTEXT RxContext;
RxContext = (PRX_CONTEXT)CONTAINING_RECORD( ListEntry, RX_CONTEXT, RxContextSerializationQLinks );
if (!RxContext || (NodeType( RxContext ) != RDBSS_NTC_RX_CONTEXT)) {
DbgPrint("ValidateBlockingIO:Invalid RxContext %x on Q %x\n",
RxContext, BlockingIoQ);
//DbgBreakPoint();
}
cntBlink += 1;
ListEntry = ListEntry->Blink;
}
//
// both counts should be the same
//
if(cntFlink != cntBlink) {
DbgPrint( "ValidateBlockingIO: cntFlink %d cntBlink %d\n", cntFlink, cntBlink );
//DbgBreakPoint();
}
}
#endif
#ifndef RX_NO_DBGFIELD_HLPRS
#define DECLARE_FIELD_HLPR(x) ULONG RxContextField_##x = FIELD_OFFSET(RX_CONTEXT,x);
#define DECLARE_FIELD_HLPR2(x,y) ULONG RxContextField_##x##y = FIELD_OFFSET(RX_CONTEXT,x.y);
DECLARE_FIELD_HLPR(MajorFunction);
DECLARE_FIELD_HLPR(CurrentIrp);
DECLARE_FIELD_HLPR(pFcb);
DECLARE_FIELD_HLPR(Flags);
DECLARE_FIELD_HLPR(MRxContext);
DECLARE_FIELD_HLPR(MRxCancelRoutine);
DECLARE_FIELD_HLPR(SyncEvent);
DECLARE_FIELD_HLPR(BlockedOperations);
DECLARE_FIELD_HLPR(FlagsForLowIo);
DECLARE_FIELD_HLPR2(Create,CanonicalNameBuffer);
DECLARE_FIELD_HLPR2(Create,pSrvCall);
DECLARE_FIELD_HLPR2(Create,pNetRoot);
DECLARE_FIELD_HLPR2(Create,pVNetRoot);
DECLARE_FIELD_HLPR2(QueryDirectory,FileIndex);
DECLARE_FIELD_HLPR2(QueryEa,UserEaList);
DECLARE_FIELD_HLPR2(QuerySecurity,SecurityInformation);
DECLARE_FIELD_HLPR2(QuerySecurity,Length);
#endif