sys: ioq: now includes a dictionary for fast translation of IrpHint to Irp

This commit is contained in:
Bill Zissimopoulos 2015-12-27 17:49:17 -08:00
parent e3c04e15ba
commit 5fb9953a3a
9 changed files with 243 additions and 120 deletions

View File

@ -152,6 +152,7 @@
<ClCompile Include="..\..\src\sys\debug.c" /> <ClCompile Include="..\..\src\sys\debug.c" />
<ClCompile Include="..\..\src\sys\devctl.c" /> <ClCompile Include="..\..\src\sys\devctl.c" />
<ClCompile Include="..\..\src\sys\device.c" /> <ClCompile Include="..\..\src\sys\device.c" />
<ClCompile Include="..\..\src\sys\dict.c" />
<ClCompile Include="..\..\src\sys\dirctl.c" /> <ClCompile Include="..\..\src\sys\dirctl.c" />
<ClCompile Include="..\..\src\sys\driver.c" /> <ClCompile Include="..\..\src\sys\driver.c" />
<ClCompile Include="..\..\src\sys\ea.c" /> <ClCompile Include="..\..\src\sys\ea.c" />

View File

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

View File

@ -13,7 +13,7 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize, NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
DEVICE_TYPE DeviceType, DEVICE_TYPE DeviceType,
PDEVICE_OBJECT *PDeviceObject); PDEVICE_OBJECT *PDeviceObject);
VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject); NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject); VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject); BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject); VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject);
@ -22,7 +22,6 @@ static BOOLEAN FspDeviceRetainAtDpcLevel(PDEVICE_OBJECT DeviceObject);
_IRQL_requires_(DISPATCH_LEVEL) _IRQL_requires_(DISPATCH_LEVEL)
static VOID FspDeviceReleaseFromDpcLevel(PDEVICE_OBJECT DeviceObject); static VOID FspDeviceReleaseFromDpcLevel(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject); static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject); static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject);
static IO_TIMER_ROUTINE FspFsvolDeviceTimerRoutine; static IO_TIMER_ROUTINE FspFsvolDeviceTimerRoutine;
static WORKER_THREAD_ROUTINE FspFsvolDeviceExpirationRoutine; static WORKER_THREAD_ROUTINE FspFsvolDeviceExpirationRoutine;
@ -49,10 +48,9 @@ VOID FspDeviceDeleteAll(VOID);
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspDeviceCreateSecure) #pragma alloc_text(PAGE, FspDeviceCreateSecure)
#pragma alloc_text(PAGE, FspDeviceCreate) #pragma alloc_text(PAGE, FspDeviceCreate)
#pragma alloc_text(PAGE, FspDeviceInitComplete) #pragma alloc_text(PAGE, FspDeviceInitialize)
#pragma alloc_text(PAGE, FspDeviceDelete) #pragma alloc_text(PAGE, FspDeviceDelete)
#pragma alloc_text(PAGE, FspFsvolDeviceInit) #pragma alloc_text(PAGE, FspFsvolDeviceInit)
#pragma alloc_text(PAGE, FspFsvolDeviceInitComplete)
#pragma alloc_text(PAGE, FspFsvolDeviceFini) #pragma alloc_text(PAGE, FspFsvolDeviceFini)
#pragma alloc_text(PAGE, FspFsvolDeviceLockContext) #pragma alloc_text(PAGE, FspFsvolDeviceLockContext)
#pragma alloc_text(PAGE, FspFsvolDeviceUnlockContext) #pragma alloc_text(PAGE, FspFsvolDeviceUnlockContext)
@ -79,6 +77,8 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
PDEVICE_OBJECT DeviceObject; PDEVICE_OBJECT DeviceObject;
FSP_DEVICE_EXTENSION *DeviceExtension; FSP_DEVICE_EXTENSION *DeviceExtension;
*PDeviceObject = 0;
switch (Kind) switch (Kind)
{ {
case FspFsvolDeviceExtensionKind: case FspFsvolDeviceExtensionKind:
@ -112,20 +112,7 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
DeviceExtension->RefCount = 1; DeviceExtension->RefCount = 1;
DeviceExtension->Kind = Kind; DeviceExtension->Kind = Kind;
switch (Kind) *PDeviceObject = DeviceObject;
{
case FspFsvolDeviceExtensionKind:
Result = FspFsvolDeviceInit(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind:
break;
}
if (!NT_SUCCESS(Result))
IoDeleteDevice(DeviceObject);
else
*PDeviceObject = DeviceObject;
return Result; return Result;
} }
@ -139,26 +126,31 @@ NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
return FspDeviceCreateSecure(Kind, ExtraSize, 0, DeviceType, 0, 0, PDeviceObject); return FspDeviceCreateSecure(Kind, ExtraSize, 0, DeviceType, 0, 0, PDeviceObject);
} }
VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject) NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject)
{ {
PAGED_CODE(); PAGED_CODE();
NTSTATUS Result;
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject);
switch (DeviceExtension->Kind) switch (DeviceExtension->Kind)
{ {
case FspFsvolDeviceExtensionKind: case FspFsvolDeviceExtensionKind:
FspFsvolDeviceInitComplete(DeviceObject); Result = FspFsvolDeviceInit(DeviceObject);
break; break;
case FspFsvrtDeviceExtensionKind: case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind: case FspFsctlDeviceExtensionKind:
Result = STATUS_SUCCESS;
break; break;
default: default:
ASSERT(0); ASSERT(0);
return; return STATUS_INVALID_PARAMETER;
} }
ClearFlag(DeviceObject->Flags, DO_DEVICE_INITIALIZING); if (NT_SUCCESS(Result))
ClearFlag(DeviceObject->Flags, DO_DEVICE_INITIALIZING);
return Result;
} }
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject) VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject)
@ -266,64 +258,64 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
NTSTATUS Result; NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
LARGE_INTEGER IrpTimeout;
/* initialize our timer routine */ /*
#pragma prefast(suppress:28133, "We are a filesystem: we do not have AddDevice") * Volume device initialization is a mess, because of the different ways of
Result = IoInitializeTimer(DeviceObject, FspFsvolDeviceTimerRoutine, 0); * creating/initializing different resources. So we will use some bits just
if (!NT_SUCCESS(Result)) * to track what has been initialized!
return Result; */
/* allocate a spare VPB in case we are mounted on a virtual disk */ /* is there a virtual disk? */
if (FILE_DEVICE_DISK_FILE_SYSTEM == DeviceObject->DeviceType) if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
{ {
/* allocate a spare VPB so that we can be mounted on the virtual disk */
FsvolDeviceExtension->SwapVpb = FspAllocNonPagedExternal(sizeof *FsvolDeviceExtension->SwapVpb); FsvolDeviceExtension->SwapVpb = FspAllocNonPagedExternal(sizeof *FsvolDeviceExtension->SwapVpb);
if (0 == FsvolDeviceExtension->SwapVpb) if (0 == FsvolDeviceExtension->SwapVpb)
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(FsvolDeviceExtension->SwapVpb, sizeof *FsvolDeviceExtension->SwapVpb); RtlZeroMemory(FsvolDeviceExtension->SwapVpb, sizeof *FsvolDeviceExtension->SwapVpb);
/* reference the virtual disk device so that it will not go away while we are using it */
ObReferenceObject(FsvolDeviceExtension->FsvrtDeviceObject);
FsvolDeviceExtension->InitDoneFsvrt = 1;
} }
/* initialize our delete lock */ /* initialize our delete lock */
ExInitializeResourceLite(&FsvolDeviceExtension->DeleteResource); ExInitializeResourceLite(&FsvolDeviceExtension->DeleteResource);
FsvolDeviceExtension->InitDoneDelRsc = 1;
/* setup our Ioq */
IrpTimeout.QuadPart = FsvolDeviceExtension->VolumeParams.IrpTimeout * 10000;
/* convert millis to nanos */
Result = FspIoqCreate(
FsvolDeviceExtension->VolumeParams.IrpCapacity, &IrpTimeout, FspIopCompleteCanceledIrp,
&FsvolDeviceExtension->Ioq);
if (!NT_SUCCESS(Result))
return Result;
FsvolDeviceExtension->InitDoneIoq = 1;
/* initialize our generic table */ /* initialize our generic table */
ExInitializeFastMutex(&FsvolDeviceExtension->GenericTableFastMutex); ExInitializeFastMutex(&FsvolDeviceExtension->GenericTableFastMutex);
RtlInitializeGenericTableAvl(&FsvolDeviceExtension->GenericTable, RtlInitializeGenericTableAvl(&FsvolDeviceExtension->GenericTable,
FspFsvolDeviceCompareElement, FspFsvolDeviceAllocateElement, FspFsvolDeviceFreeElement, 0); FspFsvolDeviceCompareElement, FspFsvolDeviceAllocateElement, FspFsvolDeviceFreeElement, 0);
FsvolDeviceExtension->InitDoneGenTab = 1;
/* initialize the volume name buffer */ /* initialize the volume name buffer */
RtlInitEmptyUnicodeString(&FsvolDeviceExtension->VolumeName, RtlInitEmptyUnicodeString(&FsvolDeviceExtension->VolumeName,
FsvolDeviceExtension->VolumeNameBuf, sizeof FsvolDeviceExtension->VolumeNameBuf); FsvolDeviceExtension->VolumeNameBuf, sizeof FsvolDeviceExtension->VolumeNameBuf);
return STATUS_SUCCESS; /* initialize our timer routine and start our expiration timer */
} #pragma prefast(suppress:28133, "We are a filesystem: we do not have AddDevice")
Result = IoInitializeTimer(DeviceObject, FspFsvolDeviceTimerRoutine, 0);
static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject) if (!NT_SUCCESS(Result))
{ return Result;
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
LARGE_INTEGER IrpTimeout;
/*
* Setup our Ioq and expiration fields.
* We must do this in InitComplete because Ioq initialization depends on VolumeParams.
*/
IrpTimeout.QuadPart = FsvolDeviceExtension->VolumeParams.IrpTimeout * 10000;
/* convert millis to nanos */
FspIoqInitialize(&FsvolDeviceExtension->Ioq,
&IrpTimeout, FsvolDeviceExtension->VolumeParams.IrpCapacity, FspIopCompleteCanceledIrp);
KeInitializeSpinLock(&FsvolDeviceExtension->ExpirationLock); KeInitializeSpinLock(&FsvolDeviceExtension->ExpirationLock);
ExInitializeWorkItem(&FsvolDeviceExtension->ExpirationWorkItem, ExInitializeWorkItem(&FsvolDeviceExtension->ExpirationWorkItem,
FspFsvolDeviceExpirationRoutine, DeviceObject); FspFsvolDeviceExpirationRoutine, DeviceObject);
/*
* Reference the virtual volume device so that it will not go away while we are using it.
*/
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
ObReferenceObject(FsvolDeviceExtension->FsvrtDeviceObject);
/* start our expiration timer */
IoStartTimer(DeviceObject); IoStartTimer(DeviceObject);
FsvolDeviceExtension->InitDoneTimer = 1;
return STATUS_SUCCESS;
} }
static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject) static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
@ -339,7 +331,8 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
* However a work item may be in flight. For this reason our IoTimer routine * However a work item may be in flight. For this reason our IoTimer routine
* retains our DeviceObject before queueing work items. * retains our DeviceObject before queueing work items.
*/ */
IoStopTimer(DeviceObject); if (FsvolDeviceExtension->InitDoneTimer)
IoStopTimer(DeviceObject);
#if 0 #if 0
/* FspDeviceFreeElement is now a no-op, so this is no longer necessary */ /* FspDeviceFreeElement is now a no-op, so this is no longer necessary */
@ -347,23 +340,31 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
* Enumerate and delete all entries in the GenericTable. * Enumerate and delete all entries in the GenericTable.
* There is no need to protect accesses to the table as we are in the device destructor. * There is no need to protect accesses to the table as we are in the device destructor.
*/ */
FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Element; if (FsvolDeviceExtension->InitDoneGenTab)
while (0 != (Element = RtlGetElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, 0))) {
RtlDeleteElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, &Element->Identifier); FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Element;
while (0 != (Element = RtlGetElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, 0)))
RtlDeleteElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, &Element->Identifier);
}
#endif #endif
/* if (FsvolDeviceExtension->InitDoneIoq)
* Dereference the virtual volume device so that it can now go away. FspIoqDelete(FsvolDeviceExtension->Ioq);
*/
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
ObDereferenceObject(FsvolDeviceExtension->FsvrtDeviceObject);
/* finalize our delete lock */ /* finalize our delete lock */
ExDeleteResourceLite(&FsvolDeviceExtension->DeleteResource); if (FsvolDeviceExtension->InitDoneDelRsc)
ExDeleteResourceLite(&FsvolDeviceExtension->DeleteResource);
/* free the spare VPB if we still have it */ /* is there a virtual disk? */
if (0 != FsvolDeviceExtension->SwapVpb) if (FsvolDeviceExtension->InitDoneFsvrt)
FspFreeExternal(FsvolDeviceExtension->SwapVpb); {
/* dereference the virtual volume device so that it can now go away */
ObDereferenceObject(FsvolDeviceExtension->FsvrtDeviceObject);
/* free the spare VPB if we still have it */
if (0 != FsvolDeviceExtension->SwapVpb)
FspFreeExternal(FsvolDeviceExtension->SwapVpb);
}
} }
static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context) static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context)
@ -405,7 +406,7 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
KIRQL Irql; KIRQL Irql;
FspIoqRemoveExpired(&FsvolDeviceExtension->Ioq); FspIoqRemoveExpired(FsvolDeviceExtension->Ioq);
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql); KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);
FsvolDeviceExtension->ExpirationInProgress = FALSE; FsvolDeviceExtension->ExpirationInProgress = FALSE;

47
src/sys/dict.c Normal file
View File

@ -0,0 +1,47 @@
/**
* @file sys/dict.c
*
* @copyright 2015 Bill Zissimopoulos
*/
#include <sys/driver.h>
VOID FspDictInitialize(FSP_DICT *Dict,
FSP_DICT_EQUAL_FUNCTION *EqualFunction, FSP_DICT_HASH_FUNCTION *HashFunction,
FSP_DICT_ENTRY **Buckets, ULONG BucketCount)
{
RtlZeroMemory(Buckets, BucketCount * sizeof Buckets[0]);
Dict->EqualFunction = EqualFunction;
Dict->HashFunction = HashFunction;
Dict->Buckets = Buckets;
Dict->BucketCount = BucketCount;
}
FSP_DICT_ENTRY *FspDictGetEntry(FSP_DICT *Dict, PVOID Key)
{
ULONG Index = Dict->HashFunction(Key) % Dict->BucketCount;
for (FSP_DICT_ENTRY *Entry = Dict->Buckets[Index]; Entry; Entry = Entry->Next)
if (Dict->EqualFunction(Key, Entry->Key))
return Entry;
return 0;
}
VOID FspDictSetEntry(FSP_DICT *Dict, FSP_DICT_ENTRY *Entry)
{
ULONG Index = Dict->HashFunction(Entry->Key) % Dict->BucketCount;
Entry->Next = Dict->Buckets[Index];
Dict->Buckets[Index] = Entry;
}
FSP_DICT_ENTRY *FspDictRemoveEntry(FSP_DICT *Dict, PVOID Key)
{
ULONG Index = Dict->HashFunction(Key) % Dict->BucketCount;
for (FSP_DICT_ENTRY **PEntry = &Dict->Buckets[Index]; *PEntry; PEntry = &(*PEntry)->Next)
if (Dict->EqualFunction(Key, (*PEntry)->Key))
{
FSP_DICT_ENTRY *Entry = *PEntry;
*PEntry = Entry->Next;
return Entry;
}
return 0;
}

View File

@ -39,8 +39,10 @@ NTSTATUS DriverEntry(
&FspFsctlNetDeviceObject); &FspFsctlNetDeviceObject);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject)); FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
FspDeviceInitComplete(FspFsctlDiskDeviceObject); Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
FspDeviceInitComplete(FspFsctlNetDeviceObject); ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
/* setup the driver object */ /* setup the driver object */
DriverObject->DriverUnload = FspUnload; DriverObject->DriverUnload = FspUnload;

View File

@ -127,7 +127,7 @@ extern __declspec(selectany) int bpglobal = 1;
/* if the IRP has not been marked pending already */\ /* if the IRP has not been marked pending already */\
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =\ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =\
FspFsvolDeviceExtension(DeviceObject);\ FspFsvolDeviceExtension(DeviceObject);\
if (!FspIoqPostIrp(&FsvolDeviceExtension->Ioq, Irp, &Result))\ if (!FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result))\
FspIopCompleteIrp(Irp, Result);\ FspIopCompleteIrp(Irp, Result);\
} \ } \
} \ } \
@ -291,12 +291,38 @@ VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
PWORKER_THREAD_ROUTINE Routine, PVOID Context); PWORKER_THREAD_ROUTINE Routine, PVOID Context);
VOID FspQueueDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, LARGE_INTEGER Delay); VOID FspQueueDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, LARGE_INTEGER Delay);
/* dictionary */
typedef BOOLEAN FSP_DICT_EQUAL_FUNCTION(PVOID Key1, PVOID Key2);
typedef ULONG FSP_DICT_HASH_FUNCTION(PVOID Key);
typedef struct _FSP_DICT_ENTRY
{
PVOID Key, Value;
struct _FSP_DICT_ENTRY *Next;
} FSP_DICT_ENTRY;
typedef struct _FSP_DICT
{
FSP_DICT_EQUAL_FUNCTION *EqualFunction;
FSP_DICT_HASH_FUNCTION *HashFunction;
FSP_DICT_ENTRY **Buckets;
ULONG BucketCount;
} FSP_DICT;
VOID FspDictInitialize(FSP_DICT *Dict,
FSP_DICT_EQUAL_FUNCTION *EqualFunction, FSP_DICT_HASH_FUNCTION *HashFunction,
FSP_DICT_ENTRY **Buckets, ULONG BucketCount);
FSP_DICT_ENTRY *FspDictGetEntry(FSP_DICT *Dict, PVOID Key);
VOID FspDictSetEntry(FSP_DICT *Dict, FSP_DICT_ENTRY *Entry);
FSP_DICT_ENTRY *FspDictRemoveEntry(FSP_DICT *Dict, PVOID Key);
/* IRP context */ /* IRP context */
#define FspIrpTimestamp(Irp) \ typedef struct
(*(ULONGLONG *)&(Irp)->Tail.Overlay.DriverContext[0]) {
/* FspIrpTimestamp() uses up DriverContext[0] and [1] in 32-bit builds */ IO_CSQ_IRP_CONTEXT IoCsqIrpContext;
ULONGLONG ExpirationTime;
} FSP_IRP_CONTEXT;
#define FspIrpContext(Irp) \
(*(FSP_IRP_CONTEXT **)&(Irp)->Tail.Overlay.DriverContext[0])
#define FspIrpRequest(Irp) \ #define FspIrpRequest(Irp) \
(*(FSP_FSCTL_TRANSACT_REQ **)&(Irp)->Tail.Overlay.DriverContext[2]) (*(FSP_FSCTL_TRANSACT_REQ **)&(Irp)->Tail.Overlay.DriverContext[0])
/* I/O queue */ /* I/O queue */
#define FspIoqTimeout ((PIRP)1) #define FspIoqTimeout ((PIRP)1)
@ -307,12 +333,16 @@ typedef struct
KEVENT PendingIrpEvent; KEVENT PendingIrpEvent;
LIST_ENTRY PendingIrpList, ProcessIrpList; LIST_ENTRY PendingIrpList, ProcessIrpList;
IO_CSQ PendingIoCsq, ProcessIoCsq; IO_CSQ PendingIoCsq, ProcessIoCsq;
FSP_DICT ProcessIrpDict;
LARGE_INTEGER IrpTimeout; LARGE_INTEGER IrpTimeout;
ULONG PendingIrpCapacity, PendingIrpCount; ULONG PendingIrpCapacity, PendingIrpCount;
VOID (*CompleteCanceledIrp)(PIRP Irp); VOID (*CompleteCanceledIrp)(PIRP Irp);
FSP_DICT_ENTRY *ProcessIrpDictBuckets[];
} FSP_IOQ; } FSP_IOQ;
VOID FspIoqInitialize(FSP_IOQ *Ioq, NTSTATUS FspIoqCreate(
PLARGE_INTEGER IrpTimeout, ULONG IrpCapacity, VOID (*CompleteCanceledIrp)(PIRP Irp)); ULONG IrpCapacity, PLARGE_INTEGER IrpTimeout, VOID (*CompleteCanceledIrp)(PIRP Irp),
FSP_IOQ **PIoq);
VOID FspIoqDelete(FSP_IOQ *Ioq);
VOID FspIoqStop(FSP_IOQ *Ioq); VOID FspIoqStop(FSP_IOQ *Ioq);
BOOLEAN FspIoqStopped(FSP_IOQ *Ioq); BOOLEAN FspIoqStopped(FSP_IOQ *Ioq);
VOID FspIoqRemoveExpired(FSP_IOQ *Ioq); VOID FspIoqRemoveExpired(FSP_IOQ *Ioq);
@ -370,6 +400,7 @@ typedef struct
typedef struct typedef struct
{ {
FSP_DEVICE_EXTENSION Base; FSP_DEVICE_EXTENSION Base;
UINT32 InitDoneFsvrt:1, InitDoneDelRsc:1, InitDoneIoq:1, InitDoneGenTab:1, InitDoneTimer:1;
PDEVICE_OBJECT FsctlDeviceObject; PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject;
HANDLE MupHandle; HANDLE MupHandle;
@ -377,7 +408,7 @@ typedef struct
FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem; FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem;
ERESOURCE DeleteResource; ERESOURCE DeleteResource;
FSP_FSCTL_VOLUME_PARAMS VolumeParams; FSP_FSCTL_VOLUME_PARAMS VolumeParams;
FSP_IOQ Ioq; FSP_IOQ *Ioq;
KSPIN_LOCK ExpirationLock; KSPIN_LOCK ExpirationLock;
WORK_QUEUE_ITEM ExpirationWorkItem; WORK_QUEUE_ITEM ExpirationWorkItem;
BOOLEAN ExpirationInProgress; BOOLEAN ExpirationInProgress;
@ -405,7 +436,7 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize, NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
DEVICE_TYPE DeviceType, DEVICE_TYPE DeviceType,
PDEVICE_OBJECT *PDeviceObject); PDEVICE_OBJECT *PDeviceObject);
VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject); NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject); VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject); BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject); VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject);

View File

@ -29,6 +29,7 @@ VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
typedef struct typedef struct
{ {
FSP_IRP_CONTEXT IrpContext;
FSP_IOP_REQUEST_FINI *RequestFini; FSP_IOP_REQUEST_FINI *RequestFini;
PVOID Context[3]; PVOID Context[3];
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 RequestBuf[]; __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 RequestBuf[];

View File

@ -91,21 +91,19 @@ static PIRP FspIoqPendingPeekNextIrp(PIO_CSQ IoCsq, PIRP Irp, PVOID PeekContext)
return 0; return 0;
PLIST_ENTRY Head = &Ioq->PendingIrpList; PLIST_ENTRY Head = &Ioq->PendingIrpList;
PLIST_ENTRY Entry = 0 == Irp ? Head->Flink : Irp->Tail.Overlay.ListEntry.Flink; PLIST_ENTRY Entry = 0 == Irp ? Head->Flink : Irp->Tail.Overlay.ListEntry.Flink;
if (Head == Entry)
return 0;
if (!PeekContext) if (!PeekContext)
return Head != Entry ? CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0; return CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
PVOID IrpHint = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->IrpHint; PVOID IrpHint = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->IrpHint;
if (0 == IrpHint) if (0 == IrpHint)
{ {
if (Head != Entry) ULONGLONG ExpirationTime = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->ExpirationTime;
{ return FspIrpContext(Irp)->ExpirationTime <= ExpirationTime ?
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0;
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; else
return CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
} }
_IRQL_raises_(DISPATCH_LEVEL) _IRQL_raises_(DISPATCH_LEVEL)
@ -134,11 +132,19 @@ static NTSTATUS FspIoqProcessInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertCo
if (Ioq->Stopped) if (Ioq->Stopped)
return STATUS_CANCELLED; return STATUS_CANCELLED;
InsertTailList(&Ioq->ProcessIrpList, &Irp->Tail.Overlay.ListEntry); InsertTailList(&Ioq->ProcessIrpList, &Irp->Tail.Overlay.ListEntry);
ASSERT(0 == FspDictGetEntry(&Ioq->ProcessIrpDict, Irp));
FSP_DICT_ENTRY DictEntry = { 0 };
DictEntry.Key = Irp;
FspDictSetEntry(&Ioq->ProcessIrpDict, &DictEntry);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static VOID FspIoqProcessRemoveIrp(PIO_CSQ IoCsq, PIRP Irp) static VOID FspIoqProcessRemoveIrp(PIO_CSQ IoCsq, PIRP Irp)
{ {
FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, ProcessIoCsq);
FSP_DICT_ENTRY *DictEntry; (VOID)DictEntry;
DictEntry = FspDictRemoveEntry(&Ioq->ProcessIrpDict, Irp);
ASSERT(0 == DictEntry);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry); RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
} }
@ -149,27 +155,22 @@ static PIRP FspIoqProcessPeekNextIrp(PIO_CSQ IoCsq, PIRP Irp, PVOID PeekContext)
return 0; return 0;
PLIST_ENTRY Head = &Ioq->ProcessIrpList; PLIST_ENTRY Head = &Ioq->ProcessIrpList;
PLIST_ENTRY Entry = 0 == Irp ? Head->Flink : Irp->Tail.Overlay.ListEntry.Flink; PLIST_ENTRY Entry = 0 == Irp ? Head->Flink : Irp->Tail.Overlay.ListEntry.Flink;
if (Head == Entry)
return 0;
if (!PeekContext) if (!PeekContext)
return Head != Entry ? CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0; return CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
PVOID IrpHint = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->IrpHint; PVOID IrpHint = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->IrpHint;
if (0 == IrpHint) if (0 == IrpHint)
{ {
if (Head != Entry) ULONGLONG ExpirationTime = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->ExpirationTime;
{ return FspIrpContext(Irp)->ExpirationTime <= ExpirationTime ?
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0;
if (FspIrpTimestamp(Irp) <= ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->ExpirationTime)
/* IRP has expired; return it */
return Irp;
}
return 0;
} }
for (; Head != Entry; Entry = Entry->Flink) else
{ {
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); FSP_DICT_ENTRY *DictEntry = FspDictGetEntry(&Ioq->ProcessIrpDict, IrpHint);
if (Irp == IrpHint) return 0 != DictEntry ? (PIRP)IrpHint : 0;
return Irp;
} }
return 0;
} }
_IRQL_raises_(DISPATCH_LEVEL) _IRQL_raises_(DISPATCH_LEVEL)
@ -192,11 +193,28 @@ static VOID FspIoqProcessCompleteCanceledIrp(PIO_CSQ IoCsq, PIRP Irp)
Ioq->CompleteCanceledIrp(Irp); Ioq->CompleteCanceledIrp(Irp);
} }
VOID FspIoqInitialize(FSP_IOQ *Ioq, BOOLEAN FspIoqIrpEquals(PVOID Irp1, PVOID Irp2)
PLARGE_INTEGER IrpTimeout, ULONG IrpCapacity, VOID (*CompleteCanceledIrp)(PIRP Irp)) {
return Irp1 == Irp2;
}
ULONG FspIoqIrpHash(PVOID Irp)
{
return (ULONG)(UINT_PTR)Irp;
}
NTSTATUS FspIoqCreate(
ULONG IrpCapacity, PLARGE_INTEGER IrpTimeout, VOID (*CompleteCanceledIrp)(PIRP Irp),
FSP_IOQ **PIoq)
{ {
ASSERT(0 != CompleteCanceledIrp); ASSERT(0 != CompleteCanceledIrp);
ULONG BucketCount = IrpCapacity / 2;
FSP_IOQ *Ioq = FspAllocNonPaged(
sizeof *Ioq + sizeof Ioq->ProcessIrpDictBuckets[0] * BucketCount);
if (0 == Ioq)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(Ioq, sizeof *Ioq); RtlZeroMemory(Ioq, sizeof *Ioq);
KeInitializeSpinLock(&Ioq->SpinLock); KeInitializeSpinLock(&Ioq->SpinLock);
KeInitializeEvent(&Ioq->PendingIrpEvent, NotificationEvent, FALSE); KeInitializeEvent(&Ioq->PendingIrpEvent, NotificationEvent, FALSE);
@ -216,9 +234,19 @@ VOID FspIoqInitialize(FSP_IOQ *Ioq,
FspIoqProcessAcquireLock, FspIoqProcessAcquireLock,
FspIoqProcessReleaseLock, FspIoqProcessReleaseLock,
FspIoqProcessCompleteCanceledIrp); FspIoqProcessCompleteCanceledIrp);
FspDictInitialize(&Ioq->ProcessIrpDict,
FspIoqIrpEquals, FspIoqIrpHash, Ioq->ProcessIrpDictBuckets, BucketCount);
Ioq->IrpTimeout = *IrpTimeout; Ioq->IrpTimeout = *IrpTimeout;
Ioq->PendingIrpCapacity = IrpCapacity; Ioq->PendingIrpCapacity = IrpCapacity;
Ioq->CompleteCanceledIrp = CompleteCanceledIrp; Ioq->CompleteCanceledIrp = CompleteCanceledIrp;
return STATUS_SUCCESS;
}
VOID FspIoqDelete(FSP_IOQ *Ioq)
{
FspIoqStop(Ioq);
FspFree(Ioq);
} }
VOID FspIoqStop(FSP_IOQ *Ioq) VOID FspIoqStop(FSP_IOQ *Ioq)
@ -261,7 +289,7 @@ VOID FspIoqRemoveExpired(FSP_IOQ *Ioq)
BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp, NTSTATUS *PResult) BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp, NTSTATUS *PResult)
{ {
NTSTATUS Result; NTSTATUS Result;
FspIrpTimestamp(Irp) = KeQueryInterruptTime() + Ioq->IrpTimeout.QuadPart; FspIrpContext(Irp)->ExpirationTime = KeQueryInterruptTime() + Ioq->IrpTimeout.QuadPart;
Result = IoCsqInsertIrpEx(&Ioq->PendingIoCsq, Irp, 0, (PVOID)1); Result = IoCsqInsertIrpEx(&Ioq->PendingIoCsq, Irp, 0, (PVOID)1);
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
return TRUE; return TRUE;

View File

@ -158,9 +158,18 @@ NTSTATUS FspVolumeCreate(
FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject; FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject;
FsvolDeviceExtension->VolumeParams = VolumeParams; FsvolDeviceExtension->VolumeParams = VolumeParams;
RtlCopyUnicodeString(&FsvolDeviceExtension->VolumeName, &VolumeName); RtlCopyUnicodeString(&FsvolDeviceExtension->VolumeName, &VolumeName);
FspDeviceInitComplete(FsvolDeviceObject); Result = FspDeviceInitialize(FsvolDeviceObject);
if (0 != FsvrtDeviceObject) if (NT_SUCCESS(Result))
FspDeviceInitComplete(FsvrtDeviceObject); {
if (0 != FsvrtDeviceObject)
Result = FspDeviceInitialize(FsvrtDeviceObject);
}
if (!NT_SUCCESS(Result))
{
if (0 != FsvrtDeviceObject)
FspDeviceRelease(FsvrtDeviceObject);
FspDeviceRelease(FsvolDeviceObject);
}
/* do we need to register with MUP? */ /* do we need to register with MUP? */
if (0 == FsvrtDeviceObject) if (0 == FsvrtDeviceObject)
@ -220,7 +229,7 @@ VOID FspVolumeDelete(
ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE); ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE);
/* stop the I/O queue */ /* stop the I/O queue */
FspIoqStop(&FsvolDeviceExtension->Ioq); FspIoqStop(FsvolDeviceExtension->Ioq);
/* do we have a virtual disk device or a MUP handle? */ /* do we have a virtual disk device or a MUP handle? */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject) if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
@ -356,7 +365,7 @@ NTSTATUS FspVolumeMount(
if (FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject) if (FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject)
{ {
ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE); ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE);
if (!FspIoqStopped(&FsvolDeviceExtension->Ioq)) if (!FspIoqStopped(FsvolDeviceExtension->Ioq))
{ {
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
/* break out of the loop without FspDeviceRelease or DeleteResource release! */ /* break out of the loop without FspDeviceRelease or DeleteResource release! */
@ -423,7 +432,7 @@ NTSTATUS FspVolumeRedirQueryPathEx(
ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE); ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE);
Result = STATUS_BAD_NETWORK_PATH; Result = STATUS_BAD_NETWORK_PATH;
if (!FspIoqStopped(&FsvolDeviceExtension->Ioq)) if (!FspIoqStopped(FsvolDeviceExtension->Ioq))
{ {
RtlInitUnicodeString(&Prefix, FsvolDeviceExtension->VolumeParams.Prefix); RtlInitUnicodeString(&Prefix, FsvolDeviceExtension->VolumeParams.Prefix);
if (Prefix.Length <= QueryPathRequest->PathName.Length && if (Prefix.Length <= QueryPathRequest->PathName.Length &&
@ -515,7 +524,7 @@ NTSTATUS FspVolumeTransact(
if (0 == NextResponse) if (0 == NextResponse)
break; break;
ProcessIrp = FspIoqEndProcessingIrp(&FsvolDeviceExtension->Ioq, (UINT_PTR)Response->Hint); ProcessIrp = FspIoqEndProcessingIrp(FsvolDeviceExtension->Ioq, (UINT_PTR)Response->Hint);
if (0 == ProcessIrp) if (0 == ProcessIrp)
/* either IRP was canceled or a bogus Hint was provided */ /* either IRP was canceled or a bogus Hint was provided */
continue; continue;
@ -538,9 +547,9 @@ NTSTATUS FspVolumeTransact(
KeQuerySystemTime(&Timeout); KeQuerySystemTime(&Timeout);
Timeout.QuadPart += FsvolDeviceExtension->VolumeParams.TransactTimeout * 10000; Timeout.QuadPart += FsvolDeviceExtension->VolumeParams.TransactTimeout * 10000;
/* convert millis to nanos and add to absolute time */ /* convert millis to nanos and add to absolute time */
while (0 == (PendingIrp = FspIoqNextPendingIrp(&FsvolDeviceExtension->Ioq, &Timeout))) while (0 == (PendingIrp = FspIoqNextPendingIrp(FsvolDeviceExtension->Ioq, &Timeout)))
{ {
if (FspIoqStopped(&FsvolDeviceExtension->Ioq)) if (FspIoqStopped(FsvolDeviceExtension->Ioq))
return STATUS_CANCELLED; return STATUS_CANCELLED;
} }
if (FspIoqTimeout == PendingIrp) if (FspIoqTimeout == PendingIrp)
@ -565,7 +574,7 @@ NTSTATUS FspVolumeTransact(
RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size); RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size);
Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size); Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size);
if (!FspIoqStartProcessingIrp(&FsvolDeviceExtension->Ioq, PendingIrp)) if (!FspIoqStartProcessingIrp(FsvolDeviceExtension->Ioq, PendingIrp))
{ {
/* /*
* This can only happen if the Ioq was stopped. Abandon everything * This can only happen if the Ioq was stopped. Abandon everything
@ -573,7 +582,7 @@ NTSTATUS FspVolumeTransact(
* queues of the Ioq will be cancelled during FspIoqStop(). We must * queues of the Ioq will be cancelled during FspIoqStop(). We must
* also cancel the PendingIrp we have in our hands. * also cancel the PendingIrp we have in our hands.
*/ */
ASSERT(FspIoqStopped(&FsvolDeviceExtension->Ioq)); ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq));
FspIopCompleteIrp(PendingIrp, STATUS_CANCELLED); FspIopCompleteIrp(PendingIrp, STATUS_CANCELLED);
return STATUS_CANCELLED; return STATUS_CANCELLED;
} }
@ -583,7 +592,7 @@ NTSTATUS FspVolumeTransact(
break; break;
} }
PendingIrp = FspIoqNextPendingIrp(&FsvolDeviceExtension->Ioq, 0); PendingIrp = FspIoqNextPendingIrp(FsvolDeviceExtension->Ioq, 0);
if (0 == PendingIrp) if (0 == PendingIrp)
break; break;
} }
@ -619,7 +628,7 @@ NTSTATUS FspVolumeWork(
* so that we can disassociate the Request on failure and release ownership * so that we can disassociate the Request on failure and release ownership
* back to the caller. * back to the caller.
*/ */
if (!FspIoqPostIrp(&FsvolDeviceExtension->Ioq, Irp, &Result)) if (!FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result))
{ {
Request->Hint = 0; Request->Hint = 0;
FspIrpRequest(Irp) = 0; FspIrpRequest(Irp) = 0;