//+----------------------------------------------------------------------------//+---------------------------------------------------------------------------- // // Copyright (C) 2001, Microsoft Corporation // // File: rxcontx.c // // Contents: Contains functions for allocating contexts and Cancel Routines // // // Functions: // // Author - Rohan Phillips (Rohanp) //----------------------------------------------------------------------------- #include "ntifs.h" #include #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RxInitializeContext) #pragma alloc_text(PAGE, DfsInitializeContextResources) #pragma alloc_text(PAGE, DfsDeInitializeContextResources) #endif #define RX_IRPC_POOLTAG ('rsfd') KSPIN_LOCK RxStrucSupSpinLock = {0}; LIST_ENTRY RxActiveContexts; ULONG NumberOfActiveContexts = 0; NPAGED_LOOKASIDE_LIST RxContextLookasideList; //+------------------------------------------------------------------------- // // Function: DfsInitializeContextResources // // Arguments: // // Returns: Status // ERROR_SUCCESS on success // ERROR status code otherwise // // // Description: Initializes all resources needed for allocating contexts // //-------------------------------------------------------------------------- NTSTATUS DfsInitializeContextResources(void) { NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); KeInitializeSpinLock( &RxStrucSupSpinLock ); // Initialize the look aside list for RxContext allocation ExInitializeNPagedLookasideList( &RxContextLookasideList, ExAllocatePoolWithTag, ExFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 32); InitializeListHead(&RxActiveContexts); return Status; } //+------------------------------------------------------------------------- // // Function: DfsDeInitializeContextResources // // Arguments: // // Returns: Status // ERROR_SUCCESS on success // ERROR status code otherwise // // // Description: DeInitializes all resources needed for allocating contexts // //-------------------------------------------------------------------------- NTSTATUS DfsDeInitializeContextResources(void) { NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); ExDeleteNPagedLookasideList(&RxContextLookasideList); return Status; } //+------------------------------------------------------------------------- // // Function: RxInitializeContext // // Arguments: // // Returns: // // // Description: initializes a context // //-------------------------------------------------------------------------- VOID RxInitializeContext( IN PIRP Irp, IN OUT PRX_CONTEXT RxContext) { PAGED_CODE(); RxContext->ReferenceCount = 1; // Initialize the Sync Event. KeInitializeEvent( &RxContext->SyncEvent, SynchronizationEvent, FALSE); if(Irp) { if (!IoIsOperationSynchronous(Irp)) { SetFlag( RxContext->Flags, DFS_CONTEXT_FLAG_ASYNC_OPERATION ); } } // Set the Irp fields. RxContext->CurrentIrp = Irp; RxContext->OriginalThread = RxContext->LastExecutionThread = PsGetCurrentThread(); } //+------------------------------------------------------------------------- // // Function: RxCreateRxContext // // Arguments: // // Returns: Pointer to context information // // // Description: allocates a context // //-------------------------------------------------------------------------- PRX_CONTEXT RxCreateRxContext ( IN PIRP Irp, IN ULONG InitialContextFlags ) { PRX_CONTEXT RxContext = NULL; ULONG RxContextFlags = 0; KIRQL SavedIrql; RxContext = ExAllocateFromNPagedLookasideList( &RxContextLookasideList); if(RxContext == NULL) { return(NULL); } InterlockedIncrement(&NumberOfActiveContexts); RtlZeroMemory( RxContext, sizeof(RX_CONTEXT) ); RxContext->Flags = RxContextFlags; RxInitializeContext(Irp,RxContext); KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql ); InsertTailList(&RxActiveContexts,&RxContext->ContextListEntry); KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql ); return RxContext; } //+------------------------------------------------------------------------- // // Function: RxDereferenceAndDeleteRxContext_Real // // Arguments: // // Returns: // // // Description: Deallocates a context // //-------------------------------------------------------------------------- VOID RxDereferenceAndDeleteRxContext_Real ( IN PRX_CONTEXT RxContext ) { PRX_CONTEXT pStopContext = NULL; LONG FinalRefCount = 0; KIRQL SavedIrql; KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql ); FinalRefCount = InterlockedDecrement(&RxContext->ReferenceCount); if (FinalRefCount == 0) { RemoveEntryList(&RxContext->ContextListEntry); InterlockedDecrement(&NumberOfActiveContexts); RtlZeroMemory( RxContext, sizeof(RX_CONTEXT) ); ExFreeToNPagedLookasideList( &RxContextLookasideList, RxContext ); } KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql ); } //+------------------------------------------------------------------------- // // Function: RxSetMinirdrCancelRoutine // // Arguments: // // Returns: // // // Description: Sets up a cancel routine // //-------------------------------------------------------------------------- NTSTATUS RxSetMinirdrCancelRoutine( IN OUT PRX_CONTEXT RxContext, IN DFS_CALLDOWN_ROUTINE DfsCancelRoutine) { NTSTATUS Status = STATUS_SUCCESS; KIRQL SavedIrql; KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql ); if (!FlagOn(RxContext->Flags, DFS_CONTEXT_FLAG_CANCELLED)) { RxContext->CancelRoutine = DfsCancelRoutine; Status = STATUS_SUCCESS; } else { Status = STATUS_CANCELLED; } KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql ); return Status; } //+------------------------------------------------------------------------- // // Function: RxCancelRoutine // // Arguments: // // Returns: // // // Description: The main cancel routine // //-------------------------------------------------------------------------- VOID RxCancelRoutine( PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { PRX_CONTEXT pRxContext = NULL; PLIST_ENTRY pListEntry = NULL; DFS_CALLDOWN_ROUTINE DfsCancelRoutine = NULL; KIRQL SavedIrql; // Locate the context corresponding to the given Irp. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql ); pListEntry = RxActiveContexts.Flink; while (pListEntry != &RxActiveContexts) { pRxContext = CONTAINING_RECORD(pListEntry,RX_CONTEXT,ContextListEntry); if (pRxContext->CurrentIrp == pIrp) { break; } else { pListEntry = pListEntry->Flink; } } if (pListEntry != &RxActiveContexts) { SetFlag( pRxContext->Flags, DFS_CONTEXT_FLAG_CANCELLED ); DfsCancelRoutine = pRxContext->CancelRoutine; pRxContext->CancelRoutine = NULL; InterlockedIncrement(&pRxContext->ReferenceCount); } else { pRxContext = NULL; DfsCancelRoutine = NULL; } KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql ); IoReleaseCancelSpinLock(pIrp->CancelIrql); if (pRxContext != NULL) { if (DfsCancelRoutine != NULL) { (DfsCancelRoutine)(pRxContext); } RxDereferenceAndDeleteRxContext(pRxContext); } }