More IRP Completion changes. Use proper stack count and other semantics, as documented in NT File System Internals. These changes don't break anything :P Modified: trunk/reactos/ntoskrnl/io/irp.c _____
Modified: trunk/reactos/ntoskrnl/io/irp.c --- trunk/reactos/ntoskrnl/io/irp.c 2005-05-07 00:37:48 UTC (rev 15068) +++ trunk/reactos/ntoskrnl/io/irp.c 2005-05-07 01:13:04 UTC (rev 15069) @@ -19,6 +19,187 @@
#define TAG_IRP TAG('I', 'R', 'P', ' ') #define TAG_SYS_BUF TAG('S', 'Y', 'S' , 'B')
+/* PRIVATE FUNCTIONS ********************************************************/ + +VOID +STDCALL +IopFreeIrpKernelApc(PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2) +{ + /* Free the IRP */ + IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc)); +} + +VOID +STDCALL +IopAbortIrpKernelApc(PKAPC Apc) +{ + /* Free the IRP */ + IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc)); +} + +/* + * FUNCTION: Performs the second stage of irp completion for read/write irps + * + * Called as a special kernel APC kernel-routine or directly from IofCompleteRequest() + * + * Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION) + * or IRP_CLOSE_OPERATION (IRP_MJ_CLOSE and IRP_MJ_CLEANUP) here since their + * cleanup/completion is fully taken care of in IoCompleteRequest. + * -Gunnar + */ +VOID +STDCALL +IopCompleteRequest(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2) +{ + PFILE_OBJECT FileObject; + PIRP Irp; + PMDL Mdl, NextMdl; + PKEVENT UserEvent; + BOOLEAN SyncIrp; + + if (Apc) DPRINT("IoSecondStageCompletition with APC: %x\n", Apc); + + /* Get data from the APC */ + FileObject = (PFILE_OBJECT)(*SystemArgument1); + Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc); + DPRINT("IoSecondStageCompletition, %x\n", Irp); + + /* Save the User Event */ + UserEvent = Irp->UserEvent; + + /* Remember if the IRP is Sync or not */ + SyncIrp = Irp->Flags & IRP_SYNCHRONOUS_API ? TRUE : FALSE; + + /* Handle Buffered case first */ + if (Irp->Flags & IRP_BUFFERED_IO) + { + /* Check if we have an input buffer and if we suceeded */ + if (Irp->Flags & IRP_INPUT_OPERATION && NT_SUCCESS(Irp->IoStatus.Status)) + { + /* Copy the buffer back to the user */ + RtlCopyMemory(Irp->UserBuffer, + Irp->AssociatedIrp.SystemBuffer, + Irp->IoStatus.Information); + } + + /* Also check if we should de-allocate it */ + if (Irp->Flags & IRP_DEALLOCATE_BUFFER) + { + ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF); + } + } + + /* Now we got rid of these two... */ + Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); + + /* Check if there's an MDL */ + if ((Mdl = Irp->MdlAddress)) + { + /* Clear all of them */ + do + { + NextMdl = Mdl->Next; + IoFreeMdl(Mdl); + Mdl = NextMdl; + } while (Mdl); + } + Irp->MdlAddress = NULL; + + /* Remove the IRP from the list of Thread Pending IRPs */ + RemoveEntryList(&Irp->ThreadListEntry); + InitializeListHead(&Irp->ThreadListEntry); + + if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->PendingReturned) + { + _SEH_TRY + { + /* Save the IOSB Information */ + *Irp->UserIosb = Irp->IoStatus; + } + _SEH_HANDLE + { + /* Ignore any error */ + } + _SEH_END; + + if (FileObject) + { + if (FileObject->Flags & FO_SYNCHRONOUS_IO) + { + /* Set the Status */ + FileObject->FinalStatus = Irp->IoStatus.Status; + + /* FIXME: Remove this check when I/O code is fixed */ + if (UserEvent != &FileObject->Event) + { + /* Signal Event */ + KeSetEvent(&FileObject->Event, 0, FALSE); + } + } + } + + /* Signal the user event, if one exist */ + if (UserEvent) + { + KeSetEvent(UserEvent, 0, FALSE); + } + + /* Now call the User APC if one was requested */ + if (Irp->Overlay.AsynchronousParameters.UserApcRoutine) + { + KeInitializeApc(&Irp->Tail.Apc, + KeGetCurrentThread(), + CurrentApcEnvironment, + IopFreeIrpKernelApc, + IopAbortIrpKernelApc, + (PKNORMAL_ROUTINE)Irp->Overlay.AsynchronousParameters.UserApcRoutine, + Irp->RequestorMode, + Irp->Overlay.AsynchronousParameters.UserApcContext); + + KeInsertQueueApc(&Irp->Tail.Apc, + Irp->UserIosb, + NULL, + 2); + Irp = NULL; + } + else if (FileObject && FileObject->CompletionContext) + { + /* Call the IO Completion Port if we have one, instead */ + IoSetIoCompletion(FileObject->CompletionContext->Port, + FileObject->CompletionContext->Key, + Irp->Overlay.AsynchronousParameters.UserApcContext, + Irp->IoStatus.Status, + Irp->IoStatus.Information, + FALSE); + Irp = NULL; + } + } + + /* Free the Irp if it hasn't already */ + if (Irp) IoFreeIrp(Irp); + + if (FileObject) + { + /* Dereference the user event, if it is an event object */ + /* FIXME: Remove last check when I/O code is fixed */ + if (UserEvent && !SyncIrp && UserEvent != &FileObject->Event) + { + ObDereferenceObject(UserEvent); + } + + /* Dereference the File Object */ + ObDereferenceObject(FileObject); + } +} + /* FUNCTIONS *****************************************************************/
/* @@ -628,11 +809,7 @@ #endif /* * @implemented - */ -VOID FASTCALL -IofCompleteRequest(PIRP Irp, - CCHAR PriorityBoost) -/* + * * FUNCTION: Indicates the caller has finished all processing for a given * I/O request and is returning the given IRP to the I/O manager * ARGUMENTS: @@ -640,211 +817,190 @@ * PriorityBoost = Increment by which to boost the priority of the * thread making the request */ +VOID +FASTCALL +IofCompleteRequest(PIRP Irp, + CCHAR PriorityBoost) { - ULONG i; - NTSTATUS Status; - PFILE_OBJECT OriginalFileObject; - PDEVICE_OBJECT DeviceObject; - KIRQL oldIrql; - PMDL Mdl; - PIO_STACK_LOCATION Stack = (PIO_STACK_LOCATION)(Irp + 1); + PIO_STACK_LOCATION StackPtr; + PDEVICE_OBJECT DeviceObject; + PFILE_OBJECT FileObject = Irp->Tail.Overlay.OriginalFileObject; + PETHREAD Thread = Irp->Tail.Overlay.Thread; + NTSTATUS Status; + PMDL Mdl;
- DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n", - Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread()); + DPRINT("IofCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n", + Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
- ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); - ASSERT(Irp->CancelRoutine == NULL); - ASSERT(Irp->IoStatus.Status != STATUS_PENDING); + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + ASSERT(!Irp->CancelRoutine); + ASSERT(Irp->IoStatus.Status != STATUS_PENDING); + + /* Get the Current Stack */ + StackPtr = IoGetCurrentIrpStackLocation(Irp); + IoSkipCurrentIrpStackLocation(Irp); + + /* Loop the Stacks and complete the IRPs */ + for (;Irp->CurrentLocation <= (Irp->StackCount + 1); StackPtr++) + { + /* Set Pending Returned */ + Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED; + + /* + * Completion routines expect the current irp stack location to be the same as when + * IoSetCompletionRoutine was called to set them. A side effect is that completion + * routines set by highest level drivers without their own stack location will receive + * an invalid current stack location (at least it should be considered as invalid). + * Since the DeviceObject argument passed is taken from the current stack, this value + * is also invalid (NULL). + */ + if (Irp->CurrentLocation == (Irp->StackCount + 1)) + { + DeviceObject = NULL; + } + else + { + DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject; + }
- Irp->PendingReturned = IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED; - - /* - * Run the completion routines. - */ + /* Check if there is a Completion Routine to Call */ + if ((NT_SUCCESS(Irp->IoStatus.Status) && + (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) || + (!NT_SUCCESS(Irp->IoStatus.Status) && + (StackPtr->Control & SL_INVOKE_ON_ERROR)) || + (Irp->Cancel && (StackPtr->Control & SL_INVOKE_ON_CANCEL))) + { + /* Call it */ + Status = StackPtr->CompletionRoutine(DeviceObject, + Irp, + StackPtr->Context);
- for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++) - { - /* - Completion routines expect the current irp stack location to be the same as when - IoSetCompletionRoutine was called to set them. A side effect is that completion - routines set by highest level drivers without their own stack location will receive - an invalid current stack location (at least it should be considered as invalid). - Since the DeviceObject argument passed is taken from the current stack, this value - is also invalid (NULL). - */ - if (Irp->CurrentLocation < Irp->StackCount - 1) - { - IoSkipCurrentIrpStackLocation(Irp); - DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject; - } - else - { - DeviceObject = NULL; - } + /* Don't touch the Packet if this was returned. It might be gone! */ + if (Status == STATUS_MORE_PROCESSING_REQUIRED) return; + } + else + { + if ((Irp->CurrentLocation <= Irp->StackCount) && (Irp->PendingReturned)) + { + if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED) + { + Irp->PendingReturned = TRUE; + } + } + } + + /* Move to next stack */ + IoSkipCurrentIrpStackLocation(Irp); + }
- if (Stack[i].CompletionRoutine != NULL && - ((NT_SUCCESS(Irp->IoStatus.Status) && (Stack[i].Control & SL_INVOKE_ON_SUCCESS)) || - (!NT_SUCCESS(Irp->IoStatus.Status) && (Stack[i].Control & SL_INVOKE_ON_ERROR)) || - (Irp->Cancel && (Stack[i].Control & SL_INVOKE_ON_CANCEL)))) - { - Status = Stack[i].CompletionRoutine(DeviceObject, - Irp, - Stack[i].Context); + /* Windows NT File System Internals, page 165 */ + if (Irp->Flags & IRP_ASSOCIATED_IRP) + { + ULONG MasterIrpCount; + PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp;
- if (Status == STATUS_MORE_PROCESSING_REQUIRED) - { - return; - } - } - - if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED) - { - Irp->PendingReturned = TRUE; - } - } + DPRINT("Handling Associated IRP\n"); + /* This should never happen! */ + ASSERT(IsListEmpty(&Irp->ThreadListEntry));
- /* Windows NT File System Internals, page 165 */ - if (Irp->Flags & IRP_ASSOCIATED_IRP) - { - ULONG MasterIrpCount; - PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp; - - /* This should never happen! */ - ASSERT(IsListEmpty(&Irp->ThreadListEntry)); - - MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount); - while ((Mdl = Irp->MdlAddress)) - { - Irp->MdlAddress = Mdl->Next; - IoFreeMdl(Mdl); - } - IoFreeIrp(Irp); - if (MasterIrpCount == 0) - { - IofCompleteRequest(MasterIrp, IO_NO_INCREMENT); - } - return; - } - - /* - * Were done calling completion routines. Now do any cleanup that can be - * done in an arbitrarily context. - */ - - /* Windows NT File System Internals, page 165 */ - if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION)) - { - /* This should never happen! */ - ASSERT(IsListEmpty(&Irp->ThreadListEntry)); - - /* - * If MDL_IO_PAGE_READ is set, then the caller is responsible - * for deallocating of the mdl. - */ - if (Irp->Flags & IRP_PAGING_IO && - Irp->MdlAddress && - !(Irp->MdlAddress->MdlFlags & MDL_IO_PAGE_READ)) - { - - if (Irp->MdlAddress->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) - { - MmUnmapLockedPages(Irp->MdlAddress->MappedSystemVa, Irp->MdlAddress); - } - - ExFreePool(Irp->MdlAddress); - } - - if (Irp->UserIosb) - { - _SEH_TRY - { - *Irp->UserIosb = Irp->IoStatus; - } - _SEH_HANDLE - { - DPRINT1("Unable to set UserIosb (at 0x%x) to 0x%x, Error: 0x%x\n", - Irp->UserIosb, Irp->IoStatus, _SEH_GetExceptionCode()); - } - _SEH_END; - } - - if (Irp->UserEvent) - { - KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE); - } + /* Decrement and get the old count */ + MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount); + + /* Free MDLs and IRP */ + while ((Mdl = Irp->MdlAddress)) + { + Irp->MdlAddress = Mdl->Next; + IoFreeMdl(Mdl); + } + IoFreeIrp(Irp);
- /* io manager frees the irp for close operations */ -// if (Irp->Flags & IRP_PAGING_IO) -// { - IoFreeIrp(Irp); -// } - - return; - } - - - /* - Hi Dave, - - I went through my old notes. You are correct and in most cases - IoCompleteRequest() will issue an MmUnlockPages() for each MDL in the IRP - chain. There are however few exceptions: one is MDLs for associated IRPs, - it's expected that those MDLs have been initialized with - IoBuildPartialMdl(). Another exception is PAGING_IO irps, the i/o completion - code doesn't do anything to MDLs of those IRPs. - - sara - -*/ - + /* Complete the Master IRP */ + if (!MasterIrpCount) IofCompleteRequest(MasterIrp, IO_NO_INCREMENT); + return; + }
- for (Mdl = Irp->MdlAddress; Mdl; Mdl = Mdl->Next) - { - /* - * Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called - * on this mdl, this mapping (if any) is also undone by MmUnlockPages. - */ - MmUnlockPages(Mdl); - } - - //Windows NT File System Internals, page 154 - OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject; + /* Windows NT File System Internals, page 165 */ + if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION)) + { + DPRINT("Handling Paging or Close I/O\n"); + /* This should never happen! */ + ASSERT(IsListEmpty(&Irp->ThreadListEntry));
- if (Irp->PendingReturned || KeGetCurrentIrql() == DISPATCH_LEVEL) - { - BOOLEAN bStatus; - - DPRINT("Dispatching APC\n"); - - KeInitializeApc( &Irp->Tail.Apc, - &Irp->Tail.Overlay.Thread->Tcb, - Irp->ApcEnvironment, - IoSecondStageCompletion,//kernel routine + /* Handle a Close Operation or Sync Paging I/O (see page 165) */ + if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION)) + { + /* Set the I/O Status and Signal the Event */ + DPRINT("Handling Sync Paging or Close I/O\n"); + *Irp->UserIosb = Irp->IoStatus; + KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE); + + /* Free the IRP for a Paging I/O Only, Close is handled by us */ + if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) + { + DPRINT("Handling Sync Paging I/O\n"); + IoFreeIrp(Irp); + } + } + else + { + DPRINT1("BUG BUG, YOU SHOULDNT BE HERE\n"); + #if 0 + /* Page 166 */ + /* When we'll actually support Async Paging I/O Properly... */ + KeInitializeApc(&Irp->Tail.Apc + &Irp->tail.Overlay.Thread->Tcb, + Irp->ApcEnvironment, + IopCompletePageWrite, + NULL, + NULL, + KernelMode, + NULL); + KeInsertQueueApc(&Irp->Tail.Apc, NULL, - (PKNORMAL_ROUTINE) NULL, - KernelMode, - NULL); - - bStatus = KeInsertQueueApc(&Irp->Tail.Apc, - (PVOID)OriginalFileObject, - NULL, // This is used for REPARSE stuff - PriorityBoost); + NULL, + PriorityBoost); + #endif + } + return; + }
- if (bStatus == FALSE) - { - DPRINT1("Error queueing APC for thread. Thread has probably exited.\n"); - } + /* Unlock MDL Pages, page 167. */ + while ((Mdl = Irp->MdlAddress)) + { + DPRINT("Unlocking MDL: %x\n", Mdl); + Irp->MdlAddress = Mdl->Next; + MmUnlockPages(Mdl); + }
- DPRINT("Finished dispatching APC\n"); - } - else - { - DPRINT("Calling IoSecondStageCompletion routine directly\n"); - KeRaiseIrql(APC_LEVEL, &oldIrql); - IoSecondStageCompletion(&Irp->Tail.Apc,NULL,NULL,(PVOID)&OriginalFileObj ect, NULL); - KeLowerIrql(oldIrql); - DPRINT("Finished completition routine\n"); - } + /* Check if we should exit because of a Deferred I/O (page 168) */ + if (Irp->Flags & IRP_DEFER_IO_COMPLETION && !Irp->PendingReturned) + { + DPRINT("Quick return\n"); + return; + } + + /* Now queue the special APC */ + if (!Irp->Cancel) + { + DPRINT("KMODE APC QUEUE\n"); + KeInitializeApc(&Irp->Tail.Apc, + &Thread->Tcb, + Irp->ApcEnvironment, + IopCompleteRequest, + NULL, + (PKNORMAL_ROUTINE) NULL, + KernelMode, + NULL); + KeInsertQueueApc(&Irp->Tail.Apc, + FileObject, + NULL, /* This is used for REPARSE stuff */ + PriorityBoost); + } + else + { + /* The IRP just got cancelled... don't think this happens in ROS yet */ + DPRINT1("The IRP was cancelled. Go Bug Alex\n"); + } }
/* @@ -942,7 +1098,7 @@ Irp->Type = IO_TYPE_IRP; Irp->Size = PacketSize; Irp->StackCount = StackSize; - Irp->CurrentLocation = StackSize; + Irp->CurrentLocation = StackSize + 1; Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex; Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
@@ -1181,183 +1337,4 @@ return IofCallDriver(DeviceObject, Irp); }
-VOID -STDCALL -IoSecondStageCompletion_KernelApcRoutine(PKAPC Apc, - PKNORMAL_ROUTINE *NormalRoutine, - PVOID *NormalContext, - PVOID *SystemArgument1, - PVOID *SystemArgument2) -{ - /* Free the IRP */ - IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc)); -} - -VOID -STDCALL -IoSecondStageCompletion_RundownApcRoutine(PKAPC Apc) -{ - /* Free the IRP */ - IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc)); -} - -/* - * FUNCTION: Performs the second stage of irp completion for read/write irps - * - * Called as a special kernel APC kernel-routine or directly from IofCompleteRequest() - * - * Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION) - * or IRP_CLOSE_OPERATION (IRP_MJ_CLOSE and IRP_MJ_CLEANUP) here since their - * cleanup/completion is fully taken care of in IoCompleteRequest. - * -Gunnar - */ -VOID -STDCALL -IoSecondStageCompletion(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArgument2) -{ - PFILE_OBJECT FileObject; - PIRP Irp; - PMDL Mdl, NextMdl; - PKEVENT UserEvent; - BOOLEAN SyncIrp; - - if (Apc) DPRINT("IoSecondStageCompletition with APC: %x\n", Apc); - - /* Get data from the APC */ - FileObject = (PFILE_OBJECT)(*SystemArgument1); - Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc); - DPRINT("IoSecondStageCompletition, %x\n", Irp); - - /* Save the User Event */ - UserEvent = Irp->UserEvent; - - /* Remember if the IRP is Sync or not */ - SyncIrp = Irp->Flags & IRP_SYNCHRONOUS_API ? TRUE : FALSE; - - /* Handle Buffered case first */ - if (Irp->Flags & IRP_BUFFERED_IO) - { - /* Check if we have an input buffer and if we suceeded */ - if (Irp->Flags & IRP_INPUT_OPERATION && NT_SUCCESS(Irp->IoStatus.Status)) - { - /* Copy the buffer back to the user */ - RtlCopyMemory(Irp->UserBuffer, - Irp->AssociatedIrp.SystemBuffer, - Irp->IoStatus.Information); - } - - /* Also check if we should de-allocate it */ - if (Irp->Flags & IRP_DEALLOCATE_BUFFER) - { - ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF); - } - } - - /* Now we got rid of these two... */ - Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); - - /* Check if there's an MDL */ - if ((Mdl = Irp->MdlAddress)) - { - /* Clear all of them */ - do - { - NextMdl = Mdl->Next; - IoFreeMdl(Mdl); - Mdl = NextMdl; - } while (Mdl); - } - Irp->MdlAddress = NULL; - - /* Remove the IRP from the list of Thread Pending IRPs */ - RemoveEntryList(&Irp->ThreadListEntry); - InitializeListHead(&Irp->ThreadListEntry); - - if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->PendingReturned) - { - _SEH_TRY - { - /* Save the IOSB Information */ - *Irp->UserIosb = Irp->IoStatus; - } - _SEH_HANDLE - { - /* Ignore any error */ - } - _SEH_END; - - if (FileObject) - { - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - /* Set the Status */ - FileObject->FinalStatus = Irp->IoStatus.Status; - - /* FIXME: Remove this check when I/O code is fixed */ - if (UserEvent != &FileObject->Event) - { - /* Signal Event */ - KeSetEvent(&FileObject->Event, 0, FALSE); - } - } - } - - /* Signal the user event, if one exist */ - if (UserEvent) - { - KeSetEvent(UserEvent, 0, FALSE); - } - - /* Now call the User APC if one was requested */ - if (Irp->Overlay.AsynchronousParameters.UserApcRoutine) - { - KeInitializeApc(&Irp->Tail.Apc, - KeGetCurrentThread(), - CurrentApcEnvironment, - IoSecondStageCompletion_KernelApcRoutine, - IoSecondStageCompletion_RundownApcRoutine, - (PKNORMAL_ROUTINE)Irp->Overlay.AsynchronousParameters.UserApcRoutine, - Irp->RequestorMode, - Irp->Overlay.AsynchronousParameters.UserApcContext); - - KeInsertQueueApc(&Irp->Tail.Apc, - Irp->UserIosb, - NULL, - 2); - Irp = NULL; - } - else if (FileObject && FileObject->CompletionContext) - { - /* Call the IO Completion Port if we have one, instead */ - IoSetIoCompletion(FileObject->CompletionContext->Port, - FileObject->CompletionContext->Key, - Irp->Overlay.AsynchronousParameters.UserApcContext, - Irp->IoStatus.Status, - Irp->IoStatus.Information, - FALSE); - Irp = NULL; - } - } - - /* Free the Irp if it hasn't already */ - if (Irp) IoFreeIrp(Irp); - - if (FileObject) - { - /* Dereference the user event, if it is an event object */ - /* FIXME: Remove last check when I/O code is fixed */ - if (UserEvent && !SyncIrp && UserEvent != &FileObject->Event) - { - ObDereferenceObject(UserEvent); - } - - /* Dereference the File Object */ - ObDereferenceObject(FileObject); - } -} - /* EOF */