- Fix race conditions in read IRP cancellation that resulting in random crashes and hangs
- Fixes MULTIPLE_IRP_COMPLETE_REQUESTS bug checks and failed cancellations resulting in hangs during ntdll:file test

svn path=/trunk/; revision=47470
This commit is contained in:
Cameron Gutman 2010-05-30 22:18:50 +00:00
parent 1c2429510e
commit 5de258d708

View file

@ -51,7 +51,9 @@ NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
PNPFS_DEVICE_EXTENSION DeviceExt; PNPFS_DEVICE_EXTENSION DeviceExt;
PIO_STACK_LOCATION IoStack; PIO_STACK_LOCATION IoStack;
PNPFS_CCB Ccb; PNPFS_CCB Ccb;
BOOLEAN Complete = FALSE; PLIST_ENTRY ListEntry;
PNPFS_THREAD_CONTEXT ThreadContext;
ULONG i;
DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp); DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
@ -67,28 +69,50 @@ NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
switch(IoStack->MajorFunction) switch(IoStack->MajorFunction)
{ {
case IRP_MJ_READ: case IRP_MJ_READ:
if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry) ListEntry = DeviceExt->ThreadListHead.Flink;
while (ListEntry != &DeviceExt->ThreadListHead)
{ {
/* we are not the first in the list, remove an complete us */ ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
RemoveEntryList(&Context->ListEntry); /* Real events start at index 1 */
Complete = TRUE; for (i = 1; i < ThreadContext->Count; i++)
} {
else if (ThreadContext->WaitIrpArray[i] == Irp)
{ {
KeSetEvent(&Ccb->ReadEvent, IO_NO_INCREMENT, FALSE); ASSERT(ThreadContext->WaitObjectArray[i] == Context->WaitEvent);
ThreadContext->WaitIrpArray[i] = NULL;
RemoveEntryList(&Context->ListEntry);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
ExReleaseFastMutex(&Ccb->DataListLock);
KeUnlockMutex(&DeviceExt->PipeListLock);
return;
}
}
ListEntry = ListEntry->Flink;
} }
RemoveEntryList(&Context->ListEntry);
ExReleaseFastMutex(&Ccb->DataListLock);
KeUnlockMutex(&DeviceExt->PipeListLock);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break; break;
default: default:
ASSERT(FALSE); ASSERT(FALSE);
} }
ExReleaseFastMutex(&Ccb->DataListLock);
KeUnlockMutex(&DeviceExt->PipeListLock);
if (Complete)
{
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
} }
static VOID NTAPI static VOID NTAPI
@ -96,7 +120,7 @@ NpfsWaiterThread(PVOID InitContext)
{ {
PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext; PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
ULONG CurrentCount; ULONG CurrentCount;
ULONG Count = 0; ULONG Count = 0, i;
PIRP Irp = NULL; PIRP Irp = NULL;
PIRP NextIrp; PIRP NextIrp;
NTSTATUS Status; NTSTATUS Status;
@ -191,8 +215,20 @@ NpfsWaiterThread(PVOID InitContext)
} }
else else
{ {
/* someone has add a new wait request */ /* someone has add a new wait request or cancelled an old one */
Irp = NULL; Irp = NULL;
/* Look for cancelled requests */
for (i = 1; i < ThreadContext->Count; i++)
{
if (ThreadContext->WaitIrpArray[i] == NULL)
{
ThreadContext->Count--;
ThreadContext->DeviceExt->EmptyWaiterCount++;
ThreadContext->WaitObjectArray[i] = ThreadContext->WaitObjectArray[ThreadContext->Count];
ThreadContext->WaitIrpArray[i] = ThreadContext->WaitIrpArray[ThreadContext->Count];
}
}
} }
if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS) if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
{ {