diff --git a/src/sys/driver.h b/src/sys/driver.h index 85053460..8aa5d764 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -571,7 +571,7 @@ typedef struct LIST_ENTRY PendingIrpList, ProcessIrpList, RetriedIrpList; IO_CSQ PendingIoCsq, ProcessIoCsq, RetriedIoCsq; ULONG IrpTimeout; - ULONG PendingIrpCapacity, PendingIrpCount; + ULONG PendingIrpCapacity, PendingIrpCount, ProcessIrpCount, RetriedIrpCount; VOID (*CompleteCanceledIrp)(PIRP Irp); ULONG ProcessIrpBucketCount; PVOID ProcessIrpBuckets[]; @@ -586,10 +586,13 @@ VOID FspIoqRemoveExpired(FSP_IOQ *Ioq, UINT64 InterruptTime); BOOLEAN FspIoqPostIrpEx(FSP_IOQ *Ioq, PIRP Irp, BOOLEAN BestEffort, NTSTATUS *PResult); PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, PIRP BoundaryIrp, PLARGE_INTEGER Timeout, PIRP CancellableIrp); +ULONG FspIoqPendingIrpCount(FSP_IOQ *Ioq); BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp); PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint); +ULONG FspIoqProcessIrpCount(FSP_IOQ *Ioq); BOOLEAN FspIoqRetryCompleteIrp(FSP_IOQ *Ioq, PIRP Irp, NTSTATUS *PResult); PIRP FspIoqNextCompleteIrp(FSP_IOQ *Ioq, PIRP BoundaryIrp); +ULONG FspIoqRetriedIrpCount(FSP_IOQ *Ioq); /* meta cache */ typedef struct diff --git a/src/sys/ioq.c b/src/sys/ioq.c index c4235a40..48d327bd 100644 --- a/src/sys/ioq.c +++ b/src/sys/ioq.c @@ -270,6 +270,7 @@ static NTSTATUS FspIoqProcessInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertCo FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, ProcessIoCsq); if (Ioq->Stopped) return STATUS_CANCELLED; + Ioq->ProcessIrpCount++; InsertTailList(&Ioq->ProcessIrpList, &Irp->Tail.Overlay.ListEntry); ULONG Index = FspHashMixPointer(Irp) % Ioq->ProcessIrpBucketCount; #if DBG @@ -296,6 +297,7 @@ static VOID FspIoqProcessRemoveIrp(PIO_CSQ IoCsq, PIRP Irp) break; } } + Ioq->ProcessIrpCount--; RemoveEntryList(&Irp->Tail.Overlay.ListEntry); } @@ -360,12 +362,15 @@ static NTSTATUS FspIoqRetriedInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertCo FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, RetriedIoCsq); if (Ioq->Stopped) return STATUS_CANCELLED; + Ioq->RetriedIrpCount++; InsertTailList(&Ioq->RetriedIrpList, &Irp->Tail.Overlay.ListEntry); return STATUS_SUCCESS; } static VOID FspIoqRetriedRemoveIrp(PIO_CSQ IoCsq, PIRP Irp) { + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, RetriedIoCsq); + Ioq->RetriedIrpCount--; RemoveEntryList(&Irp->Tail.Overlay.ListEntry); } @@ -583,6 +588,16 @@ PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, PIRP BoundaryIrp, PLARGE_INTEGER Timeout return PendingIrp; } +ULONG FspIoqPendingIrpCount(FSP_IOQ *Ioq) +{ + ULONG Result; + KIRQL Irql; + KeAcquireSpinLock(&Ioq->SpinLock, &Irql); + Result = Ioq->PendingIrpCount; + KeReleaseSpinLock(&Ioq->SpinLock, Irql); + return Result; +} + BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp) { NTSTATUS Result; @@ -606,6 +621,16 @@ PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint) return FspCsqRemoveNextIrp(&Ioq->ProcessIoCsq, &PeekContext); } +ULONG FspIoqProcessIrpCount(FSP_IOQ *Ioq) +{ + ULONG Result; + KIRQL Irql; + KeAcquireSpinLock(&Ioq->SpinLock, &Irql); + Result = Ioq->ProcessIrpCount; + KeReleaseSpinLock(&Ioq->SpinLock, Irql); + return Result; +} + BOOLEAN FspIoqRetryCompleteIrp(FSP_IOQ *Ioq, PIRP Irp, NTSTATUS *PResult) { NTSTATUS Result; @@ -637,3 +662,13 @@ PIRP FspIoqNextCompleteIrp(FSP_IOQ *Ioq, PIRP BoundaryIrp) PeekContext.ExpirationTime = 0; return FspCsqRemoveNextIrp(&Ioq->RetriedIoCsq, &PeekContext); } + +ULONG FspIoqRetriedIrpCount(FSP_IOQ *Ioq) +{ + ULONG Result; + KIRQL Irql; + KeAcquireSpinLock(&Ioq->SpinLock, &Irql); + Result = Ioq->RetriedIrpCount; + KeReleaseSpinLock(&Ioq->SpinLock, Irql); + return Result; +} diff --git a/src/sys/volume.c b/src/sys/volume.c index 5bcb61eb..aa6dfc35 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -546,6 +546,7 @@ NTSTATUS FspVolumeTransact( FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse; FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest; PIRP ProcessIrp, PendingIrp, RetriedIrp, RepostedIrp; + ULONG LoopCount; LARGE_INTEGER Timeout; PIRP TopLevelIrp = IoGetTopLevelIrp(); @@ -587,7 +588,8 @@ NTSTATUS FspVolumeTransact( } /* process any retried IRP's */ - for (;;) + LoopCount = FspIoqRetriedIrpCount(FsvolDeviceExtension->Ioq); + while (0 < LoopCount--) /* upper bound on loop guarantees forward progress! */ { /* get the next retried IRP, but do not go beyond the first reposted IRP! */ RetriedIrp = FspIoqNextCompleteIrp(FsvolDeviceExtension->Ioq, RepostedIrp); @@ -656,6 +658,7 @@ NTSTATUS FspVolumeTransact( Request = OutputBuffer; BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength; ASSERT(FspFsctlTransactCanProduceRequest(Request, BufferEnd)); + LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq); for (;;) { PendingIrpRequest = FspIrpRequest(PendingIrp); @@ -700,6 +703,9 @@ NTSTATUS FspVolumeTransact( if (!FspFsctlTransactCanProduceRequest(Request, BufferEnd)) break; } + + if (0 >= LoopCount--) /* upper bound on loop guarantees forward progress! */ + break; /* get the next pending IRP, but do not go beyond the first reposted IRP! */ PendingIrp = FspIoqNextPendingIrp(FsvolDeviceExtension->Ioq, RepostedIrp, 0, Irp);