From 9e82247366119d84802ea00702444e819951562d Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 16 Dec 2015 10:43:33 -0800 Subject: [PATCH] sys: ioq: now supports IRP expiration --- src/sys/create.c | 4 ++-- src/sys/driver.h | 10 ++++++-- src/sys/fsctl.c | 2 +- src/sys/idevctl.c | 4 ++-- src/sys/iop.c | 8 +++---- src/sys/ioq.c | 58 ++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/sys/create.c b/src/sys/create.c index f738cece..052558fe 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -392,7 +392,7 @@ VOID FspFsvolCreateComplete( FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); - FSP_FSCTL_TRANSACT_REQ *Request = FspIopRequest(Irp); + FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); PFILE_OBJECT FileObject = IrpSp->FileObject; PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; ULONG CreateOptions = IrpSp->Parameters.Create.Options; @@ -672,7 +672,7 @@ static VOID FspFsvolCreateCleanupClose( FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject); - FSP_FSCTL_TRANSACT_REQ *OriginalRequest = FspIopRequest(Irp); + FSP_FSCTL_TRANSACT_REQ *OriginalRequest = FspIrpRequest(Irp); FSP_FILE_CONTEXT *FsContext = FspIopRequestContext(OriginalRequest, RequestFsContext); UINT64 UserContext = Response->Rsp.Create.Opened.UserContext; UINT64 UserContext2 = Response->Rsp.Create.Opened.UserContext2; diff --git a/src/sys/driver.h b/src/sys/driver.h index bf3cfd2b..a7a193a3 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -245,6 +245,13 @@ FAST_IO_RELEASE_FOR_MOD_WRITE FspReleaseForModWrite; FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush; FAST_IO_RELEASE_FOR_CCFLUSH FspReleaseForCcFlush; +/* IRP context */ +#define FspIrpTimestamp(Irp) \ + (*(ULONGLONG *)&(Irp)->Tail.Overlay.DriverContext[0]) + /* FspIrpTimestamp() uses up DriverContext[0] and [1] in 32-bit builds */ +#define FspIrpRequest(Irp) \ + (*(FSP_FSCTL_TRANSACT_REQ **)&(Irp)->Tail.Overlay.DriverContext[2]) + /* I/O queue */ #define FspIoqTimeout ((PIRP)1) typedef struct @@ -258,6 +265,7 @@ typedef struct VOID FspIoqInitialize(FSP_IOQ *Ioq); VOID FspIoqStop(FSP_IOQ *Ioq); BOOLEAN FspIoqStopped(FSP_IOQ *Ioq); +VOID FspIoqRemoveExpired(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout); BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp); PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout); BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp); @@ -266,8 +274,6 @@ PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint); /* I/O processing */ #define FSP_FSCTL_WORK \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'W', METHOD_NEITHER, FILE_ANY_ACCESS) -#define FspIopRequest(Irp) \ - (*(FSP_FSCTL_TRANSACT_REQ **)&(Irp)->Tail.Overlay.DriverContext[0]) #define FspIopRequestContext(Request, I)\ (*FspIopRequestContextAddress(Request, I)) #define FspIopCreateRequest(I, F, E, P) FspIopCreateRequestEx(I, F, E, 0, P) diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index c289d9f1..d7c3d684 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -473,7 +473,7 @@ static NTSTATUS FspFsvrtTransact( ASSERT(FspFsctlTransactCanProduceRequest(Request, SystemBufferEnd)); for (;;) { - PendingIrpRequest = FspIopRequest(PendingIrp); + PendingIrpRequest = FspIrpRequest(PendingIrp); Result = FspIopDispatchPrepare(PendingIrp, PendingIrpRequest); if (!NT_SUCCESS(Result)) diff --git a/src/sys/idevctl.c b/src/sys/idevctl.c index 9d94741c..71c3fc1e 100644 --- a/src/sys/idevctl.c +++ b/src/sys/idevctl.c @@ -42,7 +42,7 @@ static NTSTATUS FspFsvolInternalDeviceControl( /* associate the passed Request with our Irp; acquire ownership of the Request */ Request->Hint = (UINT_PTR)Irp; - FspIopRequest(Irp) = Request; + FspIrpRequest(Irp) = Request; /* * Post the IRP to our Ioq; we do this here instead of at IRP_LEAVE_MJ time, @@ -55,7 +55,7 @@ static NTSTATUS FspFsvolInternalDeviceControl( ASSERT(FspIoqStopped(&FsvrtDeviceExtension->Ioq)); Request->Hint = 0; - FspIopRequest(Irp) = 0; + FspIrpRequest(Irp) = 0; Result = STATUS_CANCELLED; goto exit; diff --git a/src/sys/iop.c b/src/sys/iop.c index e6236046..bd9f691c 100644 --- a/src/sys/iop.c +++ b/src/sys/iop.c @@ -71,7 +71,7 @@ NTSTATUS FspIopCreateRequestEx( } if (0 != Irp) - FspIopRequest(Irp) = Request; + FspIrpRequest(Irp) = Request; *PRequest = Request; return STATUS_SUCCESS; @@ -152,10 +152,10 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceRelease) ASSERT(STATUS_PENDING != Result); - if (0 != FspIopRequest(Irp)) + if (0 != FspIrpRequest(Irp)) { - FspIopDeleteRequest(FspIopRequest(Irp)); - FspIopRequest(Irp) = 0; + FspIopDeleteRequest(FspIrpRequest(Irp)); + FspIrpRequest(Irp) = 0; } /* get the device object out of the IRP before completion */ diff --git a/src/sys/ioq.c b/src/sys/ioq.c index 877136a9..ee7f12ec 100644 --- a/src/sys/ioq.c +++ b/src/sys/ioq.c @@ -55,6 +55,12 @@ * queue is not empty. */ +typedef struct +{ + PVOID IrpHint; + ULONGLONG ExpirationTime; +} FSP_IOQ_PEEK_CONTEXT; + static NTSTATUS FspIoqPendingInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertContext) { FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, PendingIoCsq); @@ -81,6 +87,20 @@ static PIRP FspIoqPendingPeekNextIrp(PIO_CSQ IoCsq, PIRP Irp, PVOID PeekContext) return 0; PLIST_ENTRY Head = &Ioq->PendingIrpList; PLIST_ENTRY Entry = 0 == Irp ? Head->Flink : Irp->Tail.Overlay.ListEntry.Flink; + if (!PeekContext) + return Head != Entry ? CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0; + PVOID IrpHint = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->IrpHint; + if (0 == IrpHint) + { + if (Head != Entry) + { + Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); + if (FspIrpTimestamp(Irp) <= ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->ExpirationTime) + /* IRP has expired; return it */ + return Irp; + } + return 0; + } return Head != Entry ? CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0; } @@ -126,10 +146,22 @@ static PIRP FspIoqProcessPeekNextIrp(PIO_CSQ IoCsq, PIRP Irp, PVOID PeekContext) PLIST_ENTRY Entry = 0 == Irp ? Head->Flink : Irp->Tail.Overlay.ListEntry.Flink; if (!PeekContext) return Head != Entry ? CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0; + PVOID IrpHint = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->IrpHint; + if (0 == IrpHint) + { + if (Head != Entry) + { + Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); + if (FspIrpTimestamp(Irp) <= ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->ExpirationTime) + /* IRP has expired; return it */ + return Irp; + } + return 0; + } for (; Head != Entry; Entry = Entry->Flink) { Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); - if (Irp == PeekContext) + if (Irp == IrpHint) return Irp; } return 0; @@ -202,9 +234,22 @@ BOOLEAN FspIoqStopped(FSP_IOQ *Ioq) return Result; } +VOID FspIoqRemoveExpired(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout) +{ + FSP_IOQ_PEEK_CONTEXT PeekContext; + PeekContext.IrpHint = 0; + PeekContext.ExpirationTime = KeQueryInterruptTime() - Timeout->QuadPart; + PIRP Irp; + while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, &PeekContext))) + FspIoqPendingCompleteCanceledIrp(&Ioq->PendingIoCsq, Irp); + while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->ProcessIoCsq, &PeekContext))) + FspIoqProcessCompleteCanceledIrp(&Ioq->ProcessIoCsq, Irp); +} + BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp) { NTSTATUS Result; + FspIrpTimestamp(Irp) = KeQueryInterruptTime(); Result = IoCsqInsertIrpEx(&Ioq->PendingIoCsq, Irp, 0, 0); return NT_SUCCESS(Result); } @@ -221,12 +266,16 @@ PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout) if (STATUS_TIMEOUT == Result) return FspIoqTimeout; } - return IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, (PVOID)1); + FSP_IOQ_PEEK_CONTEXT PeekContext; + PeekContext.IrpHint = (PVOID)1; + PeekContext.ExpirationTime = 0; + return IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, &PeekContext); } BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp) { NTSTATUS Result; + FspIrpTimestamp(Irp) = KeQueryInterruptTime(); Result = IoCsqInsertIrpEx(&Ioq->ProcessIoCsq, Irp, 0, 0); return NT_SUCCESS(Result); } @@ -235,5 +284,8 @@ PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint) { if (0 == IrpHint) return 0; - return IoCsqRemoveNextIrp(&Ioq->ProcessIoCsq, (PVOID)IrpHint); + FSP_IOQ_PEEK_CONTEXT PeekContext; + PeekContext.IrpHint = (PVOID)IrpHint; + PeekContext.ExpirationTime = 0; + return IoCsqRemoveNextIrp(&Ioq->ProcessIoCsq, &PeekContext); }