From 175ba3205ac5e807452e286cbc7e46775bb06a38 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 23 Nov 2015 16:04:08 -0800 Subject: [PATCH] sys: ioq --- build/VStudio/winfsp.vcxproj | 1 + build/VStudio/winfsp.vcxproj.filters | 3 + src/sys/driver.h | 107 ++++++++------ src/sys/ioq.c | 209 +++++++++++++++++++++++++++ 4 files changed, 275 insertions(+), 45 deletions(-) create mode 100644 src/sys/ioq.c diff --git a/build/VStudio/winfsp.vcxproj b/build/VStudio/winfsp.vcxproj index 4a4418c9..f7d94004 100644 --- a/build/VStudio/winfsp.vcxproj +++ b/build/VStudio/winfsp.vcxproj @@ -142,6 +142,7 @@ + diff --git a/build/VStudio/winfsp.vcxproj.filters b/build/VStudio/winfsp.vcxproj.filters index f49c593f..eb72665c 100644 --- a/build/VStudio/winfsp.vcxproj.filters +++ b/build/VStudio/winfsp.vcxproj.filters @@ -74,6 +74,9 @@ Source + + Source + diff --git a/src/sys/driver.h b/src/sys/driver.h index d6027dc5..90a147c6 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -113,51 +113,6 @@ #pragma warning(disable:4100) /* unreferenced formal parameter */ #pragma warning(disable:4200) /* zero-sized array in struct/union */ -/* types */ -enum -{ - FspFsctlDeviceExtensionKind = 'C', /* file system control device (e.g. \Device\WinFsp.Disk) */ - FspFsvrtDeviceExtensionKind = 'V', /* virtual volume device (e.g. \Device\Volume{GUID}) */ - FspFsvolDeviceExtensionKind = 'F', /* file system volume device (unnamed) */ -}; -typedef struct -{ - UINT8 Kind; -} FSP_DEVICE_EXTENSION; -typedef struct -{ - FSP_DEVICE_EXTENSION Base; -} FSP_FSCTL_DEVICE_EXTENSION; -typedef struct -{ - FSP_DEVICE_EXTENSION Base; - UINT8 SecurityDescriptorBuf[]; -} FSP_FSVRT_DEVICE_EXTENSION; -typedef struct -{ - FSP_DEVICE_EXTENSION Base; -} FSP_FSVOL_DEVICE_EXTENSION; -static inline -FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject) -{ - return DeviceObject->DeviceExtension; -} -static inline -FSP_FSCTL_DEVICE_EXTENSION *FspFsctlDeviceExtension(PDEVICE_OBJECT DeviceObject) -{ - return DeviceObject->DeviceExtension; -} -static inline -FSP_FSVRT_DEVICE_EXTENSION *FspFsvrtDeviceExtension(PDEVICE_OBJECT DeviceObject) -{ - return DeviceObject->DeviceExtension; -} -static inline -FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject) -{ - return DeviceObject->DeviceExtension; -} - /* driver major functions */ DRIVER_DISPATCH FspCleanup; DRIVER_DISPATCH FspClose; @@ -190,6 +145,68 @@ FAST_IO_RELEASE_FOR_MOD_WRITE FspReleaseForModWrite; FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush; FAST_IO_RELEASE_FOR_CCFLUSH FspReleaseForCcFlush; +/* I/O queue */ +typedef struct +{ + KSPIN_LOCK SpinLock; + int Enabled; + LIST_ENTRY PendingIrpList, ProcessIrpList; + IO_CSQ PendingIoCsq, ProcessIoCsq; +} FSP_IOQ; +VOID FspIoqInitialize(FSP_IOQ *Ioq); +VOID FspIoqEnable(FSP_IOQ *Ioq, int Delta); +BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp); +PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq); +BOOLEAN FspIoqProcessIrp(FSP_IOQ *Ioq, PIRP Irp); +PIRP FspIoqRemoveProcessIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint); +VOID FspIoqCancelAll(FSP_IOQ *Ioq); + +/* device extensions */ +enum +{ + FspFsctlDeviceExtensionKind = 'C', /* file system control device (e.g. \Device\WinFsp.Disk) */ + FspFsvrtDeviceExtensionKind = 'V', /* virtual volume device (e.g. \Device\Volume{GUID}) */ + FspFsvolDeviceExtensionKind = 'F', /* file system volume device (unnamed) */ +}; +typedef struct +{ + UINT8 Kind; +} FSP_DEVICE_EXTENSION; +typedef struct +{ + FSP_DEVICE_EXTENSION Base; +} FSP_FSCTL_DEVICE_EXTENSION; +typedef struct +{ + FSP_DEVICE_EXTENSION Base; + FSP_IOQ Ioq; + UINT8 SecurityDescriptorBuf[]; +} FSP_FSVRT_DEVICE_EXTENSION; +typedef struct +{ + FSP_DEVICE_EXTENSION Base; +} FSP_FSVOL_DEVICE_EXTENSION; +static inline +FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject) +{ + return DeviceObject->DeviceExtension; +} +static inline +FSP_FSCTL_DEVICE_EXTENSION *FspFsctlDeviceExtension(PDEVICE_OBJECT DeviceObject) +{ + return DeviceObject->DeviceExtension; +} +static inline +FSP_FSVRT_DEVICE_EXTENSION *FspFsvrtDeviceExtension(PDEVICE_OBJECT DeviceObject) +{ + return DeviceObject->DeviceExtension; +} +static inline +FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject) +{ + return DeviceObject->DeviceExtension; +} + /* misc */ NTSTATUS CreateGuid(GUID *Guid); NTSTATUS SecuritySubjectContextAccessCheck( diff --git a/src/sys/ioq.c b/src/sys/ioq.c new file mode 100644 index 00000000..7371a2a2 --- /dev/null +++ b/src/sys/ioq.c @@ -0,0 +1,209 @@ +/** + * @file sys/ioq.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +/* + * An FSP_IOQ encapsulates the main FSP mechanism for handling IRP's. + * It has two queues: a "pending" queue for managing newly arrived IRP's + * and a "processing" queue for managing IRP's currently being processed + * (i.e. sent to the user-mode file system for further processing). + * + * IRP's arrive at a MajorFunction (MJ) and are then posted to the device's + * FSP_IOQ and marked pending. When the user-mode file system performs + * FSP_FSCTL_TRANSACT, the IRP's are removed from the pending queue and + * are then marshalled to the user process; prior to that they are added + * to the processing queue. At a later time the user-mode will perform + * another FSP_FSCTL_TRANSACT at which time any processed IRP's will be + * marshalled back to us and will be then removed from the processing queue + * and completed. + * + * State diagram: + * +--------------------+ + * | | | ProcessIrp + * v | v + * +------------+ | +------------+ + * | MJ | | | Processing | + * +------------+ | +------------+ + * | | | + * | PostIrp | | RemoveProcessIrp + * v | v + * +------------+ | +------------+ + * | Pending | | | TRANSACT | + * +------------+ | | IN | + * | | +------------+ + * | NextPendingIrp | | + * v | | CompleteIrp + * +------------+ | v + * | TRANSACT | | +------------+ + * | OUT | | | Completed | + * +------------+ | +------------+ + * | | + * +---------------------+ + */ + +static NTSTATUS FspIoqPendingInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertContext) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, PendingIoCsq); + + if (0 > Ioq->Enabled) + return STATUS_ACCESS_DENIED; + + InsertTailList(&Ioq->PendingIrpList, &Irp->Tail.Overlay.ListEntry); + return STATUS_SUCCESS; +} + +static VOID FspIoqPendingRemoveIrp(PIO_CSQ IoCsq, PIRP Irp) +{ + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + +static PIRP FspIoqPendingPeekNextIrp(PIO_CSQ IoCsq, PIRP Irp, PVOID PeekContext) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, PendingIoCsq); + PLIST_ENTRY Head, Entry; + + if (!PeekContext && 0 > Ioq->Enabled) + return 0; + + Head = &Ioq->PendingIrpList; + if (0 == Irp) + Entry = Head->Flink; + else + Entry = Irp->Tail.Overlay.ListEntry.Flink; + + return Head != Entry ? CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0; +} + +static VOID FspIoqPendingAcquireLock(PIO_CSQ IoCsq, PKIRQL Irql) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, PendingIoCsq); + KeAcquireSpinLock(&Ioq->SpinLock, Irql); +} + +static VOID FspIoqPendingReleaseLock(PIO_CSQ IoCsq, KIRQL Irql) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, PendingIoCsq); + KeReleaseSpinLock(&Ioq->SpinLock, Irql); +} + +static NTSTATUS FspIoqProcessInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertContext) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, ProcessIoCsq); + + if (0 > Ioq->Enabled) + return STATUS_ACCESS_DENIED; + + InsertTailList(&Ioq->ProcessIrpList, &Irp->Tail.Overlay.ListEntry); + return STATUS_SUCCESS; +} + +static VOID FspIoqProcessRemoveIrp(PIO_CSQ IoCsq, PIRP Irp) +{ + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + +static PIRP FspIoqProcessPeekNextIrp(PIO_CSQ IoCsq, PIRP Irp, PVOID PeekContext) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, ProcessIoCsq); + PLIST_ENTRY Head, Entry; + + if (!PeekContext && 0 > Ioq->Enabled) + return 0; + + Head = &Ioq->ProcessIrpList; + if (0 == Irp) + Entry = Head->Flink; + else + Entry = Irp->Tail.Overlay.ListEntry.Flink; + + for (; Head != Entry; Entry = Entry->Flink) + { + Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); + if (Irp == PeekContext) + return Irp; + } + + return 0; +} + +static VOID FspIoqProcessAcquireLock(PIO_CSQ IoCsq, PKIRQL Irql) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, ProcessIoCsq); + KeAcquireSpinLock(&Ioq->SpinLock, Irql); +} + +static VOID FspIoqProcessReleaseLock(PIO_CSQ IoCsq, KIRQL Irql) +{ + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, ProcessIoCsq); + KeReleaseSpinLock(&Ioq->SpinLock, Irql); +} + +static VOID FspIoqCompleteCanceledIrp(PIO_CSQ IoCsq, PIRP Irp) +{ + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, FSP_IO_INCREMENT); +} + +VOID FspIoqInitialize(FSP_IOQ *Ioq) +{ + RtlZeroMemory(Ioq, sizeof *Ioq); + KeInitializeSpinLock(&Ioq->SpinLock); + InitializeListHead(&Ioq->PendingIrpList); + InitializeListHead(&Ioq->ProcessIrpList); + IoCsqInitializeEx(&Ioq->PendingIoCsq, + FspIoqPendingInsertIrpEx, + FspIoqPendingRemoveIrp, + FspIoqPendingPeekNextIrp, + FspIoqPendingAcquireLock, + FspIoqPendingReleaseLock, + FspIoqCompleteCanceledIrp); + IoCsqInitializeEx(&Ioq->ProcessIoCsq, + FspIoqProcessInsertIrpEx, + FspIoqProcessRemoveIrp, + FspIoqProcessPeekNextIrp, + FspIoqProcessAcquireLock, + FspIoqProcessReleaseLock, + FspIoqCompleteCanceledIrp); +} + +VOID FspIoqEnable(FSP_IOQ *Ioq, int Delta) +{ + KIRQL Irql; + KeAcquireSpinLock(&Ioq->SpinLock, &Irql); + Ioq->Enabled += Delta; + KeReleaseSpinLock(&Ioq->SpinLock, Irql); +} + +BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp) +{ + return STATUS_SUCCESS == IoCsqInsertIrpEx(&Ioq->PendingIoCsq, Irp, 0, 0); +} + +PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq) +{ + return IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, (PVOID)1); +} + +BOOLEAN FspIoqProcessIrp(FSP_IOQ *Ioq, PIRP Irp) +{ + return STATUS_SUCCESS == IoCsqInsertIrpEx(&Ioq->ProcessIoCsq, Irp, 0, 0); +} + +PIRP FspIoqRemoveProcessIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint) +{ + return IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, (PVOID)IrpHint); +} + +VOID FspIoqCancelAll(FSP_IOQ *Ioq) +{ + PIRP Irp; + while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, 0))) + FspIoqCompleteCanceledIrp(&Ioq->PendingIoCsq, Irp); + while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->ProcessIoCsq, 0))) + FspIoqCompleteCanceledIrp(&Ioq->ProcessIoCsq, Irp); +}