/*++ 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 #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, __RxSynchronizeBlockingOperationsMaybeDroppingFcbLock) #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->pNetRoot != NULL) && (Fcb->pNetRoot->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; DebugDoit( InterlockedIncrement(&RxFsdEntryCount); ) 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 = RxContext->Flags & RX_CONTEXT_PRESERVED_FLAGS; ULONG InitialContextFlags = 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; BOOLEAN RxContextIsMustSucceedAllocated; BOOLEAN RxContextIsFromZone; PRDBSS_DEVICE_OBJECT RxDeviceObject; PRX_CONTEXT pStopContext = 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); RxContextIsMustSucceedAllocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED); 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)) { pStopContext = 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 (pStopContext != NULL) { // Signal the event. RxSignalSynchronousWaiter(pStopContext); } if (RxContext->dwShadowCritOwner) { DbgPrint("RxDereferenceAndDeleteRxContext:shdowcrit still owned by %x\n", RxContext->dwShadowCritOwner); ASSERT(FALSE); } 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) { PIRP Irp; PAGED_CODE(); ASSERT(RxContext); ASSERT(RxContext->CurrentIrp); Irp = 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(); } } #if 0 if ((Status!=STATUS_SUCCESS) && (RxContext->LoudCompletionString)) { DbgPrint("LoudFailure %08lx/%08lx on %wZ\n",Status,Irp->IoStatus.Information,RxContext->LoudCompletionString); if (RxStopOnLoudCompletion) { //DbgBreakPoint(); } } #endif RxContext->CurrentIrp = NULL; 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 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; } if (Irp->MdlAddress) { RxUnprotectMdlFromFree(Irp->MdlAddress); } 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)) { if (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 ); } } if (IrpSp->MajorFunction == IRP_MJ_WRITE) { if (Irp->IoStatus.Status == STATUS_SUCCESS) { ASSERT(Irp->IoStatus.Information <= IrpSp->Parameters.Write.Length); } } if (RxContext != NULL) { if (RxContext->PendingReturned) { ASSERT(IrpSp->Control & SL_PENDING_RETURNED); } } 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 __RxSynchronizeBlockingOperationsMaybeDroppingFcbLock( IN OUT PRX_CONTEXT RxContext, 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; RxCaptureFcb; RxCaptureRequestPacket; BOOLEAN FcbLockDropped = FALSE; BOOLEAN SerializationMutexReleased = FALSE; PRX_CONTEXT FrontRxContext; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock, rxc=%08lx, fobx=%08lx\n", RxContext, RxContext->pFobx )); RxContext->StoredStatus = STATUS_SUCCESS; //do this early....a cleanup could come thru and change it ExAcquireFastMutex(&RxContextPerFileSerializationMutex); if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED)) { SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION); // ValidateBlockingIoQ(BlockingIoQ); 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,capFcb); } 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,capReqPacket); } 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 )); } } Status = (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : RxContext->StoredStatus); } else { Status = STATUS_CANCELLED; } if (!SerializationMutexReleased) { SerializationMutexReleased = TRUE; ExReleaseFastMutex(&RxContextPerFileSerializationMutex); } if (DropFcbLock && !FcbLockDropped) { RxContext->FcbResourceAcquired = FALSE; FcbLockDropped = TRUE; RxReleaseFcb(RxContext,capFcb); } 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) /*++ Routine Description: This routine cancels the operation in the blocking queue 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; if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) { RxSignalSynchronousWaiter(RxContext); } else { // The reference taken in the synchronization routine is derefernced // by the post completion routine, RxFsdPostRequest(RxContext); } } ExReleaseFastMutex(&RxContextPerFileSerializationMutex); 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); //DbgBreakPoint(); } } #if 0 VOID ValidateBlockingIoQ( PLIST_ENTRY BlockingIoQ ) { PLIST_ENTRY pListEntry; ULONG cntFlink, cntBlink; cntFlink = cntBlink = 0; pListEntry = BlockingIoQ->Flink; while (pListEntry != BlockingIoQ) { PRX_CONTEXT pRxContext; pRxContext = (PRX_CONTEXT)CONTAINING_RECORD( pListEntry, RX_CONTEXT, RxContextSerializationQLinks); if (!pRxContext || (NodeType(pRxContext) != RDBSS_NTC_RX_CONTEXT)) { DbgPrint("ValidateBlockingIO:Invalid RxContext %x on Q %x\n", pRxContext, BlockingIoQ); //DbgBreakPoint(); } ++cntFlink; pListEntry = pListEntry->Flink; } // check backward list validity pListEntry = BlockingIoQ->Blink; while (pListEntry != BlockingIoQ) { PRX_CONTEXT pRxContext; pRxContext = (PRX_CONTEXT)CONTAINING_RECORD( pListEntry, RX_CONTEXT, RxContextSerializationQLinks); if (!pRxContext || (NodeType(pRxContext) != RDBSS_NTC_RX_CONTEXT)) { DbgPrint("ValidateBlockingIO:Invalid RxContext %x on Q %x\n", pRxContext, BlockingIoQ); //DbgBreakPoint(); } ++cntBlink; pListEntry = pListEntry->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