Fix filip's fixme and alex's fixme (ie: make IRP cancellation work properly). This should appease Hartmut even more =).

svn path=/trunk/; revision=15794
This commit is contained in:
Alex Ionescu 2005-06-04 21:07:00 +00:00
parent 14245cb4ed
commit 2fb48b3787

View file

@ -37,6 +37,87 @@ IopAbortIrpKernelApc(PKAPC Apc)
IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc)); IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
} }
VOID
STDCALL
IopRemoveThreadIrp(VOID)
{
KIRQL OldIrql;
PIRP DeadIrp;
PETHREAD IrpThread;
PLIST_ENTRY IrpEntry;
PIO_ERROR_LOG_PACKET ErrorLogEntry;
/* 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);
/* Disown the IRP! */
DeadIrp->Tail.Overlay.Thread = NULL;
InitializeListHead(&DeadIrp->ThreadListEntry);
RemoveHeadList(&IrpThread->IrpList);
/* Lower IRQL now */
KeLowerIrql(OldIrql);
/* Check if we can send an Error Log Entry*/
if (DeadIrp->CurrentLocation <= DeadIrp->StackCount)
{
/* Allocate an entry */
ErrorLogEntry = IoAllocateErrorLogEntry(IoGetCurrentIrpStackLocation(DeadIrp)->DeviceObject,
sizeof(IO_ERROR_LOG_PACKET));
/* Write the entry */
ErrorLogEntry->ErrorCode = 0xBAADF00D; /* FIXME */
IoWriteErrorLogEntry(ErrorLogEntry);
}
}
VOID
STDCALL
IopCleanupIrp(PIRP Irp,
PFILE_OBJECT FileObject)
{
PMDL Mdl;
/* Check if there's an MDL */
while ((Mdl = Irp->MdlAddress))
{
/* Clear all of them */
Irp->MdlAddress = Mdl->Next;
IoFreeMdl(Mdl);
}
/* Free the buffer */
if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
{
ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
}
/* Derefernce the User Event */
if (Irp->UserEvent && !(Irp->Flags & IRP_SYNCHRONOUS_API) && FileObject)
{
ObDereferenceObject(Irp->UserEvent);
}
/* Dereference the File Object */
if (FileObject) ObDereferenceObject(FileObject);
/* Free the IRP */
IoFreeIrp(Irp);
}
/* /*
* FUNCTION: Performs the second stage of irp completion for read/write irps * FUNCTION: Performs the second stage of irp completion for read/write irps
* *
@ -884,7 +965,6 @@ IoCancelIrp(PIRP Irp)
* @param Thread * @param Thread
* Thread to cancel requests for. * Thread to cancel requests for.
*/ */
VOID VOID
STDCALL STDCALL
IoCancelThreadIo(PETHREAD Thread) IoCancelThreadIo(PETHREAD Thread)
@ -895,47 +975,44 @@ IoCancelThreadIo(PETHREAD Thread)
ULONG Retries = 3000; ULONG Retries = 3000;
LARGE_INTEGER Interval; LARGE_INTEGER Interval;
/* Raise to APC to protect the IrpList */
OldIrql = KfRaiseIrql(APC_LEVEL); OldIrql = KfRaiseIrql(APC_LEVEL);
/* /* Start by cancelling all the IRPs in the current thread queue. */
* Start by cancelling all the IRPs in the current thread queue.
*/
for (IrpEntry = Thread->IrpList.Flink; for (IrpEntry = Thread->IrpList.Flink;
IrpEntry != &Thread->IrpList; IrpEntry != &Thread->IrpList;
IrpEntry = IrpEntry->Flink) IrpEntry = IrpEntry->Flink)
{ {
/* Get the IRP */
Irp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry); Irp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
/* Cancel it */
IoCancelIrp(Irp); IoCancelIrp(Irp);
} }
/* /* Wait 100 milliseconds */
* Wait till all the IRPs are completed or cancelled. Interval.QuadPart = -1000000;
*/
/* Wait till all the IRPs are completed or cancelled. */
while (!IsListEmpty(&Thread->IrpList)) while (!IsListEmpty(&Thread->IrpList))
{ {
/* Now we can lower */
KfLowerIrql(OldIrql); KfLowerIrql(OldIrql);
/* Wait a short while and then look if all our IRPs were completed. */ /* Wait a short while and then look if all our IRPs were completed. */
Interval.QuadPart = -1000000; /* 100 milliseconds */
KeDelayExecutionThread(KernelMode, FALSE, &Interval); KeDelayExecutionThread(KernelMode, FALSE, &Interval);
/* /*
* Don't stay here forever if some broken driver doesn't complete * Don't stay here forever if some broken driver doesn't complete
* the IRP. * the IRP.
*/ */
if (Retries-- == 0) IopRemoveThreadIrp();
if (Retries-- == 0) /* Raise the IRQL Again */
{
/* FIXME: Handle this gracefully. */
DPRINT1("Thread with dead IRPs!");
ASSERT(FALSE);
}
OldIrql = KfRaiseIrql(APC_LEVEL); OldIrql = KfRaiseIrql(APC_LEVEL);
} }
/* We're done, lower the IRQL */
KfLowerIrql(OldIrql); KfLowerIrql(OldIrql);
} }
@ -1204,8 +1281,29 @@ IofCompleteRequest(PIRP Irp,
} }
else else
{ {
/* The IRP just got cancelled... don't think this happens in ROS yet */ /* The IRP just got cancelled... does a thread still own it? */
DPRINT1("The IRP was cancelled. Go Bug Alex\n"); if ((Thread = Irp->Tail.Overlay.Thread))
{
/* Yes! There is still hope! */
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
{
/* Nothing left for us to do, kill it */
IopCleanupIrp(Irp, FileObject);
}
} }
} }