mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 09:43:04 +00:00
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
svn path=/trunk/; revision=15069
This commit is contained in:
parent
7ed5318927
commit
ee7e1eefbe
1 changed files with 357 additions and 380 deletions
|
@ -19,6 +19,187 @@
|
||||||
#define TAG_IRP TAG('I', 'R', 'P', ' ')
|
#define TAG_IRP TAG('I', 'R', 'P', ' ')
|
||||||
#define TAG_SYS_BUF TAG('S', 'Y', 'S' , 'B')
|
#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 *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -628,11 +809,7 @@ IofCallDriver(PDEVICE_OBJECT DeviceObject,
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*
|
||||||
VOID FASTCALL
|
|
||||||
IofCompleteRequest(PIRP Irp,
|
|
||||||
CCHAR PriorityBoost)
|
|
||||||
/*
|
|
||||||
* FUNCTION: Indicates the caller has finished all processing for a given
|
* 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
|
* I/O request and is returning the given IRP to the I/O manager
|
||||||
* ARGUMENTS:
|
* ARGUMENTS:
|
||||||
|
@ -640,68 +817,81 @@ IofCompleteRequest(PIRP Irp,
|
||||||
* PriorityBoost = Increment by which to boost the priority of the
|
* PriorityBoost = Increment by which to boost the priority of the
|
||||||
* thread making the request
|
* thread making the request
|
||||||
*/
|
*/
|
||||||
|
VOID
|
||||||
|
FASTCALL
|
||||||
|
IofCompleteRequest(PIRP Irp,
|
||||||
|
CCHAR PriorityBoost)
|
||||||
{
|
{
|
||||||
ULONG i;
|
PIO_STACK_LOCATION StackPtr;
|
||||||
NTSTATUS Status;
|
|
||||||
PFILE_OBJECT OriginalFileObject;
|
|
||||||
PDEVICE_OBJECT DeviceObject;
|
PDEVICE_OBJECT DeviceObject;
|
||||||
KIRQL oldIrql;
|
PFILE_OBJECT FileObject = Irp->Tail.Overlay.OriginalFileObject;
|
||||||
|
PETHREAD Thread = Irp->Tail.Overlay.Thread;
|
||||||
|
NTSTATUS Status;
|
||||||
PMDL Mdl;
|
PMDL Mdl;
|
||||||
PIO_STACK_LOCATION Stack = (PIO_STACK_LOCATION)(Irp + 1);
|
|
||||||
|
|
||||||
DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
|
DPRINT("IofCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
|
||||||
Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
|
Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
|
||||||
|
|
||||||
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
||||||
ASSERT(Irp->CancelRoutine == NULL);
|
ASSERT(!Irp->CancelRoutine);
|
||||||
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
|
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
|
||||||
|
|
||||||
Irp->PendingReturned = IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED;
|
/* Get the Current Stack */
|
||||||
|
StackPtr = IoGetCurrentIrpStackLocation(Irp);
|
||||||
/*
|
|
||||||
* Run the completion routines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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);
|
IoSkipCurrentIrpStackLocation(Irp);
|
||||||
DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
|
|
||||||
}
|
/* Loop the Stacks and complete the IRPs */
|
||||||
else
|
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;
|
DeviceObject = NULL;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
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,
|
DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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,
|
Irp,
|
||||||
Stack[i].Context);
|
StackPtr->Context);
|
||||||
|
|
||||||
if (Status == STATUS_MORE_PROCESSING_REQUIRED)
|
/* 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))
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
|
if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
|
||||||
{
|
{
|
||||||
Irp->PendingReturned = TRUE;
|
Irp->PendingReturned = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move to next stack */
|
||||||
|
IoSkipCurrentIrpStackLocation(Irp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Windows NT File System Internals, page 165 */
|
/* Windows NT File System Internals, page 165 */
|
||||||
if (Irp->Flags & IRP_ASSOCIATED_IRP)
|
if (Irp->Flags & IRP_ASSOCIATED_IRP)
|
||||||
|
@ -709,141 +899,107 @@ IofCompleteRequest(PIRP Irp,
|
||||||
ULONG MasterIrpCount;
|
ULONG MasterIrpCount;
|
||||||
PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp;
|
PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp;
|
||||||
|
|
||||||
|
DPRINT("Handling Associated IRP\n");
|
||||||
/* This should never happen! */
|
/* This should never happen! */
|
||||||
ASSERT(IsListEmpty(&Irp->ThreadListEntry));
|
ASSERT(IsListEmpty(&Irp->ThreadListEntry));
|
||||||
|
|
||||||
|
/* Decrement and get the old count */
|
||||||
MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
|
MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
|
||||||
|
|
||||||
|
/* Free MDLs and IRP */
|
||||||
while ((Mdl = Irp->MdlAddress))
|
while ((Mdl = Irp->MdlAddress))
|
||||||
{
|
{
|
||||||
Irp->MdlAddress = Mdl->Next;
|
Irp->MdlAddress = Mdl->Next;
|
||||||
IoFreeMdl(Mdl);
|
IoFreeMdl(Mdl);
|
||||||
}
|
}
|
||||||
IoFreeIrp(Irp);
|
IoFreeIrp(Irp);
|
||||||
if (MasterIrpCount == 0)
|
|
||||||
{
|
/* Complete the Master IRP */
|
||||||
IofCompleteRequest(MasterIrp, IO_NO_INCREMENT);
|
if (!MasterIrpCount) IofCompleteRequest(MasterIrp, IO_NO_INCREMENT);
|
||||||
}
|
|
||||||
return;
|
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 */
|
/* Windows NT File System Internals, page 165 */
|
||||||
if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION))
|
if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION))
|
||||||
{
|
{
|
||||||
|
DPRINT("Handling Paging or Close I/O\n");
|
||||||
/* This should never happen! */
|
/* This should never happen! */
|
||||||
ASSERT(IsListEmpty(&Irp->ThreadListEntry));
|
ASSERT(IsListEmpty(&Irp->ThreadListEntry));
|
||||||
|
|
||||||
/*
|
/* Handle a Close Operation or Sync Paging I/O (see page 165) */
|
||||||
* If MDL_IO_PAGE_READ is set, then the caller is responsible
|
if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))
|
||||||
* 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
|
|
||||||
{
|
{
|
||||||
|
/* Set the I/O Status and Signal the Event */
|
||||||
|
DPRINT("Handling Sync Paging or Close I/O\n");
|
||||||
*Irp->UserIosb = Irp->IoStatus;
|
*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);
|
KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
|
||||||
}
|
|
||||||
|
|
||||||
/* io manager frees the irp for close operations */
|
/* Free the IRP for a Paging I/O Only, Close is handled by us */
|
||||||
// if (Irp->Flags & IRP_PAGING_IO)
|
if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO)
|
||||||
// {
|
{
|
||||||
|
DPRINT("Handling Sync Paging I/O\n");
|
||||||
IoFreeIrp(Irp);
|
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,
|
||||||
|
NULL,
|
||||||
|
PriorityBoost);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unlock MDL Pages, page 167. */
|
||||||
/*
|
while ((Mdl = Irp->MdlAddress))
|
||||||
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
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
for (Mdl = Irp->MdlAddress; Mdl; Mdl = Mdl->Next)
|
|
||||||
{
|
{
|
||||||
/*
|
DPRINT("Unlocking MDL: %x\n", Mdl);
|
||||||
* Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called
|
Irp->MdlAddress = Mdl->Next;
|
||||||
* on this mdl, this mapping (if any) is also undone by MmUnlockPages.
|
|
||||||
*/
|
|
||||||
MmUnlockPages(Mdl);
|
MmUnlockPages(Mdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Windows NT File System Internals, page 154
|
/* Check if we should exit because of a Deferred I/O (page 168) */
|
||||||
OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject;
|
if (Irp->Flags & IRP_DEFER_IO_COMPLETION && !Irp->PendingReturned)
|
||||||
|
|
||||||
if (Irp->PendingReturned || KeGetCurrentIrql() == DISPATCH_LEVEL)
|
|
||||||
{
|
{
|
||||||
BOOLEAN bStatus;
|
DPRINT("Quick return\n");
|
||||||
|
return;
|
||||||
DPRINT("Dispatching APC\n");
|
}
|
||||||
|
|
||||||
|
/* Now queue the special APC */
|
||||||
|
if (!Irp->Cancel)
|
||||||
|
{
|
||||||
|
DPRINT("KMODE APC QUEUE\n");
|
||||||
KeInitializeApc(&Irp->Tail.Apc,
|
KeInitializeApc(&Irp->Tail.Apc,
|
||||||
&Irp->Tail.Overlay.Thread->Tcb,
|
&Thread->Tcb,
|
||||||
Irp->ApcEnvironment,
|
Irp->ApcEnvironment,
|
||||||
IoSecondStageCompletion,//kernel routine
|
IopCompleteRequest,
|
||||||
NULL,
|
NULL,
|
||||||
(PKNORMAL_ROUTINE) NULL,
|
(PKNORMAL_ROUTINE) NULL,
|
||||||
KernelMode,
|
KernelMode,
|
||||||
NULL);
|
NULL);
|
||||||
|
KeInsertQueueApc(&Irp->Tail.Apc,
|
||||||
bStatus = KeInsertQueueApc(&Irp->Tail.Apc,
|
FileObject,
|
||||||
(PVOID)OriginalFileObject,
|
NULL, /* This is used for REPARSE stuff */
|
||||||
NULL, // This is used for REPARSE stuff
|
|
||||||
PriorityBoost);
|
PriorityBoost);
|
||||||
|
|
||||||
if (bStatus == FALSE)
|
|
||||||
{
|
|
||||||
DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT("Finished dispatching APC\n");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DPRINT("Calling IoSecondStageCompletion routine directly\n");
|
/* The IRP just got cancelled... don't think this happens in ROS yet */
|
||||||
KeRaiseIrql(APC_LEVEL, &oldIrql);
|
DPRINT1("The IRP was cancelled. Go Bug Alex\n");
|
||||||
IoSecondStageCompletion(&Irp->Tail.Apc,NULL,NULL,(PVOID)&OriginalFileObject, NULL);
|
|
||||||
KeLowerIrql(oldIrql);
|
|
||||||
DPRINT("Finished completition routine\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,7 +1098,7 @@ IoInitializeIrp(PIRP Irp,
|
||||||
Irp->Type = IO_TYPE_IRP;
|
Irp->Type = IO_TYPE_IRP;
|
||||||
Irp->Size = PacketSize;
|
Irp->Size = PacketSize;
|
||||||
Irp->StackCount = StackSize;
|
Irp->StackCount = StackSize;
|
||||||
Irp->CurrentLocation = StackSize;
|
Irp->CurrentLocation = StackSize + 1;
|
||||||
Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
|
Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
|
||||||
Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
|
Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
|
||||||
|
|
||||||
|
@ -1181,183 +1337,4 @@ IoSynchronousPageWrite(PFILE_OBJECT FileObject,
|
||||||
return IofCallDriver(DeviceObject, Irp);
|
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 */
|
/* EOF */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue