Fix a FIXME: properly reset timer when re-using a queued IRP for reading.
Also fix a possible race condition between time out DPC and IRP re-use.

Thanks to Thomas for his help with DPC & timers.

CORE-10245

svn path=/trunk/; revision=69483
This commit is contained in:
Pierre Schweitzer 2015-10-10 12:50:33 +00:00
parent 9b2b4cbee8
commit 6da1a0b9b0
3 changed files with 22 additions and 3 deletions

View file

@ -46,6 +46,7 @@ typedef struct _MSFS_DPC_CTX
KTIMER Timer;
KDPC Dpc;
PIO_CSQ Csq;
KEVENT Event;
IO_CSQ_IRP_CONTEXT CsqContext;
} MSFS_DPC_CTX, *PMSFS_DPC_CTX;

View file

@ -117,14 +117,20 @@ MsfsTimeout(PKDPC Dpc,
Context = (PMSFS_DPC_CTX)DeferredContext;
/* Try to get the IRP */
Irp = IoCsqRemoveIrp(Context->Csq, &Context->CsqContext);
if (Irp != NULL)
{
/* It timed out, complete it (it's ours) and free context */
Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ExFreePoolWithTag(Context, 'NFsM');
}
else
{
/* We were racing with writing and failed, signal we're done */
KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
}
ExFreePool(Context);
}
/* EOF */

View file

@ -107,10 +107,12 @@ MsfsRead(PDEVICE_OBJECT DeviceObject,
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(&Context->Event, SynchronizationEvent, FALSE);
IoCsqInsertIrp(&Fcb->CancelSafeQueue, Irp, &Context->CsqContext);
Timer = &Context->Timer;
Dpc = &Context->Dpc;
Context->Csq = &Fcb->CancelSafeQueue;
Irp->Tail.Overlay.DriverContext[0] = Context;
/* No timer for INFINITY_WAIT */
if (Timeout.QuadPart != -1)
@ -139,6 +141,7 @@ MsfsWrite(PDEVICE_OBJECT DeviceObject,
ULONG Length;
PVOID Buffer;
PIRP CsqIrp;
PMSFS_DPC_CTX Context;
DPRINT("MsfsWrite(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
@ -193,7 +196,16 @@ MsfsWrite(PDEVICE_OBJECT DeviceObject,
CsqIrp = IoCsqRemoveNextIrp(&Fcb->CancelSafeQueue, NULL);
if (CsqIrp != NULL)
{
/* FIXME: It is necessary to reset the timers. */
/* Get the context */
Context = CsqIrp->Tail.Overlay.DriverContext[0];
/* DPC was queued, wait for it to fail (IRP is ours) */
if (Fcb->TimeOut.QuadPart != -1 && !KeCancelTimer(&Context->Timer))
{
KeWaitForSingleObject(&Context->Event, Executive, KernelMode, FALSE, NULL);
}
/* Free context & attempt read */
ExFreePoolWithTag(Context, 'NFsM');
MsfsRead(DeviceObject, CsqIrp);
}