This commit is contained in:
Bill Zissimopoulos 2015-11-23 16:04:08 -08:00
parent 694a39db9a
commit 175ba3205a
4 changed files with 275 additions and 45 deletions

View File

@ -142,6 +142,7 @@
<ClCompile Include="..\..\src\sys\fileinfo.c" /> <ClCompile Include="..\..\src\sys\fileinfo.c" />
<ClCompile Include="..\..\src\sys\flush.c" /> <ClCompile Include="..\..\src\sys\flush.c" />
<ClCompile Include="..\..\src\sys\fsctl.c" /> <ClCompile Include="..\..\src\sys\fsctl.c" />
<ClCompile Include="..\..\src\sys\ioq.c" />
<ClCompile Include="..\..\src\sys\lockctl.c" /> <ClCompile Include="..\..\src\sys\lockctl.c" />
<ClCompile Include="..\..\src\sys\misc.c" /> <ClCompile Include="..\..\src\sys\misc.c" />
<ClCompile Include="..\..\src\sys\read.c" /> <ClCompile Include="..\..\src\sys\read.c" />

View File

@ -74,6 +74,9 @@
<ClCompile Include="..\..\src\sys\misc.c"> <ClCompile Include="..\..\src\sys\misc.c">
<Filter>Source</Filter> <Filter>Source</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\sys\ioq.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h"> <ClInclude Include="..\..\src\sys\driver.h">

View File

@ -113,51 +113,6 @@
#pragma warning(disable:4100) /* unreferenced formal parameter */ #pragma warning(disable:4100) /* unreferenced formal parameter */
#pragma warning(disable:4200) /* zero-sized array in struct/union */ #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 major functions */
DRIVER_DISPATCH FspCleanup; DRIVER_DISPATCH FspCleanup;
DRIVER_DISPATCH FspClose; DRIVER_DISPATCH FspClose;
@ -190,6 +145,68 @@ FAST_IO_RELEASE_FOR_MOD_WRITE FspReleaseForModWrite;
FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush; FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush;
FAST_IO_RELEASE_FOR_CCFLUSH FspReleaseForCcFlush; 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 */ /* misc */
NTSTATUS CreateGuid(GUID *Guid); NTSTATUS CreateGuid(GUID *Guid);
NTSTATUS SecuritySubjectContextAccessCheck( NTSTATUS SecuritySubjectContextAccessCheck(

209
src/sys/ioq.c Normal file
View 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);
}