mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48:38 -05:00 
			
		
		
		
	sys: ioq
This commit is contained in:
		
							
								
								
									
										107
									
								
								src/sys/driver.h
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								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( | ||||
|   | ||||
							
								
								
									
										209
									
								
								src/sys/ioq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								src/sys/ioq.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,209 @@ | ||||
| /** | ||||
|  * @file sys/ioq.c | ||||
|  * | ||||
|  * @copyright 2015 Bill Zissimopoulos | ||||
|  */ | ||||
|  | ||||
| #include <sys/driver.h> | ||||
|  | ||||
| /* | ||||
|  * 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); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user