📄 irp.c
字号:
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/irp.c
* PURPOSE: IRP Handling Functions
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Gunnar Dalsnes
* Filip Navara (navaraf@reactos.org)
*/
/* INCLUDES ****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* Undefine some macros we implement here */
#undef IoCallDriver
#undef IoCompleteRequest
/* PRIVATE FUNCTIONS ********************************************************/
VOID
NTAPI
IopFreeIrpKernelApc(IN PKAPC Apc,
IN PKNORMAL_ROUTINE *NormalRoutine,
IN PVOID *NormalContext,
IN PVOID *SystemArgument1,
IN PVOID *SystemArgument2)
{
/* Free the IRP */
IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
}
VOID
NTAPI
IopAbortIrpKernelApc(IN PKAPC Apc)
{
/* Free the IRP */
IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
}
NTSTATUS
NTAPI
IopCleanupFailedIrp(IN PFILE_OBJECT FileObject,
IN PKEVENT EventObject OPTIONAL,
IN PVOID Buffer OPTIONAL)
{
PAGED_CODE();
/* Dereference the event */
if (EventObject) ObDereferenceObject(EventObject);
/* Free a buffer, if any */
if (Buffer) ExFreePool(Buffer);
/* If this was a file opened for synch I/O, then unlock it */
if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
/* Now dereference it and return */
ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
VOID
NTAPI
IopAbortInterruptedIrp(IN PKEVENT EventObject,
IN PIRP Irp)
{
KIRQL OldIrql;
BOOLEAN CancelResult;
LARGE_INTEGER Wait;
PAGED_CODE();
/* Raise IRQL to APC */
KeRaiseIrql(APC_LEVEL, &OldIrql);
/* Check if nobody completed it yet */
if (!KeReadStateEvent(EventObject))
{
/* First, cancel it */
CancelResult = IoCancelIrp(Irp);
KeLowerIrql(OldIrql);
/* Check if we cancelled it */
if (CancelResult)
{
/* Wait for the IRP to be cancelled */
Wait.QuadPart = -100000;
while (!KeReadStateEvent(EventObject))
{
/* Delay indefintely */
KeDelayExecutionThread(KernelMode, FALSE, &Wait);
}
}
else
{
/* No cancellation done, so wait for the I/O system to kill it */
KeWaitForSingleObject(EventObject,
Executive,
KernelMode,
FALSE,
NULL);
}
}
else
{
/* We got preempted, so give up */
KeLowerIrql(OldIrql);
}
}
VOID
NTAPI
IopRemoveThreadIrp(VOID)
{
KIRQL OldIrql;
PIRP DeadIrp;
PETHREAD IrpThread;
PLIST_ENTRY IrpEntry;
PIO_ERROR_LOG_PACKET ErrorLogEntry;
PDEVICE_OBJECT DeviceObject = NULL;
PIO_STACK_LOCATION IoStackLocation;
/* First, raise to APC to protect IrpList */
KeRaiseIrql(APC_LEVEL, &OldIrql);
/* Get the Thread and check the list */
IrpThread = PsGetCurrentThread();
if (IsListEmpty(&IrpThread->IrpList))
{
/* It got completed now, so quit */
KeLowerIrql(OldIrql);
return;
}
/* Get the misbehaving IRP */
IrpEntry = IrpThread->IrpList.Flink;
DeadIrp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
IOTRACE(IO_IRP_DEBUG,
"%s - Deassociating IRP %p for %p\n",
__FUNCTION__,
DeadIrp,
IrpThread);
/* Don't cancel the IRP if it's already been completed far */
if (DeadIrp->CurrentLocation == (DeadIrp->StackCount + 2))
{
/* Return */
KeLowerIrql(OldIrql);
return;
}
/* Disown the IRP! */
DeadIrp->Tail.Overlay.Thread = NULL;
RemoveHeadList(&IrpThread->IrpList);
InitializeListHead(&DeadIrp->ThreadListEntry);
/* Get the stack location and check if it's valid */
IoStackLocation = IoGetCurrentIrpStackLocation(DeadIrp);
if (DeadIrp->CurrentLocation <= DeadIrp->StackCount)
{
/* Get the device object */
DeviceObject = IoStackLocation->DeviceObject;
}
/* Lower IRQL now, since we have the pointers we need */
KeLowerIrql(OldIrql);
/* Check if we can send an Error Log Entry*/
if (DeviceObject)
{
/* Allocate an entry */
ErrorLogEntry = IoAllocateErrorLogEntry(DeviceObject,
sizeof(IO_ERROR_LOG_PACKET));
if (ErrorLogEntry)
{
/* Write the entry */
ErrorLogEntry->ErrorCode = 0xBAADF00D; /* FIXME */
IoWriteErrorLogEntry(ErrorLogEntry);
}
}
}
VOID
NTAPI
IopCleanupIrp(IN PIRP Irp,
IN PFILE_OBJECT FileObject)
{
PMDL Mdl;
IOTRACE(IO_IRP_DEBUG,
"%s - Cleaning IRP %p for %p\n",
__FUNCTION__,
Irp,
FileObject);
/* Check if there's an MDL */
while ((Mdl = Irp->MdlAddress))
{
/* Clear all of them */
Irp->MdlAddress = Mdl->Next;
IoFreeMdl(Mdl);
}
/* Check if the IRP has system buffer */
if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
{
/* Free the buffer */
ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
}
/* Check if this IRP has a user event, a file object, and is async */
if ((Irp->UserEvent) &&
!(Irp->Flags & IRP_SYNCHRONOUS_API) &&
(FileObject))
{
/* Dereference the User Event */
ObDereferenceObject(Irp->UserEvent);
}
/* Check if we have a file object and this isn't a create operation */
if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
{
/* Dereference the file object */
ObDereferenceObject(FileObject);
}
/* Free the IRP */
IoFreeIrp(Irp);
}
VOID
NTAPI
IopCompleteRequest(IN PKAPC Apc,
IN PKNORMAL_ROUTINE* NormalRoutine,
IN PVOID* NormalContext,
IN PVOID* SystemArgument1,
IN PVOID* SystemArgument2)
{
PFILE_OBJECT FileObject;
PIRP Irp;
PMDL Mdl, NextMdl;
PVOID Port = NULL, Key = NULL;
BOOLEAN SignaledCreateRequest = FALSE;
/* Get data from the APC */
FileObject = (PFILE_OBJECT)*SystemArgument1;
Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
IOTRACE(IO_IRP_DEBUG,
"%s - Completing IRP %p for %p\n",
__FUNCTION__,
Irp,
FileObject);
/* Sanity check */
ASSERT(Irp->IoStatus.Status != 0xFFFFFFFF);
/* Check if we have a file object */
if (*SystemArgument2)
{
/* Check if we're reparsing */
if ((Irp->IoStatus.Status == STATUS_REPARSE) &&
(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT))
{
/* We should never get this yet */
DPRINT1("Reparse support not yet present!\n");
while (TRUE);
}
}
/* Handle Buffered case first */
if (Irp->Flags & IRP_BUFFERED_IO)
{
/* Check if we have an input buffer and if we succeeded */
if ((Irp->Flags & IRP_INPUT_OPERATION) &&
(Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED) &&
!(NT_ERROR(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)
{
/* Deallocate it */
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 */
for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
{
/* Free it */
NextMdl = Mdl->Next;
IoFreeMdl(Mdl);
}
/* No MDLs left */
Irp->MdlAddress = NULL;
/*
* Check if either the request was completed without any errors
* (but warnings are OK!), or if it was completed with an error, but
* did return from a pending I/O Operation and is not synchronous.
*/
if (!(NT_ERROR(Irp->IoStatus.Status)) ||
(NT_ERROR(Irp->IoStatus.Status) &&
(Irp->PendingReturned) &&
!(IsIrpSynchronous(Irp, FileObject))))
{
/* Get any information we need from the FO before we kill it */
if ((FileObject) && (FileObject->CompletionContext))
{
/* Save Completion Data */
Port = FileObject->CompletionContext->Port;
Key = FileObject->CompletionContext->Key;
}
/* Use SEH to make sure we don't write somewhere invalid */
_SEH_TRY
{
/* Save the IOSB Information */
*Irp->UserIosb = Irp->IoStatus;
}
_SEH_HANDLE
{
/* Ignore any error */
}
_SEH_END;
/* Check if we have an event or a file object */
if (Irp->UserEvent)
{
/* At the very least, this is a PKEVENT, so signal it always */
KeSetEvent(Irp->UserEvent, 0, FALSE);
/* Check if we also have a File Object */
if (FileObject)
{
/* Check if this is an Asynch API */
if (!(Irp->Flags & IRP_SYNCHRONOUS_API))
{
/* HACK */
if (*((PULONG)(Irp->UserEvent) - 1) != 0x87878787)
{
/* Dereference the event */
ObDereferenceObject(Irp->UserEvent);
}
else
{
DPRINT1("Not an executive event -- should not be dereferenced\n");
}
}
/*
* Now, if this is a Synch I/O File Object, then this event is
* NOT an actual Executive Event, so we won't dereference it,
* and instead, we will signal the File Object
*/
if ((FileObject->Flags & FO_SYNCHRONOUS_IO) &&
!(Irp->Flags & IRP_OB_QUERY_NAME))
{
/* Signal the file object and set the status */
KeSetEvent(&FileObject->Event, 0, FALSE);
FileObject->FinalStatus = Irp->IoStatus.Status;
}
/*
* This could also be a create operation, in which case we want
* to make sure there's no APC fired.
*/
if (Irp->Flags & IRP_CREATE_OPERATION)
{
/* Clear the APC Routine and remember this */
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
SignaledCreateRequest = TRUE;
}
}
}
else if (FileObject)
{
/* Signal the file object and set the status */
KeSetEvent(&FileObject->Event, 0, FALSE);
FileObject->FinalStatus = Irp->IoStatus.Status;
/*
* This could also be a create operation, in which case we want
* to make sure there's no APC fired.
*/
if (Irp->Flags & IRP_CREATE_OPERATION)
{
/* Clear the APC Routine and remember this */
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
SignaledCreateRequest = TRUE;
}
}
/* Now that we've signaled the events, de-associate the IRP */
IopUnQueueIrpFromThread(Irp);
/* Now check if a User APC Routine was requested */
if (Irp->Overlay.AsynchronousParameters.UserApcRoutine)
{
/* Initialize it */
KeInitializeApc(&Irp->Tail.Apc,
KeGetCurrentThread(),
CurrentApcEnvironment,
IopFreeIrpKernelApc,
IopAbortIrpKernelApc,
(PKNORMAL_ROUTINE)Irp->
Overlay.AsynchronousParameters.UserApcRoutine,
Irp->RequestorMode,
Irp->
Overlay.AsynchronousParameters.UserApcContext);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -