mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 17:34:57 +00:00
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:
parent
14245cb4ed
commit
2fb48b3787
1 changed files with 141 additions and 43 deletions
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue